-2009-01-21 Marcelo Vanzin <mvanzin@vmware.com>
- * Resync with internal trunk (2009.01.19)
+2009-02-18 Marcelo Vanzin <mvanzin@vmware.com>
+ * Resync with internal trunk (2009.01.13)
+
+ * configure.ac, m4/vmtools.m4: clean up a lot of the library detection code.
+
+ * configure.ac: remove support for gtk+ 1.2 (code already depended on it in
+ any case); enforce need for glib 2.6.0 or later due to new code being
+ added; add detection for gtkmm; check for C++ compiler when it's needed;
+ reorder the include path to avoid clashing with system headers in some
+ situations.
+
+ * guestd/foundryToolsDaemon.*, vmware-user/foundryToolsDaemon.*,
+ guestd/Makefile.am, vmware-user/Makefile.am: moved shared source files to
+ a new place to avoid duplication.
+
+ * hgfsmounter/hgfsmounter.c: add support for Solaris.
+
+ * lib/appUtil/appUtilX11.c: fix loading of icons when the name has a period.
+
+ * lib/dnd/dndClipboard.c, lib/dnd/dndInt.h, lib/dnd/dndMsg.c,
+ lib/dnd/Makefile.am, lib/dndGuest/*, lib/include/copyPasteBase.h,
+ lib/include/copyPaste.hh, lib/include/copyPasteRpc.hh,
+ lib/include/copyPasteRpcV3.hh, lib/include/dndBase.h,
+ lib/include/dndClipboard.h, lib/include/dndFileContentsUtil.h,
+ lib/include/dndFileList.hh, lib/include/dnd.h, lib/include/dnd.hh,
+ lib/include/dndInt.h, lib/include/dndMsg.h, lib/include/dndRpc.hh,
+ lib/include/dndRpcV3.hh, lib/include/dndTransportGuestRpc.hh,
+ lib/include/dndTransport.hh, lib/include/libExport.hh,
+ vmware-user/copyPaste.cpp, vmware-user/copyPasteUI.{cpp,h},
+ vmware-user/copyPasteV3.h, vmware-user/copyPasteWrapper.{cpp,h},
+ vmware-user/dnd.cpp, vmware-user/Makefile.am,
+ vmware-user/vmware-user.{c,cpp}, vmware-user/vmwareuserInt.h,
+ vmware-user/stringxx/string.{cc,hh}, vmware-user/stringxx/ubstr_t.hh: add
+ support for new version of the DnD protocol.
+
+ * lib/guestInfo/guestInfoPerfMonLinux.c: fix problem with overwriting flags
+ after GuestInfoMonitorReadMeminfo() was called.
+
+ * lib/guestRpc/guestlibV3.x, lib/include/vmGuestLib.h,
+ libguestlib/vmGuestLib.c: add new host stats.
+
+ * lib/guestRpc/Makefile.am: fix a few compatibility issues with non-GNU
+ versions of make.
- * configure.ac: detect the presence of FUSE libraries.
+ * lib/hgfsServer/hgfsServer.c, lib/hgfsServer/hgfsServerInt.h,
+ lib/hgfsServer/hgfsServerLinux.c, */hgfsProto.h,
+ modules/freebsd/vmhgfs/vnops.c, modules/freebsd/vmhgfs/vnopscommon.{c,h}:
+ don't trust the local VFS layer, check the HGFS server to see if an
+ operation would succeed.
+
+ * lib/include/rpcChannel.h, lib/rpcChannel/*: add new Guest RPC channel
+ abstraction library used by the new "core services" code.
+
+ * lib/include/vmrpcdbg.h, tests/*: add test code from the "core services"
+ project.
+
+ * lib/include/vmtoolsApp.h, lib/include/vmtoolsd_version.h,
+ services/vmtoolsd/*: add "vmtoolsd", the new service "shell" used in the
+ "core services" project.
+
+ * lib/unity/unityPlatformX11Window.c: don't send initial "region" updates for
+ shaped windows. This works around an issue where resizing a shaped window
+ would not work as expected in Unity mode.
+
+ * lib/wiper/wiperPosix.c: fix major number detection for disks on newer Linux
+ kernels.
+
+ * libvmtools/Makefile.am: link more libraries needed by vmtoolsd and the new
+ plugins.
+
+ * modules/linux/pvscsi/pvscsi.c, modules/linux/pvscsi/pvscsi_version.h: use
+ PCI-specific memory allocation functions and update driver version.
- * configure.ac, Makefile.am: compile kernel modules for Solaris, and
- vmblock-fuse module if FUSE is available.
+ * modules/linux/vmci/vmciKernelIf.c: disable queue pair support in the host
+ version of the driver on older Linux kernels. This doesn't affect the
+ guest driver.
+
+ * modules/linux/vmci/vmci_queue_pair.h: implement MSG_PEEK support on
+ Linux driver.
+
+ * modules/linux/vmhgfs/bdhandler.c, modules/linux/vmhgfs/compat_sched.h,
+ modules/linux/vmmemctl/os.c: fix issue with HGFS module interfering with
+ suspend / hibernation on newer Linux kernels (bug #2523263).
+
+ * modules/linux/vmhgfs/compat_cred.h, modules/linux/vmhgfs/file.c,
+ modules/linux/vmhgfs/filesystem.c, modules/linux/vmhgfs/inode.c: changes
+ for compatibility with newer Linux kernels, where it's not possible to
+ change fsuid/capabilities directly anymore.
+
+ * modules/linux/vmhgfs/compat_pagemap.h, modules/linux/vmhgfs/page.c:
+ fix warning, and compatibility changes for newer Linux kernels
+ (2.6.28.1 and newer; bug #2530616).
+
+ * modules/linux/vmhgfs/inode.c: fix creation of symlinks (bug #2531303).
+
+ * modules/linux/vmxnet/vmxnet.c: use PCI-specific memory allocation
+ functions.
- * lib/ghIntegration/ghIntegrationX11.c: retrieved localized application
- names.
+ * modules/linux/vmxnet/vmxnet.c, modules/linux/vmxnet3/vmxnet3.c: add option
+ to disable LRO.
- * lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoPosix.c,
- lib/include/hostinfo.h, lib/misc/hostinfo_misc.c, lib/misc/hostinfoPosic.c,
- lib/vixTools/vixTools.c: refactoring to move code shared with other VMware
- products to a common library.
+ * modules/linux/vsock/af_inet.{c,h}, modules/linux/vsock/util.{c,h}: add
+ MSG_PEEK support; remove ifdefs that were disabling support for queue
+ pairs on the host kernel module; fix compilation with certain versions
+ of gcc (bug #2531283).
+
+ * modules/solaris/vmhgfs/*: move backdoor handling code to the HGFS driver;
+ this makes the user-level code to handle the driver (currently in
+ vmware-guestd) obsolete.
+
+ * modules/solaris/vmxnet/*: add vmxnet driver for Solaris, under the CDDL.
+
+ * services/plugins/*: add all currently available "core services" plugins.
+ The current set of plugins provide the functionality available in
+ vmware-guestd; there are a few plugins that replace functionality from
+ vmware-user, but not all features are ported yet (and vmtoolsd - with
+ vmware-user plugins - and vmware-user cannot run at the same time).
+
+ * toolbox/toolboxAbout.c: fix the copyright character.
+
+ * toolbox/toolbox-cmd.c: reword a few messages, fix typos.
+
+ * toolbox/toolboxCmdInt.h, toolbox/toolboxcmd-record.c,
+ toolbox/toolbox-gtk.c, toolbox/toolboxRecord.c: remove the "record"
+ functionality from tools (due to internal request).
+
+ * toolbox/toolboxInt.c, toolbox/toolboxScripts.c, toolbox/toolbox-scripts.c:
+ changes to use the new config file format used by the "core services" code.
+
+ * */Makefile.am: make sure 'rm' and 'mv' are being used instead of $(RM) and
+ $(MV) (which are not defined by automake; bug #2492040).
+
+2009-01-21 Marcelo Vanzin <mvanzin@vmware.com>
+ * Resync with internal trunk (2009.01.19)
+
+ * configure.ac: detect the presence of FUSE libraries.
+
+ * configure.ac, Makefile.am: compile kernel modules for Solaris, and
+ vmblock-fuse module if FUSE is available.
+
+ * lib/ghIntegration/ghIntegrationX11.c: retrieved localized application
+ names.
+
+ * lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoPosix.c,
+ lib/include/hostinfo.h, lib/misc/hostinfo_misc.c, lib/misc/hostinfoPosic.c,
+ lib/vixTools/vixTools.c: refactoring to move code shared with other VMware
+ products to a common library.
- * lib/guestRpc/guestlibV3.x, lib/guestRpc/Makefile.am,
- lib/include/vmGuestLib.h, libguestlib/*: add new iteration of the
- "guestlib" protocol. This is a more extensible solution than the current
- protocol, and should make it easier to add new information when needed.
+ * lib/guestRpc/guestlibV3.x, lib/guestRpc/Makefile.am,
+ lib/include/vmGuestLib.h, libguestlib/*: add new iteration of the
+ "guestlib" protocol. This is a more extensible solution than the current
+ protocol, and should make it easier to add new information when needed.
- * lib/include/dynarray.h, lib/include/dynbuf.h, lib/misc/dynarray.c,
- lib/misc/dynbuf.c: make some DynArray/DynBuf functions inline for speed.
+ * lib/include/dynarray.h, lib/include/dynbuf.h, lib/misc/dynarray.c,
+ lib/misc/dynbuf.c: make some DynArray/DynBuf functions inline for speed.
- * lib/include/unityCommon.h: more documentation about the Unity protocol.
+ * lib/include/unityCommon.h: more documentation about the Unity protocol.
- * lib/unity/unityPlatformX11.c: fix Unity<->guest desktop ID mappings.
+ * lib/unity/unityPlatformX11.c: fix Unity<->guest desktop ID mappings.
- * libvmtools/vmtoolsLog.c: change the way log domains are configured; now
- sub-domains inherit the default handler for the app if no handler is
- specified.
+ * libvmtools/vmtoolsLog.c: change the way log domains are configured; now
+ sub-domains inherit the default handler for the app if no handler is
+ specified.
- * modules/freebsd/vmhgfs/state.c, modules/freebsd/vmhgfs/state.h,
- modules/freebsd/vmhgfs/vnopscommon.{c,h}: implement support for mmap on
- the Mac OS driver, which allows running executables from an HGFS
- share. The FreeBSD module still does not support this functionality.
+ * modules/freebsd/vmhgfs/state.c, modules/freebsd/vmhgfs/state.h,
+ modules/freebsd/vmhgfs/vnopscommon.{c,h}: implement support for mmap on
+ the Mac OS driver, which allows running executables from an HGFS
+ share. The FreeBSD module still does not support this functionality.
- * modules/freebsd/vmhgfs/transport.{c,h}: refactoring for sharing structure
- definitions.
+ * modules/freebsd/vmhgfs/transport.{c,h}: refactoring for sharing structure
+ definitions.
- * modules/linux/pvscsi/pvscsi.c, modules/linux/vmblock/linux/module.c,
- modules/linux/vmci/vmci_drv.c, modules/linux/hgfs/module.c,
- modules/linux/vmmemctl/os.c, modules/linux/vmsync/sync.c,
- modules/linux/vmxnet/vmxnet.c, modules/linux/vmxnet3/vmxnet3.c: add support
- for Novell's proprietary module info tag ("supported").
+ * modules/linux/pvscsi/pvscsi.c, modules/linux/vmblock/linux/module.c,
+ modules/linux/vmci/vmci_drv.c, modules/linux/hgfs/module.c,
+ modules/linux/vmmemctl/os.c, modules/linux/vmsync/sync.c,
+ modules/linux/vmxnet/vmxnet.c, modules/linux/vmxnet3/vmxnet3.c: add support
+ for Novell's proprietary module info tag ("supported").
- * modules/linux/vmci/vmciKernelIf.c: add support for VMCI queue pairs on
- the host. This does not affect the driver when it runs inside virtual
- machines.
+ * modules/linux/vmci/vmciKernelIf.c: add support for VMCI queue pairs on
+ the host. This does not affect the driver when it runs inside virtual
+ machines.
- * modules/linux/vmci/*.h, modules/linux/vsock/*.h: some changes in the common
- code to support Mac OS X, and also queue pairs on the Solaris VMCI module.
+ * modules/linux/vmci/*.h, modules/linux/vsock/*.h: some changes in the common
+ code to support Mac OS X, and also queue pairs on the Solaris VMCI module.
- * modules/linux/vsock/af_vsock.{c,h}: add functions for registering with
- the vsock driver from within the kernel.
+ * modules/linux/vsock/af_vsock.{c,h}: add functions for registering with
+ the vsock driver from within the kernel.
- * modules/linux/*/Makefile: add $(LINUXINCLUDE) to the compiler flags; this
- allows compiling the modules against recent kernels which removed that
- from $(KBUILD_CPPFLAGS).
+ * modules/linux/*/Makefile: add $(LINUXINCLUDE) to the compiler flags; this
+ allows compiling the modules against recent kernels which removed that
+ from $(KBUILD_CPPFLAGS).
- * modules/Makefile.am: add support for compiling Solaris kernel modules.
+ * modules/Makefile.am: add support for compiling Solaris kernel modules.
- * modules/solaris/vmhgfs/*: initial release of the Solaris HGFS driver in
- open-vm-tools. Driver is licensed under the CDDL 1.0.
+ * modules/solaris/vmhgfs/*: initial release of the Solaris HGFS driver in
+ open-vm-tools. Driver is licensed under the CDDL 1.0.
- * vmblock-fuse/*: add the user-level implementation of the vmblock driver,
- which is build on top of FUSE, to open-vm-tools. vmware-user hasn't yet
- been modified to use this version of vmblock.
+ * vmblock-fuse/*: add the user-level implementation of the vmblock driver,
+ which is build on top of FUSE, to open-vm-tools. vmware-user hasn't yet
+ been modified to use this version of vmblock.
- * vmware-user/copyPaseV3.h: new header introduced during development of the
- next version of copy paste / DnD for X11 platforms.
+ * vmware-user/copyPaseV3.h: new header introduced during development of the
+ next version of copy paste / DnD for X11 platforms.
2008-11-23 Marcelo Vanzin <mvanzin@vmware.com>
endif
SUBDIRS += checkvm
SUBDIRS += libguestlib
-if ENABLE_CORE_SERVICES
- SUBDIRS += libvmtools
-endif
+SUBDIRS += libvmtools
+SUBDIRS += scripts
+SUBDIRS += services
+SUBDIRS += toolbox
if HAVE_FUSE
SUBDIRS += vmblock-fuse
endif
SUBDIRS += xferlogs
-SUBDIRS += scripts
-SUBDIRS += toolbox
+SUBDIRS += tests
if WITH_KERNEL_MODULES
SUBDIRS += modules
endif
+open-vm-tools 2009.02.18 changes:
+ * open-vm-tools now depend on glib 2.6.0 as a minimum requirement.
+
+ * Added vmxnet module for Solaris, and reworked the HGFS module so it
+ works without help from vmware-guestd.
+
+ * Added implementation of new DnD protocol, which adds a dependency on
+ a C++ compiler and the gtkmm library to vmware-user.
+
+ * The code from the "core services" has been added to open-vm-tools,
+ including a few tests. vmtoolsd + plugins are now capable of replacing
+ vmware-guestd (vmware-user still needs to have some features ported
+ over), but this code is still not to be considered as stable as the
+ legacy services, so vmware-guestd is still included.
+
+ * A few fixes for compatibility with non-GNU toolchains, newer Linux
+ kernels and old gcc compilers.
+
open-vm-tools 2009.01.21 changes:
- * First open source release of the HGFS module for Solaris, under the CDDL.
- Other modules are expected to be added in the upcoming releases.
+ * First open source release of the HGFS module for Solaris, under the CDDL.
+ Other modules are expected to be added in the upcoming releases.
- * Added an implementation of vmblock on top of FUSE; vmware-user still
- doesn't use this module even if it is available, though.
+ * Added an implementation of vmblock on top of FUSE; vmware-user still
+ doesn't use this module even if it is available, though.
- * Linux modules now add the "supported" tag used by Novell in their
- SLES 10 SP2 release when loading modules.
+ * Linux modules now add the "supported" tag used by Novell in their
+ SLES 10 SP2 release when loading modules.
- * Fix compilation of modules in newer Linux kernels which don't include
- $(LINUXINCLUDE) in the compiler flags anymore.
+ * Fix compilation of modules in newer Linux kernels which don't include
+ $(LINUXINCLUDE) in the compiler flags anymore.
open-vm-tools 2008.12.23 changes:
* Lots of makefile cleanup with the switch to using libtool archives.
################################################################################
# In addition to the usual environment variables and command line
# arguments that a configure script usually takes (CFLAGS, LDFLAGS,
-# etc.), this script also accepts:
-# $CUSTOM_FUSE_CPPFLAGS - compile-time flags to find FUSE headers.
-# $CUSTOM_FUSE_LIBS - link-time flags to find FUSE libraries.
-# $CUSTOM_GLIB2_CPPFLAGS - compile-time flags to find Glib headers.
-# $CUSTOM_GLIB2_LIBS - link-time flags to find Glib libraries.
-# $CUSTOM_GTK_CPPFLAGS - compile-time flags to find Gtk headers.
-# $CUSTOM_GTK_LIBS - link-time flags to find and link the Gtk libraries.
-# $CUSTOM_PROCPS_LIBS - link-time flags to find and link the procps library.
-# $CUSTOM_URIPARSER_CPPFLAGS - compile-time flags to find the uriparser headers
-# $CUSTOM_URIPARSER_LIBS - link-time flags to find and link the uriparser library
-# $CUSTOM_ZLIB_CPPFLAGS - compile-time flags to find the zlib headers
-# $CUSTOM_ZLIB_LIBS - link-time flags to find and link the zlib library
+# etc.), this script also accepts variables of the form:
+#
+# CUSTOM_LIB_CPPFLAGS: compile-time flags for LIB
+# CUSTOM_LIB_LIBS: link-time flags for LIB
+# RPCGENFLAGS: extra flags to pass to rpcgen
+#
+# The following libraries are currently tested: DNET, FUSE, GLIB2, GMODULE,
+# GOBJECT, GTHREAD, GTK, GTKMM, LIBPNG, PROCPS, URIPARSER, ZLIB
################################################################################
###
AC_INIT(
[open-vm-tools],
- [2009.01.21-142982],
+ [2009.02.18-148847],
[open-vm-tools-devel@lists.sourceforge.net])
# In order to make this configure script auto-detect situations where
gtk2,
AS_HELP_STRING(
[--without-gtk2],
- [compiles without Gtk 2.0 (falls back on Gtk 1.2)]),
+ [compiles without Gtk 2.0]),
[with_gtk2="$withval"],
[with_gtk2="yes"])
-# If we're not going to use Gtk 2.0, disable Unity. It may be possible to
-# get Unity working with Gtk 1.2 (it used to in the past), but that will
-# require a great deal of work.
+AC_ARG_WITH(
+ gtkmm,
+ AS_HELP_STRING(
+ [--without-gtkmm],
+ [compiles without Gtkmm, sigc++, and related libs]),
+ [with_gtkmm="$withval"],
+ [with_gtkmm="yes"])
+
+# If we're not going to use Gtk 2.0, disable Unity.
if test "$with_gtk2" != "yes"; then
enable_unity="no"
fi
AC_PATH_XTRA
+#
+# Check for libintl.h. When configuring using "--without-x", /usr/local/include
+# may not be added to the include path, so code that use glib's i18n functions
+# would fail to compile because it can't find libintl.h.
+#
+AC_CHECK_HEADER([libintl.h],
+ [],
+ [have_libintl=no],
+ [])
+if test "$have_libintl" = "no"; then
+ unset ac_cv_header_libintl_h
+ CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+ AC_CHECK_HEADER([libintl.h],
+ [],
+ [AC_MSG_ERROR([libintl.h not found. Make sure you have the gettext headers installed.])],
+ [])
+fi
+
#
# Check for glib 2.6.0 or greater.
-# XXX: glib < 2.6 should become an error once the code that needs it is the default.
#
-if test "$HAVE_PKG_CONFIG" = "yes"; then
- AC_MSG_CHECKING([for glib >= 2.6.0 (via pkg-config)])
- if pkg-config --exists 'glib-2.0 >= 2.6.0'; then
- GLIB2_CPPFLAGS="`pkg-config --cflags glib-2.0`"
- GLIB2_LIBS="`pkg-config --libs glib-2.0`"
- have_glib_26="yes"
- AC_MSG_RESULT([yes])
- else
- have_glib_26="no"
- AC_MSG_RESULT([no])
- fi
-else
- # g_key_file_new (and related) functions were added in glib 2.6. That's the
- # minimum version supported by the Core Services code.
- AC_CHECK_LIB(
- [glib-2.0],
- [g_key_file_new],
- [have_glib_26="yes"],
- [AC_MSG_WARN([glib 2 is older than 2.6.0, some features will be disabled.])],
- [$CUSTOM_GLIB2_LIBS])
- if test "$have_glib_26" = "yes"; then
- GLIB2_CPPFLAGS="$CUSTOM_GLIB2_CPPFLAGS"
- GLIB2_LIBS="$CUSTOM_GLIB2_LIBS"
- fi
+AC_VMW_CHECK_LIB([glib-2.0],
+ [GLIB2],
+ [glib-2.0],
+ [],
+ [2.6.0],
+ [glib.h],
+ [g_key_file_new],
+ [],
+ [AC_MSG_ERROR([glib >= 2.6.0 is required.])])
+AC_VMW_CHECK_LIB([gmodule-2.0],
+ [GMODULE],
+ [gmodule-2.0],
+ [],
+ [2.6.0],
+ [],
+ [],
+ [],
+ [AC_MSG_ERROR([gmodule >= 2.6.0 is required.])])
+AC_VMW_CHECK_LIB([gobject-2.0],
+ [GOBJECT],
+ [gobject-2.0],
+ [],
+ [2.6.0],
+ [glib-object.h],
+ [],
+ [],
+ [AC_MSG_ERROR([gobject >= 2.6.0 is required.])])
+AC_VMW_CHECK_LIB([gthread-2.0],
+ [GTHREAD],
+ [gthread-2.0],
+ [],
+ [2.6.0],
+ [],
+ [],
+ [],
+ [AC_MSG_ERROR([glib >= 2.6.0 is required.])])
+AC_CHECK_PROG([have_genmarshal],
+ [glib-genmarshal],
+ [yes],
+ [no])
+
+if test "$have_genmarshal" != "yes"; then
+ AC_MSG_ERROR([glib-genmarshal is required; make sure it's available in your path.])
fi
#
# Check for fuse.
#
-if test "$HAVE_PKG_CONFIG" = "yes"; then
- AC_MSG_CHECKING([for fuse (via pkg-config)])
- if pkg-config --exists 'fuse'; then
- FUSE_CPPFLAGS="`pkg-config --cflags fuse`"
- FUSE_LIBS="`pkg-config --libs fuse`"
- have_fuse="yes"
- AC_MSG_RESULT([yes])
- else
- have_fuse="no"
- AC_MSG_RESULT([no])
- fi
-else
- ORIGINAL_LDFLAGS="$LDFLAGS"
- LDFLAGS="$CUSTOM_FUSE_LIBS $LDFLAGS"
- AC_CHECK_LIB(
- [fuse],
- [fuse_main],
- [have_fuse="yes";
- if test -n "$CUSTOM_FUSE_LIBS"; then
- FUSE_LIBS="$CUSTOM_FUSE_LIBS"
- else
- FUSE_LIBS="-lfuse"
- fi],
- [have_fuse="no"; AC_MSG_WARN([Fuse is missing, vmblock-fuse will be disabled.])])
- LDFLAGS="$ORIGINAL_LDFLAGS"
-
- if test "$have_fuse" = "yes"; then
- ORIGINAL_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CUSTOM_FUSE_CPPFLAGS $CPPFLAGS"
- AC_CHECK_HEADER(
- [fuse.h],
- [if test -n "$CUSTOM_FUSE_CPPFLAGS"; then
- FUSE_CPPFLAGS="$CUSTOM_FUSE_CPPFLAGS"
- else
- FUSE_CPPFLAGS="-I/usr/include"
- fi],
- [have_fuse="no"; AC_MSG_WARN([Can't locate fuse headers, vmblock-fuse will be disabled.])])
- CPPFLAGS="$ORIGINAL_CPPFLAGS"
- fi
-fi
+AC_VMW_CHECK_LIB([fuse],
+ [FUSE],
+ [fuse],
+ [],
+ [],
+ [fuse.h],
+ [fuse_main],
+ [have_fuse=yes],
+ [have_fuse=no;
+ AC_MSG_WARN([Fuse is missing, vmblock-fuse will be disabled.])])
# If the user explicitly disables X11, then don't try to detect the X-related libraries
if test "$have_x" = "disabled"; then
# Note that we look for uriFreeQueryListA because it's a relatively
# new symbol that our code needs (it isn't present in the uriparser
# that shipped with Ubuntu Hardy).
- ORIGINAL_LDFLAGS="$LDFLAGS"
- LDFLAGS="$CUSTOM_URIPARSER_LIBS $LDFLAGS"
- AC_CHECK_LIB(
- [uriparser],
- [uriFreeQueryListA],
- [if test -n "$CUSTOM_URIPARSER_LIBS"; then
- URIPARSER_LIBS="$CUSTOM_URIPARSER_LIBS"
- else
- URIPARSER_LIBS="-luriparser"
- fi],
- [AC_MSG_ERROR(
- [uriparser library not found or is too old. Please configure without Unity (using --disable-unity) or install the liburiparser devel package.])])
- LDFLAGS="$ORIGINAL_LDFLAGS"
-
- if test -n "$CUSTOM_URIPARSER_CPPFLAGS"; then
- URIPARSER_CPPFLAGS="$CUSTOM_URIPARSER_CPPFLAGS"
- else
- # XXX: No pkg-config and no uriparser-config means we need to
- # hard-code a sensible default.
- URIPARSER_CPPFLAGS="-I/usr/include/uriparser"
- fi
- ORIGINAL_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$URIPARSER_CPPFLAGS $CPPFLAGS"
- AC_CHECK_HEADER(
- [Uri.h],
- [],
- [AC_MSG_ERROR(
- [uriparser headers not found. Please configure without Unity (using --disable-unity) or install the liburiparser devel package])])
- CPPFLAGS="$ORIGINAL_CPPFLAGS"
-
- # Check for libpng using pkg-config, or barring that, using
- # libpng-config.
- if test "$HAVE_PKG_CONFIG" = "yes"; then
- AC_MSG_CHECKING([for libpng (via pkg-config)])
- if pkg-config --exists libpng12; then
- LIBPNG_CPPFLAGS="`pkg-config --cflags libpng12`"
- LIBPNG_LIBS="`pkg-config --libs libpng12`"
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- else
- AC_PATH_PROG(
- [LIBPNG_CONFIG],
- [libpng-config],
- [no])
- if test "$LIBPNG_CONFIG" != "no"; then
- LIBPNG_CPPFLAGS="`$LIBPNG_CONFIG --cflags`"
- LIBPNG_LIBS="`$LIBPNG_CONFIG --libs`"
- fi
- fi
- if test -z "$LIBPNG_CPPFLAGS"; then
- AC_MSG_ERROR(
- [libpng not found. Please configure without Unity (using --disable-unity) or install the libpng devel package])
+ if test -z "$CUSTOM_URIPARSER_CPPFLAGS"; then
+ # XXX: No pkg-config and no uriparser-config means we need to
+ # hard-code a sensible default.
+ CUSTOM_URIPARSER_CPPFLAGS="-I/usr/include/uriparser"
fi
+ AC_VMW_CHECK_LIB([uriparser],
+ [URIPARSER],
+ [],
+ [],
+ [],
+ [Uri.h],
+ [uriFreeQueryListA],
+ [],
+ [AC_MSG_ERROR([uriparser library not found or is too old. Please configure without Unity (using --disable-unity) or install the liburiparser devel package.])])
+
+ # Check for libpng.
+ AC_VMW_CHECK_LIB([png12],
+ [LIBPNG],
+ [libpng12],
+ [libpng-config],
+ [],
+ [png.h],
+ [png_access_version_number],
+ [],
+ [AC_MSG_ERROR([libpng not found. Please configure without Unity (using --disable-unity) or install the libpng devel package])])
# Check for the zlib library and headers. Like uriparser, there
# isn't a pkg-config or zlib-config file.
- ORIGINAL_LDFLAGS="$LDFLAGS"
- LDFLAGS="$CUSTOM_ZLIB_LIBS $LDFLAGS"
- AC_CHECK_LIB(
- [z],
- [zlibVersion],
- [if test -n "$CUSTOM_ZLIB_LIBS"; then
- ZLIB_LIBS="$CUSTOM_ZLIB_LIBS"
- else
- ZLIB_LIBS="-lz"
- fi],
- [AC_MSG_ERROR(
- [zlib library not found. Please configure without Unity (using --disable-unity) or install the zlib devel package.])])
- LDFLAGS="$ORIGINAL_LDFLAGS"
-
- if test -n "$CUSTOM_ZLIB_CPPFLAGS"; then
- ZLIB_CPPFLAGS="$CUSTOM_ZLIB_CPPFLAGS"
- else
- # XXX: No pkg-config and no zlib-config means we need to
- # hard-code a sensible default.
- ZLIB_CPPFLAGS="-I/usr/include"
+ if test -z "$CUSTOM_ZLIB_CPPFLAGS"; then
+ # XXX: No pkg-config and no zlib-config means we need to
+ # hard-code a sensible default.
+ CUSTOM_ZLIB_CPPFLAGS="-I/usr/include"
fi
- ORIGINAL_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$ZLIB_CPPFLAGS $CPPFLAGS"
- AC_CHECK_HEADER(
- [zlib.h],
- [],
- [AC_MSG_ERROR(
- [zlib headers not found. Please configure without Unity (using --disable-unity) or install the zlib devel package])])
- CPPFLAGS="$ORIGINAL_CPPFLAGS"
+ AC_VMW_CHECK_LIB([z],
+ [ZLIB],
+ [],
+ [],
+ [],
+ [zlib.h],
+ [zlibVersion],
+ [],
+ [AC_MSG_ERROR([zlib library not found. Please configure without Unity (using --disable-unity) or install the zlib devel package.])])
fi # End of library checks for Unity.
- if test -n "$CUSTOM_GTK_CPPFLAGS" -o -n "$CUSTOM_GTK_LIBS"; then
- # Check to see if we have some version of GTK. gtk_accel_group_add
- # is a random function that is present in Gtk 1.2 but not Gtk
- # 2.0. Similarly, gtk_tree_view_new is a random function in Gtk 2.0
- # which is not present in Gtk 1.2.
- AC_CHECK_LIB(
- [gtk],
- [gtk_accel_group_add],
- [HAVE_GTK1="yes"],,
- [$CUSTOM_GTK_LIBS])
- if test "$with_gtk2" != "no"; then
- AC_CHECK_LIB(
- [gtk-x11-2.0],
- [gtk_tree_view_new],
- [HAVE_GTK2="yes"],,
- [$CUSTOM_GTK_LIBS])
- fi
- fi
-
- # Sometimes pkg-config can find stuff that AC_CHECK_LIB can't, so we use that as well.
- if test "$HAVE_PKG_CONFIG" = "yes"; then
- if test "$with_gtk2" != "no"; then
- AC_MSG_CHECKING([for Gtk+ 2.0 (via pkg-config)])
- if pkg-config --exists gtk+-2.0; then
- HAVE_GTK2="yes"
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- fi
-
- AC_MSG_CHECKING([for Gtk+ 1.x (via pkg-config)])
- # The latter half of the test is because pkg-config's fallback
- # to gtk-config is broken on systems such as Ubuntu that use
- # bash-completion for unknown commands. (On Ubuntu, typing
- # 'gtk-config' on a system that doesn't have libgtk1.2-dev
- # installed outputs hints about using apt-get, in addition to the
- # regular bash "command not found" message.)
- if pkg-config --exists gtk+ \
- && test -n "`pkg-config --libs gtk+ 2>/dev/null | grep -v '^ *$'`"; then
- HAVE_GTK1="yes"
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- fi
-
- if test "$HAVE_GTK1" = "yes" -o "$HAVE_GTK2" = "yes"; then
- # This bit is to fix builds on OpenSolaris B71, where
- # 'pkg-config --cflags gtk+-2.0' gives an error.
- if test "$HAVE_GTK2" = "yes" -a "$HAVE_PKG_CONFIG" = "yes" \
- && ! pkg-config --exists gtk+-2.0 \
- && test -z "$CUSTOM_GTK_CPPFLAGS" -a -z "$CUSTOM_GTK_LIBS"; then
- HAVE_GTK2="no"
- fi
-
- if test "$HAVE_GTK2" = "yes"; then
- # Gtk 2.0
- GTK_CPPFLAGS="$GTK_CPPFLAGS -DGTK2"
- gtkPackageName="gtk+-2.0"
- elif test "$HAVE_GTK1" = "yes"; then
- # Gtk 1.2
- gtkPackageName="gtk+"
-
- # Unity requires Gtk 2.0.
- if test "$enable_unity" != "no"; then
- AC_MSG_ERROR([The Unity feature requires Gtk+ 2.0. Please install the Gtk+ 2.0 devel packages or configure without Unity (using --disable-unity)])
- fi
- else
- # We found Gtk+ 2.0 that turned out to have a non-working
- # pkg-config setup, AND Gtk 1.2 wasn't installed.
- AC_MSG_ERROR([The Gtk+ library installed on your system is not fully functional. Please contact your OS vendor.])
- fi
-
- # Prefer flags specified, in the environment, by the user.
- if test -n "$CUSTOM_GTK_CPPFLAGS" -o -n "$CUSTOM_GTK_LIBS"; then
- GTK_CPPFLAGS="$GTK_CPPFLAGS $CUSTOM_GTK_CPPFLAGS"
- GTK_LIBS="$GTK_LIBS $CUSTOM_GTK_LIBS"
- # Use pkg-config if available and there are no user-specified flags.
- elif test "$HAVE_PKG_CONFIG" = "yes"; then
- GTK_CPPFLAGS="$GTK_CPPFLAGS $(pkg-config --cflags $gtkPackageName)"
- GTK_LIBS="$GTK_LIBS $(pkg-config --libs $gtkPackageName)"
- # Otherwise, we have a problem.
- else
- AC_MSG_ERROR([pkg-config not found. Get pkg-config or set CUSTOM_GTK_CPPFLAGS and CUSTOM_GTK_LIBS to specify gtk header file and library locations.])
- fi
-
- # Check for a sufficiently new installation of Gtk 2.0. This symbol is, at
- # the time of writing, used in vmware-user. We must perform this check
- # after GTK_LIBS has been set up. Note: we don't actually use the
- # resultant HAVE_NEW_GTK2 variable; it's just set so that the default
- # action, which will append gdk-x11-2.0 to LIBS, isn't taken.
- if test "$HAVE_GTK2" == "yes"; then
- AC_CHECK_LIB(
- [gdk-x11-2.0],
- [gdk_display_get_default_group],
- [HAVE_NEW_GTK2="yes"],
- [AC_MSG_ERROR(
- [Gtk 2.0 installation may be too old. Please upgrade your Gtk 2.0 packages or configure without Gtk 2.0 (using --without-gtk2)])]
- [$GTK_LIBS])
- fi
+ # Check whether we have gtk+ 2.0.
+ if test "$with_gtk2" != "no"; then
+ # gdk_display_get_default_group (added in gtk+ 2.4.0) is function currently
+ # needed by vmware-user.
+ AC_VMW_CHECK_LIB([gtk-x11-2.0],
+ [GTK],
+ [gtk+-2.0],
+ [],
+ [2.4.0],
+ [gtk/gtk.h],
+ [gdk_display_get_default_group],
+ [GTK_CPPFLAGS="$GTK_CPPFLAGS -DGTK2"],
+ [AC_MSG_ERROR([Gtk+ 2.0 library not found or too old. Please configure without Gtk+ support (using --without-gtk2) or install the Gtk+ 2.0 devel package.])])
# Unity requires libgdk_pixbuf_xlib, which most systems don't seem to
# provide via "pkg-config --libs gtk+-2.0".
[gdk_pixbuf_xlib-2.0],
[gdk_pixbuf_xlib_init],
[GTK_LIBS="$GTK_LIBS -lgdk_pixbuf_xlib-2.0"],
- [AC_MSG_ERROR(
- [gdk_pixbuf_xlib-2.0 not found. Make sure your Gtk 2.0 installation is sane, or configure without Unity (using --disable-unity).])],
+ [AC_MSG_ERROR([gdk_pixbuf_xlib-2.0 not found. Make sure your Gtk 2.0 installation is sane, or configure without Unity (using --disable-unity).])],
[$GTK_LIBS])
fi
- else
- AC_MSG_ERROR([libgtk not found. Please install the gtk devel package(s).])
+ fi
+
+ #
+ # Check for gtkmm 2.4.0 or greater.
+ #
+
+ if test "$with_gtkmm" != "no"; then
+ CUSTOM_GTKMM_CPPFLAGS="$CUSTOM_GTKMM_CPPFLAGS $GTK_CPPFLAGS"
+ AC_VMW_CHECK_LIBXX([gtkmm-2.4],
+ [GTKMM],
+ [gtkmm-2.4],
+ [],
+ [2.4.0],
+ [gtkmm.h],
+ [],
+ [GTKMM_CPPFLAGS="$GTKMM_CPPFLAGS -DHAVE_GTKMM"],
+ [AC_MSG_ERROR([gtkmm library not found. Please install the libgtkmm devel package(s), or re-configure using --without-gtkmm.])])
fi
fi # End of checks for X libraries
AC_CHECK_LIB(
[crypt],
[crypt],
- [HAVE_CRYPT="yes"
- GUESTD_LDADD="$GUESTD_LDADD -lcrypt"],
+ [HAVE_CRYPT="yes"],
[AC_MSG_ERROR(
[libcrypt not found. Please install the libc/libcrypt devel package(s).])])
AC_CHECK_LIB(
[pthread],
[pthread_mutex_init],
- [GUESTD_LDADD="$GUESTD_LDADD -lpthread"
- VMWARE_USER_LDADD="$VMWARE_USER_LDADD -lpthread"],
+ [HAVE_PTHREAD=yes],
[AC_MSG_ERROR(
[libpthread not found. Please install the libc/libpthread devel package(s).])])
fi
if test "$with_procps" = "yes"; then
- ORIGINAL_LDFLAGS="$LDFLAGS"
- LDFLAGS="$CUSTOM_PROCPS_LIBS $LDFLAGS"
- AC_CHECK_LIB(
- [proc-3.2.7],
- [getstat],
- [if test -n "$CUSTOM_PROCPS_LIBS"; then
- PROCPS_LIBS="$CUSTOM_PROCPS_LIBS"
- else
- PROCPS_LIBS="-lproc-3.2.7"
- fi],
- [AC_MSG_ERROR(
- [libproc not found. Please configure without procps (using --without-procps) or install procps - http://procps.sourceforge.net])])
- LDFLAGS="$ORIGINAL_LDFLAGS"
-
- GUESTD_LDADD="$GUESTD_LDADD $PROCPS_LIBS"
- VMWARE_USER_LDADD="$VMWARE_USER_LDADD $PROCPS_LIBS"
+ # XXX: Force CUSTOM_PROCPS_LIBS to have something so that AC_VMW_CHECK_LIB
+ # properly performs the library check.
+ if test -z "$CUSTOM_PROCPS_LIBS"; then
+ CUSTOM_PROCPS_LIBS="-L/lib"
+ fi
+ AC_VMW_CHECK_LIB([proc-3.2.7],
+ [PROCPS],
+ [],
+ [],
+ [],
+ [],
+ [getstat],
+ [GUESTD_LDADD="$GUESTD_LDADD $PROCPS_LIBS";
+ VMWARE_USER_LDADD="$VMWARE_USER_LDADD $PROCPS_LIBS"],
+ [AC_MSG_ERROR([libproc not found. Please configure without procps (using --without-procps) or install procps - http://procps.sourceforge.net])])
fi
if test "$with_procps" != "yes"; then
[with_dnet=yes])
if test "$with_dnet" = "yes"; then
+ have_dnet=0
# On Debian, dnet is installed via the libdumbnet package. We need to
# detect this so that our source files include dumbnet.h instead of
# dnet.h, which is part of a different package altogether.
- AC_CHECK_PROGS([DNET_CONFIG],
- [dumbnet-config dnet-config],
- [no])
-
- if test "$DNET_CONFIG" != no; then
- DNET_CPPFLAGS="`$DNET_CONFIG --cflags`"
- DNET_LIBS="`$DNET_CONFIG --libs`"
-
- GUESTD_LDADD="$GUESTD_LDADD $DNET_LIBS"
- VMWARE_USER_LDADD="$VMWARE_USER_LDADD $DNET_LIBS"
- if test "$DNET_CONFIG" == dumbnet-config; then
- AC_DEFINE([DNET_IS_DUMBNET], 1, [Define to 1 if substituting Debian's libdumbnet for libdnet.])
- fi
- else
+ AC_VMW_CHECK_LIB([dumbnet],
+ [DNET],
+ [],
+ [dumbnet-config],
+ [],
+ [dumbnet.h],
+ [intf_open],
+ [have_dnet=1;
+ AC_DEFINE([DNET_IS_DUMBNET], 1, [Define to 1 if substituting Debian's libdumbnet for libdnet.])],
+ [])
+
+ if test $have_dnet -eq 0; then
+ AC_VMW_CHECK_LIB([dnet],
+ [DNET],
+ [],
+ [dnet-config],
+ [],
+ [dnet.h],
+ [intf_open],
+ [have_dnet=1],
+ [])
+ fi
+
+ if test $have_dnet -eq 1; then
+ GUESTD_LDADD="$GUESTD_LDADD $DNET_LIBS"
+ VMWARE_USER_LDADD="$VMWARE_USER_LDADD $DNET_LIBS"
+ else
AC_MSG_ERROR(
[dnet-config was not found on your PATH. Please configure without dnet (using --without-dnet) or install dnet - http://libdnet.sourceforge.net])
fi
[],
[with_icu=yes])
-if test "$with_icu" = "yes"; then
+if test "$have_x" = "yes" -o "$with_icu" = "yes"; then
+ AC_CHECK_TOOL([have_cxx], [$CXX], [no])
+ if test "$have_cxx" = "no"; then
+ AC_MSG_ERROR([C++ compiler not found. Make sure you have a C++ compiler installed or configure without X11 (using --without-x) and without ICU (using --without-icu).])
+ fi
+fi
- AC_PATH_PROG([ICU_CONFIG],
- [icu-config],
- [no])
-
- if test "$ICU_CONFIG" != no; then
- ICU_CPPFLAGS="`$ICU_CONFIG --cppflags` -DUSE_ICU"
- ICU_LIBS="`$ICU_CONFIG --ldflags`"
-
- # The icu components are built with C++, so we need to ensure
- # that the C++ linker actually exists, and use it when linking
- # icu into our applications and when performing configuration
- # tests against icu.
- #
- # XXX: Getting automake to choose between the C linker and the
- # C++ linker depending on HAVE_ICU was a royal pain in the ass.
- # The classic way to do this is to define an optional source
- # file for a program with an extension of .cxx, using
- # nodist_EXTRA_fooprogram_SOURCES. This causes automake's
- # linker detection algorithm to see a C++ source file and
- # automatically set up the C++ linker and link line for us.
- # Unfortunately, said linker detection doesn't obey
- # conditionals, which means that it'd always pick the C++
- # linker, regardless of the value of HAVE_ICU. Instead, we are
- # forced to manually set the correct linker in fooprogram_LINK.
- # However, since none of our programs actually contain C++
- # code, automake doesn't make the CXXLINK variable (which
- # contains the linker as well as all link flags) available to
- # us, so we must hard-code the entire link line into
- # fooprogram_LINK. Not exactly a futureproof solution...
- #
- # Additional references on this problem:
- # http://sources.redhat.com/ml/automake/1999-10/msg00101.html
- # http://lists.gnu.org/archive/html/bug-automake/2008-04/msg00010.html
- # http://www.gnu.org/software/automake/manual/automake.html#Libtool-Convenience-Libraries
- # http://www.gnu.org/software/automake/manual/automake.html#C_002b_002b-Support
- AC_CHECK_TOOL(
- [HAVE_CXX],
- [$CXX])
- if test -z "$HAVE_CXX"; then
- AC_MSG_ERROR(
- [No C++ compiler was found on your PATH. Please configure without ICU (using --without-icu) or install a C++ compiler.])
- fi
- AC_LANG_PUSH([C++])
- AC_CHECK_LIB([icuuc],
- [ucasemap_utf8ToTitle_3_8],
- [have_ICU_38="yes"],,
- [$ICU_LIBS])
- AC_LANG_POP([C++])
-
- if test "$have_ICU_38" = "yes"; then
- ICU_CPPFLAGS="$ICU_CPPFLAGS -DHAVE_ICU_38"
- fi
-
- # Easier to give all modules the ICU defines/includes...
- CPPFLAGS="$CPPFLAGS $ICU_CPPFLAGS"
- else
- AC_MSG_ERROR(
- [icu-config was not found on your PATH. Please configure without ICU (using --without-icu) or install ICU - http://www.icu-project.org])
- fi
+if test "$with_icu" = "yes"; then
+ AC_VMW_CHECK_LIBXX([icuuc],
+ [ICU],
+ [],
+ [icu-config],
+ [],
+ [unicode/utf.h],
+ [],
+ [ICU_CPPFLAGS="$ICU_CPPFLAGS -DUSE_ICU"],
+ [AC_MSG_ERROR([ICU library not found. Please configure without ICU (using --without-icu) or install ICU - http://www.icu-project.org])])
+ # Check whether we have ICU 3.8.
+ AC_LANG_PUSH([C++])
+ AC_CHECK_LIB([icuuc],
+ [ucasemap_utf8ToTitle_3_8],
+ [ICU_CPPFLAGS="$ICU_CPPFLAGS -DHAVE_ICU_38"],
+ [],
+ [$ICU_LIBS])
+ AC_LANG_POP([C++])
+
+ # Easier to give all modules the ICU defines/includes...
+ CPPFLAGS="$CPPFLAGS $ICU_CPPFLAGS"
fi
AC_PATH_PROG(
CPPFLAGS="$CPPFLAGS -DVMX86_TOOLS"
CPPFLAGS="$CPPFLAGS -DNO_CORE_ICU"
+# -fvisibility is used by "core service" plugins, but not required.
+ORIGINAL_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -fvisibility=hidden"
+AC_MSG_CHECKING([for GCC flag -fvisibility])
+AC_TRY_COMPILE([],
+ [return 0;],
+ [PLUGIN_CPPFLAGS="-fvisibility=hidden -DGCC_EXPLICIT_EXPORT";
+ AC_MSG_RESULT(yes)],
+ [AC_MSG_RESULT(no)])
+CFLAGS="$ORIGINAL_CFLAGS"
+
BUILDDIR="`pwd`"
INCLUDE_DIR="`cd $srcdir; pwd`/lib/include"
BLD_INCLUDE_DIR="$BUILDDIR/lib/include"
-CPPFLAGS="$CPPFLAGS -I$INCLUDE_DIR -I$BLD_INCLUDE_DIR"
+CPPFLAGS="-I$INCLUDE_DIR -I$BLD_INCLUDE_DIR $CPPFLAGS"
### OS/arch-specific flags / actions
CPPFLAGS="$CPPFLAGS -DSOL10"
MODULES="$MODULES vmhgfs"
fi
+
+ # We build vmxnet on Solaris 9 and 10
+ if test "$osVersion" -lt 511000 -a "$osVersion" -ge 509000; then
+ MODULES="$MODULES vmxnet"
+ fi
fi
AM_CONDITIONAL(BUILD_HGFSMOUNTER, test "$buildHgfsmounter" = "yes")
AM_CONDITIONAL(PAMD, test -d /etc/pam.d)
AM_CONDITIONAL(ENABLE_UNITY, test "$enable_unity" = "yes")
AM_CONDITIONAL(WITH_ROOT_PRIVILEGES, test "$with_root_privileges" = "yes")
-AM_CONDITIONAL(ENABLE_CORE_SERVICES, test "$have_glib_26" = "yes")
AM_CONDITIONAL(HAVE_FUSE, test "$have_fuse" = "yes")
AM_CONDITIONAL(HAVE_GNU_LD, test "$with_gnu_ld" = "yes")
+AM_CONDITIONAL(HAVE_GTKMM, test "$have_x" = "yes" -a "$with_gtkmm" = "yes")
### Feature-specific flags / actions
# Combine where possible
if test "$HAVE_CRYPT" = "yes"; then
LIB_AUTH_CPPFLAGS="$LIB_AUTH_CPPFLAGS -DGLIBC_VERSION_22"
+ GUESTD_LDADD="$GUESTD_LDADD -lcrypt"
+ VIX_LIBADD="$VIX_LIBADD -lcrypt"
fi
if test "$HAVE_WCHAR_H" = "yes"; then
LIB_STRING_CPPFLAGS="$LIB_STRING_CPPFLAGS -DGLIBC_VERSION_22"
fi
+if test "$HAVE_PTHREAD" = "yes"; then
+ GUESTD_LDADD="$GUESTD_LDADD -lpthread"
+ VIX_LIBADD="$VIX_LIBADD -lpthread"
+ VMWARE_USER_LDADD="$VMWARE_USER_LDADD -lpthread"
+fi
+
### Core Services definitions.
-VMTOOLS_LIBS="$BUILDDIR/libvmtools/libvmtools.la"
+VMTOOLS_LIBS="$BUILDDIR/libvmtools/libvmtools.la $GLIB2_LIBS"
VMTOOLS_CPPFLAGS="-DVMTOOLS_USE_GLIB $GLIB2_CPPFLAGS"
+PLUGIN_CPPFLAGS="$VMTOOLS_CPPFLAGS $PLUGIN_CPPFLAGS"
+
+# For plugins, we'd like to build shared libraries but not install them in the
+# usual shared library destination. Problem is, "noinst_LTLIBRARIES" does not
+# create shared libraries by itself: the "rpath" flag seems to be needed to tell
+# libtool it should create one. All I've found as far as documentation goes is
+# this:
+#
+# http://lists.gnu.org/archive/html/libtool/2007-07/msg00065.html
+#
+# The other options are common options we use when building shared libraries.
+PLUGIN_LDFLAGS="-rpath `pwd` -Wl,-z,defs -Wl,-lc"
+
+# In Solaris, the XDR-related functions are not in libc like in Linux and
+# FreeBSD, so binaries need to be linked to some extra libraries.
+XDR_LIBS=
+if test "$os" = "solaris"; then
+ XDR_LIBS="-lnsl -lrpcsvc"
+fi
+
+# Installation directories for core services plugins.
+VMSVC_PLUGIN_INSTALLDIR=$libdir/open-vm-tools/plugins/vmsvc
+VMUSR_PLUGIN_INSTALLDIR=$libdir/open-vm-tools/plugins/vmusr
+
### General substs
AC_SUBST([TARGET_OS])
AC_SUBST([MODULES_DIR])
AC_SUBST([MODULES])
AC_SUBST([COMMON_XLIBS])
-AC_SUBST([GLIB2_CPPFLAGS])
-AC_SUBST([GLIB2_LIBS])
-AC_SUBST([GTK_CPPFLAGS])
-AC_SUBST([GTK_LIBS])
-AC_SUBST([DNET_CPPFLAGS])
-AC_SUBST([DNET_LIBS])
-AC_SUBST([PROCPS_LIBS])
-AC_SUBST([ICU_CPPFLAGS])
-AC_SUBST([ICU_LIBS])
AC_SUBST([PAM_PREFIX])
-AC_SUBST([URIPARSER_CPPFLAGS])
-AC_SUBST([URIPARSER_LIBS])
-AC_SUBST([LIBPNG_CPPFLAGS])
-AC_SUBST([LIBPNG_LIBS])
+AC_SUBST([PLUGIN_CPPFLAGS])
+AC_SUBST([PLUGIN_LDFLAGS])
AC_SUBST([VMTOOLS_CPPFLAGS])
AC_SUBST([VMTOOLS_LIBS])
-AC_SUBST([ZLIB_CPPFLAGS])
-AC_SUBST([ZLIB_LIBS])
-AC_SUBST([FUSE_CPPFLAGS])
-AC_SUBST([FUSE_LIBS])
+AC_SUBST([RPCGENFLAGS])
+AC_SUBST([XDR_LIBS])
+AC_SUBST([VMSVC_PLUGIN_INSTALLDIR])
+AC_SUBST([VMUSR_PLUGIN_INSTALLDIR])
### Lib substs
### Program substs
AC_SUBST([GUESTD_LDADD])
-
+AC_SUBST([VIX_LIBADD])
AC_SUBST([VMWARE_USER_CPPFLAGS])
AC_SUBST([VMWARE_USER_LDADD])
lib/conf/Makefile \
lib/dict/Makefile \
lib/dnd/Makefile \
+ lib/dndGuest/Makefile \
lib/dynxdr/Makefile \
lib/err/Makefile \
lib/eventManager/Makefile \
lib/raster/Makefile \
lib/region/Makefile \
lib/resolution/Makefile \
+ lib/rpcChannel/Makefile \
lib/rpcIn/Makefile \
lib/rpcOut/Makefile \
lib/rpcVmx/Makefile \
lib/vmSignal/Makefile \
lib/wiper/Makefile \
guestd/Makefile \
+ services/Makefile \
+ services/vmtoolsd/Makefile \
+ services/plugins/Makefile \
+ services/plugins/guestInfo/Makefile \
+ services/plugins/hgfsServer/Makefile \
+ services/plugins/powerOps/Makefile \
+ services/plugins/resolutionSet/Makefile \
+ services/plugins/timeSync/Makefile \
+ services/plugins/vix/Makefile \
+ services/plugins/vixUser/Makefile \
+ services/plugins/vmbackup/Makefile \
vmware-user/Makefile \
vmware-user-suid-wrapper/Makefile \
toolbox/Makefile \
xferlogs/Makefile \
modules/Makefile \
vmblock-fuse/Makefile \
+ tests/Makefile \
+ tests/vmrpcdbg/Makefile \
+ tests/testDebug/Makefile \
+ tests/testPlugin/Makefile \
scripts/Makefile \
])
pamdir = $(PAM_PREFIX)/pam.d
AM_CFLAGS = -I$(top_builddir)/include
+AM_CFLAGS += -I$(top_srcdir)/services/plugins/vix
vmware_guestd_LDADD =
vmware_guestd_LDADD += ../lib/backdoor/libBackdoor.la
vmware_guestd_SOURCES += debugStdio.c
vmware_guestd_SOURCES += foreignVMToolsDaemon.c
vmware_guestd_SOURCES += foreignVMToolsNetworking.c
-vmware_guestd_SOURCES += foundryToolsDaemon.c
+vmware_guestd_SOURCES += $(top_srcdir)/services/plugins/vix/foundryToolsDaemon.c
vmware_guestd_SOURCES += main.c
vmware_guestd_SOURCES += toolsDaemon.c
echo 'disable-tools-version = "true"' > $(DESTDIR)/etc/vmware-tools/tools.conf
uninstall-hook:
- $(RM) -rf $(DESTDIR)/etc/vmware-tools
+ rm -rf $(DESTDIR)/etc/vmware-tools
#include "guestApp.h"
#include "rpcout.h"
#include "rpcin.h"
+#include "hostinfo.h"
#include "strutil.h"
#include "str.h"
#include "msg.h"
status = TRUE;
#ifdef _WIN32
if (data->stateChgInProgress == GUESTOS_STATECHANGE_REBOOT || data->stateChgInProgress == GUESTOS_STATECHANGE_HALT) {
- if (System_GetOSType() >= OS_VISTA) {
+ if (Hostinfo_GetOSType() >= OS_VISTA) {
DISABLE_RES_CAPS();
}
}
* current UIs will treat as unsupported.
*/
if (!RpcOut_sendOne(NULL, NULL, "tools.capability.display_topology_set %s",
- System_GetOSType() >= OS_WINXP ? "2" : "0")) {
+ Hostinfo_GetOSType() >= OS_WINXP ? "2" : "0")) {
Debug("ToolsDaemonTcloCapReg: Unable to register display topology set "
"capability\n");
}
#if defined(WIN32)
HgfsUsability_RegisterServiceCaps();
- if (System_GetOSType() >= OS_VISTA) {
+ if (Hostinfo_GetOSType() >= OS_VISTA) {
ServiceHelpers_SendResolutionCaps();
}
#endif
if FREEBSD
install-exec-hook:
- $(MV) $(DESTDIR)$(sbindir)/mount.vmhgfs \
+ mv $(DESTDIR)$(sbindir)/mount.vmhgfs \
$(DESTDIR)$(sbindir)/mount_vmhgfs
if WITH_ROOT_PRIVILEGES
chmod u+s $(DESTDIR)$(sbindir)/mount_vmhgfs
-$(LN_S) $(DESTDIR)$(sbindir)/mount_vmhgfs \
$(DESTDIR)/sbin/mount_vmhgfs &> /dev/null
uninstall-hook:
- -$(RM) -f $(DESTDIR)$(sbindir)/mount_vmhgfs &> /dev/null
+ rm -f $(DESTDIR)$(sbindir)/mount_vmhgfs
else
install-exec-hook:
if WITH_ROOT_PRIVILEGES
-$(LN_S) $(DESTDIR)$(sbindir)/mount.vmhgfs \
$(DESTDIR)/sbin/mount.vmhgfs &> /dev/null
uninstall-hook:
- -$(RM) -f $(DESTDIR)/sbin/mount.vmhgfs &> /dev/null
+ rm -f $(DESTDIR)/sbin/mount.vmhgfs
endif !FREEBSD
#if defined(__FreeBSD__) || defined(__APPLE__)
# include <sys/uio.h>
# include <sys/param.h>
+
# define MS_MANDLOCK 0
# define MS_RDONLY MNT_RDONLY
# define MS_SYNCHRONOUS MNT_SYNCHRONOUS
* 10.4 one. Once this is built against the newer library, this should be changed.
*/
# define MS_NOATIME 0
+# endif
#endif
-#endif
-
-
#include <sys/mount.h>
#include <pwd.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
-#ifdef MOUNTED // defined in mntent.h
+#ifdef MOUNTED /* defined in mntent.h */
/*
* If VM_HAVE_MTAB is set, hgfsmounter will update /etc/mtab. This is not necessary on
* systems such as FreeBSD (and possibly Solaris) that don't have a mtab or the mntent.h
#define LOG(format, ...) (beVerbose ? printf(format, ##__VA_ARGS__) : 0)
#endif
+typedef struct MountOptions {
+ char *opt; /* Option name */
+ int flag; /* Corresponding flag */
+ Bool set; /* Whether the flag should be set or reset */
+ char *helpMsg; /* Help message for the option */
+ char *logMsg; /* Log message to emit when option was detected */
+ /* Special handler for more complex options */
+ Bool (*handler)(const char *opt,
+ HgfsMountInfo *mountInfo, int *flags);
+} MountOptions;
+
static char *thisProgram;
static char *thisProgramBase;
static char *shareName;
static char *mountPoint;
static Bool beVerbose = FALSE;
-static void PrintVersion(void);
-static void PrintUsage(void);
-static size_t GetPathMax(const char *path);
-static Bool ParseShareName(const char *shareName,
- const char **shareNameHost,
- const char **shareNameDir);
-static Bool ParseUid(const char *uidString,
- uid_t *uid);
-static Bool ParseGid(const char *gidString,
- gid_t *gid);
-static Bool ParseOptions(const char *optionString,
- HgfsMountInfo *mountInfo,
- int *flags);
-#ifdef VM_HAVE_MTAB
-static void UpdateMtab(HgfsMountInfo *mountInfo,
- int flags);
-#endif
-
/*
*-----------------------------------------------------------------------------
*
}
-/*
- *-----------------------------------------------------------------------------
- *
- * PrintUsage --
- *
- * Displays usage for the HGFS mounting utility, and exits with failure.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-PrintUsage(void)
-{
- printf("Usage: %s <sharename> <dir> [-o <options>]\n", thisProgramBase);
- printf("Mount the HGFS share, specified by name, to a local directory.\n");
- printf("Share name must be in host:dir format.\n\nOptions:\n");
- printf(" uid=<arg> mount owner (by uid or username)\n");
- printf(" gid=<arg> mount group (by gid or groupname)\n");
- printf(" fmask=<arg> file umask (in octal)\n");
- printf(" dmask=<arg> directory umask (in octal)\n");
- printf(" ro mount read-only\n");
- printf(" rw mount read-write (default)\n");
- printf(" nosuid ignore suid/sgid bits\n");
- printf(" suid allow suid/sgid bits (default)\n");
-#ifdef MS_NODEV
- printf(" nodev prevent device node access\n");
- printf(" dev allow device node access (default)\n");
-#endif
- printf(" noexec prevent program execution\n");
- printf(" exec allow program execution (default)\n");
- printf(" sync file writes are synchronous\n");
- printf(" async file writes are asynchronous (default)\n");
- printf(" mand allow mandatory locks\n");
- printf(" nomand prevent mandatory locks (default)\n");
- printf(" noatime do not update access times\n");
- printf(" atime update access times (default)\n");
- printf(" nodiratime do not update directory access times\n");
- printf(" adirtime update directory access times (default)\n");
- printf(" ttl=<arg> time before file attributes must be\n");
- printf(" revalidated (in seconds). Improves\n");
- printf(" performance but decreases coherency.\n");
- printf(" Defaults to 1 if not set.\n");
- printf("\n");
- printf("This command is intended to be run from within /bin/mount by\n");
- printf("passing the option '-t %s'. For example:\n", HGFS_NAME);
- printf(" mount -t %s .host:/ /mnt/hgfs/\n", HGFS_NAME);
- printf(" mount -t %s .host:/foo /mnt/foo\n", HGFS_NAME);
- printf(" mount -t %s .host:/foo/bar /var/lib/bar\n", HGFS_NAME);
- exit(EXIT_FAILURE);
-}
-
-
/*
*-----------------------------------------------------------------------------
*
const char **shareNameHost, // OUT: Share name, host component
const char **shareNameDir) // OUT: Share name, dir component
{
- const char *colon, *dir;
+ const char *colon;
+ const char *dir;
/* 1) Must be colon separated into host and dir. */
colon = strchr(shareName, ':');
* ParseUid
*
* A helper function to process a string containing either a user name
- * or a uid and return the resulting uid.
+ * or a uid and set up mountInfo accordingly.
*
* Results:
- * TRUE on success, uid contains the user ID.
- * FALSE on failure, uid is undefined.
+ * TRUE on success, mountInfo modified appropriately, FALSE on failure.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
-
+#ifndef sun
static Bool
-ParseUid(const char *uidString, // IN: String with uid
- uid_t *uid) // OUT: Converted uid
+ParseUid(const char *option, // IN: option string along with value
+ HgfsMountInfo *mountInfo, // OUT: mount data
+ int *flags) // OUT: mount flags
{
Bool success = FALSE;
- uid_t myUid;
+ unsigned int idx = 0;
+ char *optString;
+ char *uidString;
+ uid_t myUid = 0;
+
+ ASSERT(option);
+ ASSERT(mountInfo);
+ ASSERT(flags);
- ASSERT(uidString);
- ASSERT(uid);
+ /* Figure where value starts, we don't need result, just index. */
+ optString = StrUtil_GetNextToken(&idx, option, "=");
+ ASSERT(optString);
+ uidString = StrUtil_GetNextToken(&idx, option, "=");
+ if (!uidString) {
+ LOG("Error getting the value for uid\n");
+ goto out;
+ }
/*
* The uid can be a direct value or a username which we must first
errno = 0;
myUid = strtoul(uidString, NULL, 10);
if (errno == 0) {
- *uid = myUid;
success = TRUE;
} else {
printf("Bad UID value \"%s\"\n", uidString);
if (!(pw = getpwnam(uidString))) {
printf("Bad user name \"%s\"\n", uidString);
} else {
- *uid = pw->pw_uid;
+ myUid = pw->pw_uid;
success = TRUE;
}
endpwent();
}
+
+ if (success) {
+ mountInfo->uid = myUid;
+ mountInfo->uidSet = TRUE;
+ LOG("Setting mount owner to %"FMTUID"\n", myUid);
+ }
+
+ free(uidString);
+out:
+ free(optString);
return success;
}
-
+#endif
/*
*-----------------------------------------------------------------------------
* ParseGid
*
* A helper function to process a string containing either a group name
- * or a gid and return the resulting gid.
+ * or a gid and set up mountInfo accordingly.
*
* Results:
- * TRUE on success, gid contains the group ID.
- * FALSE on failure, gid is undefined.
+ * TRUE on success, mountInfo modified appropriately, FALSE on failure.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
-
+#ifndef sun
static Bool
-ParseGid(const char *gidString, // IN: String with gid
- gid_t *gid) // OUT: Converted gid
+ParseGid(const char *option, // IN: option string along with value
+ HgfsMountInfo *mountInfo, // OUT: mount data
+ int *flags) // OUT: mount flags
{
Bool success = FALSE;
- gid_t myGid;
+ unsigned int idx = 0;
+ char *optString;
+ char *gidString;
+ gid_t myGid = 0;
- ASSERT(gidString);
- ASSERT(gid);
+ ASSERT(option);
+ ASSERT(mountInfo);
+ ASSERT(flags);
+
+ /* Figure where value starts, we don't need result, just index. */
+ optString = StrUtil_GetNextToken(&idx, option, "=");
+ ASSERT(optString);
+ gidString = StrUtil_GetNextToken(&idx, option, "=");
+ if (!gidString) {
+ LOG("Error getting the value for gid\n");
+ goto out;
+ }
/*
* The gid can be a direct value or a group name which we must first
errno = 0;
myGid = strtoul(gidString, NULL, 10);
if (errno == 0) {
- *gid = myGid;
success = TRUE;
} else {
printf("Bad GID value \"%s\"\n", gidString);
if (!(gr = getgrnam(gidString))) {
printf("Bad group name \"%s\"\n", gidString);
} else {
- *gid = gr->gr_gid;
+ myGid = gr->gr_gid;
success = TRUE;
}
endpwent();
}
+
+ if (success) {
+ mountInfo->gid = myGid;
+ mountInfo->gidSet = TRUE;
+ LOG("Setting mount group to %"FMTUID"\n", myGid);
+ }
+
+ free(gidString);
+out:
+ free(optString);
+ return success;
+}
+#endif
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ParseMask
+ *
+ * A helper function to parse a string containing File/Directory
+ * mask value.
+ *
+ * Results:
+ * TRUE on success, along with the mask, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+#ifndef sun
+static Bool
+ParseMask(const char *option, // IN: option string along with value
+ unsigned short *pmask) // OUT: parsed mask
+{
+ Bool success = FALSE;
+ unsigned int idx = 0;
+ char *optString;
+ char *maskString;
+ unsigned short mask;
+
+ optString = StrUtil_GetNextToken(&idx, option, "=");
+ ASSERT(optString);
+ maskString = StrUtil_GetNextToken(&idx, option, "=");
+ if (!maskString) {
+ LOG("Error getting the value for %s\n", optString);
+ goto out;
+ }
+
+ /*
+ * The way to check for an overflow in strtol(3), according to its
+ * man page.
+ */
+ errno = 0;
+ mask = strtol(maskString, NULL, 8);
+ if (errno == 0) {
+ *pmask = mask;
+ success = TRUE;
+ } else {
+ LOG("Error, overflow in %s\n", optString);
+ }
+
+ free(maskString);
+out:
+ free(optString);
return success;
}
+#endif
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ParseFmask
+ *
+ * A helper function to process a string containing File mask value.
+ *
+ * Results:
+ * TRUE on success, mountInfo modified appropriately, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+#ifndef sun
+static Bool
+ParseFmask(const char *option, // IN: option string along with value
+ HgfsMountInfo *mountInfo, // OUT: mount data
+ int *flags) // OUT: mount flags
+{
+ ASSERT(option);
+ ASSERT(mountInfo);
+
+ if (ParseMask(option, &mountInfo->fmask)) {
+ LOG("Setting mount fmask to %o\n", mountInfo->fmask);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ParseDmask
+ *
+ * A helper function to process a string containing dmask value.
+ *
+ * Results:
+ * TRUE on success, mountInfo modified appropriately, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+#ifndef sun
+static Bool
+ParseDmask(const char *option, // IN: option string along with value
+ HgfsMountInfo *mountInfo, // OUT: mount data
+ int *flags) // OUT: mount flags
+{
+ ASSERT(option);
+ ASSERT(mountInfo);
+
+ if (ParseMask(option, &mountInfo->fmask)) {
+ LOG("Setting mount dmask to %o\n", mountInfo->dmask);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ParseTtl
+ *
+ * A helper function to process a string containing TTL value.
+ *
+ * Results:
+ * TRUE on success, mountInfo modified appropriately, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+#ifndef sun
+static Bool
+ParseTtl(const char *option, // IN: option string along with value
+ HgfsMountInfo *mountInfo, // OUT: mount data
+ int *flags) // OUT: mount flags
+{
+ Bool success = FALSE;
+ unsigned int idx = 0;
+ char *optString;
+ int32 ttl;
+
+ ASSERT(option);
+ ASSERT(mountInfo);
+ ASSERT(flags);
+
+ /* Figure where value starts, we don't need result, just index. */
+ optString = StrUtil_GetNextToken(&idx, option, "=");
+ ASSERT(optString);
+
+ if (StrUtil_GetNextIntToken(&ttl, &idx, option, "=") && ttl > 0) {
+ LOG("Setting maximum attribute TTL to %u\n", ttl);
+ mountInfo->ttl = ttl;
+ success = TRUE;
+ } else {
+ LOG("Error getting the value for ttl\n");
+ }
+
+ free(optString);
+ return success;
+}
+#endif
+
+static MountOptions mountOptions[] = {
+ { "ro", MS_RDONLY, TRUE, "mount read-only",
+ "Setting mount read-only", NULL },
+ { "rw", MS_RDONLY, FALSE, "mount read-write",
+ "Setting mount read-write", NULL },
+ { "nosuid", MS_NOSUID, TRUE, "ignore suid/sgid bits",
+ "Setting mount option for allowing suid/sgid bits off", NULL },
+ { "suid", MS_NOSUID, FALSE, "allow suid/sgid bits (default)",
+ "Setting mount option for allowing suid/sgid bits on", NULL },
+
+#ifndef sun /* Solaris does not have any of these options */
+
+ { "uid=<arg>", 0, TRUE, "mount owner (by uid or username)",
+ NULL, ParseUid },
+ { "gid=<arg>", 0, TRUE, "mount group (by gid or groupname)",
+ NULL, ParseGid },
+ { "fmask=<arg>", 0, TRUE, "file umask (in octal)",
+ NULL, ParseFmask },
+ { "dmask=<arg>", 0, TRUE, "directory umask (in octal)",
+ NULL, ParseDmask },
+#ifdef MS_NODEV
+ { "nodev", MS_NODEV, TRUE, "prevent device node access",
+ "Setting mount option for accessing device nodes off", NULL },
+ { "dev", MS_NODEV, FALSE, "allow device node access (default)",
+ "Setting mount option for accessing device nodes on", NULL },
+#endif
+ { "noexec", MS_NOEXEC, TRUE, "prevent program execution",
+ "Setting mount option for program execution off", NULL },
+ { "exec", MS_NOEXEC, FALSE, "allow program execution (default)",
+ "Setting mount option for program execution on", NULL },
+ { "sync", MS_SYNCHRONOUS, TRUE, "file writes are synchronous",
+ "Setting mount synchronous writes", NULL },
+ { "async", MS_SYNCHRONOUS, FALSE, "file writes are asynchronous (default)",
+ "Setting mount synchronous writes", NULL },
+ { "mand", MS_MANDLOCK, TRUE, "allow mandatory locks",
+ "Setting mount option for allow mandatory locks on", NULL },
+ { "nomand", MS_MANDLOCK, FALSE, "prevent mandatory locks (default)",
+ "Setting mount option for allow mandatory locks off", NULL },
+ { "noatime", MS_NOATIME, TRUE, "do not update access times",
+ "Setting mount option for updating access times off", NULL },
+ { "atime", MS_NOATIME, FALSE, "update access times (default)",
+ "Setting mount option for updating access times on", NULL },
+ { "nodiratime", MS_NOATIME, TRUE, "do not update directory access times",
+ "Setting mount option for updating directory access times off", NULL },
+ { "diratime", MS_NOATIME, FALSE, "update access directory times (default)",
+ "Setting mount option for updating directory access times on", NULL },
+ { "ttl=<arg>", 0, TRUE,
+ "time before file attributes must be\n"
+ "revalidated (in seconds). Improves\n"
+ "performance but decreases coherency.\n"
+ "Defaults to 1 if not set.\n",
+ NULL, ParseTtl },
+ { "bind", MS_BIND, TRUE, "perform bind mount",
+ "Setting mount type to bind", NULL },
+ { "bind", MS_MOVE, TRUE, "move an existig mount point",
+ "Setting mount type to move", NULL },
+#endif
+
+ { "remount", MS_REMOUNT, TRUE, "remount already mounted filesystem",
+ "Setting mount type to remount", NULL }
+};
+
/*
*-----------------------------------------------------------------------------
*
int *flags) // OUT: Flags we might modify
{
unsigned int commaIndex = 0;
- Bool valid, success = FALSE;
+ Bool success = FALSE;
char *key = NULL;
char *keyVal = NULL;
+ int i;
ASSERT(optionString);
ASSERT(mountInfo);
goto out;
}
- /*
- * Here are all our recognized option keys. Some have corresponding
- * values, others don't.
- */
- if (strcmp(key, "fmask") == 0) {
- char *fmaskString = StrUtil_GetNextToken(&equalsIndex, keyVal, "=");
- if (fmaskString != NULL) {
- unsigned short fmask;
-
- /*
- * The way to check for an overflow in strtol(3), according to its
- * man page.
- */
- errno = 0;
- fmask = strtol(fmaskString, NULL, 8);
- free(fmaskString);
- if (errno == 0) {
- LOG("Setting mount fmask to %o\n", fmask);
- mountInfo->fmask = fmask;
- } else {
- LOG("Error, overflow in fmask\n");
- goto out;
- }
- } else {
- LOG("Error getting the value for fmask\n");
- goto out;
- }
- } else if (strcmp(key, "dmask") == 0) {
- char *dmaskString = StrUtil_GetNextToken(&equalsIndex, keyVal, "=");
- if (dmaskString != NULL) {
- unsigned short dmask;
-
- /*
- * The way to check for an overflow in strtol(3), according to its
- * man page.
- */
- errno = 0;
- dmask = strtol(dmaskString, NULL, 8);
- free(dmaskString);
- if (errno == 0) {
- LOG("Setting mount dmask to %o\n", dmask);
- mountInfo->dmask = dmask;
- } else {
- LOG("Error, overflow in dmask\n");
- goto out;
- }
- } else {
- LOG("Error getting the value for dmask\n");
+ for (i = 0; i < ARRAYSIZE(mountOptions); i++) {
+ Bool match = FALSE;
+ unsigned int idx = 0;
+ char *optName = StrUtil_GetNextToken(&idx, mountOptions[i].opt, "=");
+
+ if (!optName) {
+ printf("Failed to parse option name, out of memory?\n");
goto out;
}
- } else if (strcmp(key, "uid") == 0) {
- char *uidString = StrUtil_GetNextToken(&equalsIndex, keyVal, "=");
- if (uidString != NULL) {
- uid_t uid = 0;
-
- valid = ParseUid(uidString, &uid);
- free(uidString);
- if (valid) {
- mountInfo->uid = uid;
- mountInfo->uidSet = TRUE;
- LOG("Setting mount owner to %u\n", uid);
+
+ match = strcmp(key, optName) == 0;
+ free(optName);
+
+ if (match) {
+ if (mountOptions[i].handler) {
+ if (!mountOptions[i].handler(keyVal, mountInfo, flags)) {
+ goto out;
+ }
} else {
- goto out;
+ if (mountOptions[i].set) {
+ *flags |= mountOptions[i].flag;
+ } else {
+ *flags &= ~mountOptions[i].flag;
+ }
+ LOG("%s\n", mountOptions[i].logMsg);
}
- } else {
- LOG("Error getting the value for uid\n");
- goto out;
+ break;
}
- } else if (strcmp(key, "gid") == 0) {
- char *gidString = StrUtil_GetNextToken(&equalsIndex, keyVal, "=");
- if (gidString != NULL) {
- gid_t gid = 0;
-
- valid = ParseGid(gidString, &gid);
- free(gidString);
- if (valid) {
- mountInfo->gid = gid;
- mountInfo->gidSet = TRUE;
- LOG("Setting mount group to %u\n", gid);
- } else {
- goto out;
- }
- } else {
- LOG("Error getting the value for gid\n");
- goto out;
- }
- } else if (strcmp(key, "ttl") == 0) {
- int32 ttl;
+ }
- if (StrUtil_GetNextIntToken(&ttl, &equalsIndex, keyVal, "=") && ttl > 0) {
- mountInfo->ttl = ttl;
- LOG("Setting maximum attribute TTL to %u\n", ttl);
- } else {
- LOG("Error getting the value for ttl\n");
- goto out;
- }
- } else if (strcmp(key, "rw") == 0) { // can we write to the mount?
- *flags &= ~MS_RDONLY;
- LOG("Setting mount read-write\n");
- } else if (strcmp(key, "ro") == 0) {
- *flags |= MS_RDONLY;
- LOG("Setting mount read-only\n");
- } else if (strcmp(key, "nosuid") == 0) { // allow suid and sgid bits?
- *flags |= MS_NOSUID;
- LOG("Setting mount option for allowing suid/sgid bits off\n");
- } else if (strcmp(key, "suid") == 0) {
- *flags &= ~MS_NOSUID;
- LOG("Setting mount option for allowing suid/sgid bits on\n");
-#ifdef MS_NODEV
- } else if (strcmp(key, "nodev") == 0) { // allow access to device nodes?
- *flags |= MS_NODEV;
- LOG("Setting mount option for accessing device nodes off\n");
- } else if (strcmp(key, "dev") == 0) {
- *flags &= ~MS_NODEV;
- LOG("Setting mount option for accessing device nodes on\n");
-#endif
- } else if (strcmp(key, "noexec") == 0) { // allow program execution?
- *flags |= MS_NOEXEC;
- LOG("Setting mount option for program execution off\n");
- } else if (strcmp(key, "exec") == 0) {
- *flags &= ~MS_NOEXEC;
- LOG("Setting mount option for program execution on\n");
- } else if (strcmp(key, "sync") == 0) { // meaningless at the moment
- *flags |= MS_SYNCHRONOUS;
- LOG("Setting mount synchronous writes\n");
- } else if (strcmp(key, "async") == 0) {
- *flags &= ~MS_SYNCHRONOUS;
- LOG("Setting mount asynchronous writes\n");
- } else if (strcmp(key, "mand") == 0) { // are mandatory locks allowed?
- *flags |= MS_MANDLOCK;
- LOG("Setting mount option for allow mandatory locks on\n");
- } else if (strcmp(key, "nomand") == 0) {
- *flags &= ~MS_MANDLOCK;
- LOG("Setting mount option for allow mandatory locks off\n");
- } else if (strcmp(key, "noatime") == 0) { // don't update access times?
- *flags |= MS_NOATIME;
- LOG("Setting mount option for updating access times off\n");
- } else if (strcmp(key, "atime") == 0) {
- *flags &= ~MS_NOATIME;
- LOG("Setting mount option for updating access times on\n");
- } else if (strcmp(key, "nodiratime") == 0) { // don't update dir atimes?
- *flags |= MS_NODIRATIME;
- LOG("Setting mount option for updating directory access times off\n");
- } else if (strcmp(key, "diratime") == 0) {
- *flags &= ~MS_NODIRATIME;
- LOG("Setting mount option for updating directory access times on\n");
- } else if (strcmp(key, "bind") == 0) { // bind mount?
- *flags |= MS_BIND;
- LOG("Setting mount type to bind\n");
- } else if (strcmp(key, "move") == 0) { // move an existing mount?
- *flags |= MS_MOVE;
- LOG("Setting mount type to move\n");
- } else if (strcmp(key, "remount") == 0) { // remount?
- *flags |= MS_REMOUNT;
- LOG("Setting mount type to remount\n");
- } else {
+ if (i == ARRAYSIZE(mountOptions)) {
LOG("Skipping unrecognized option \"%s\"\n", key);
}
+
free(key);
free(keyVal);
key = NULL;
keyVal = NULL;
}
+
success = TRUE;
- out:
+out:
free(key);
free(keyVal);
return success;
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * PrintUsage --
+ *
+ * Displays usage for the HGFS mounting utility, and exits with failure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+PrintUsage(void)
+{
+ int i;
+
+ printf("Usage: %s <sharename> <dir> [-o <options>]\n", thisProgramBase);
+ printf("Mount the HGFS share, specified by name, to a local directory.\n");
+ printf("Share name must be in host:dir format.\n\nOptions:\n");
+
+ for (i = 0; i < ARRAYSIZE(mountOptions); i++) {
+ Bool printOptName = TRUE;
+ unsigned int tokidx = 0;
+ char *msg;
+
+ while ((msg = StrUtil_GetNextToken(&tokidx,
+ mountOptions[i].helpMsg,
+ "\n")) != NULL) {
+ printf(" %-15s %s\n",
+ printOptName ? mountOptions[i].opt : "", msg);
+ free(msg);
+ printOptName = FALSE;
+ }
+ }
+
+ printf("\n");
+ printf("This command is intended to be run from within /bin/mount by\n");
+ printf("passing the option '-t %s'. For example:\n", HGFS_NAME);
+ printf(" mount -t %s .host:/ /mnt/hgfs/\n", HGFS_NAME);
+ printf(" mount -t %s .host:/foo /mnt/foo\n", HGFS_NAME);
+ printf(" mount -t %s .host:/foo/bar /var/lib/bar\n", HGFS_NAME);
+ exit(EXIT_FAILURE);
+}
+
#ifdef VM_HAVE_MTAB
/*
mountInfo.magicNumber = HGFS_SUPER_MAGIC;
mountInfo.version = HGFS_PROTOCOL_VERSION;
+
+#ifndef sun
mountInfo.fmask = 0;
mountInfo.dmask = 0;
mountInfo.uidSet = FALSE;
mountInfo.ttl = HGFS_DEFAULT_TTL;
mountInfo.shareNameHost = shareNameHost;
mountInfo.shareNameDir = shareNameDir;
+#endif
/*
* This'll write the rest of the options into HgfsMountInfo and possibly
}
#elif defined(__APPLE__)
mntRes = mount(HGFS_NAME, mountPoint, flags, &mountInfo);
+#elif defined(sun)
+ mntRes = mount(mountPoint, mountPoint, MS_DATA | flags, HGFS_NAME,
+ &mountInfo, sizeof mountInfo);
#endif
if (mntRes) {
perror("Error: cannot mount filesystem");
SUBDIRS += dict
SUBDIRS += deployPkg
SUBDIRS += dnd
+if HAVE_GTKMM
+ SUBDIRS += dndGuest
+endif
SUBDIRS += dynxdr
SUBDIRS += err
SUBDIRS += eventManager
if HAVE_X11
SUBDIRS += resolution
endif
+SUBDIRS += rpcChannel
SUBDIRS += rpcIn
SUBDIRS += rpcOut
SUBDIRS += rpcVmx
*/
if (iconName[0] != '/') {
char *ctmp2;
- char *ctmpext;
int i;
+ static const char *iconExtensions[] = {
+ "", // MUST be first entry.
+ ".png",
+ ".xpm",
+ ".gif",
+ ".svg",
+ };
+
myIconName = NULL;
- ctmpext = strrchr(iconName, '.');
+
ctmp2 = g_alloca(PATH_MAX);
for (i = 0; !myIconName && i < ARRAYSIZE(extraIconPaths); i++) {
+ int j;
+
if (!extraIconPaths[i]) {
continue;
}
- if (ctmpext) {
- g_snprintf(ctmp2, PATH_MAX, "%s/%s", extraIconPaths[i], iconName);
- if (g_file_test(ctmp2, G_FILE_TEST_EXISTS)) {
- myIconName = ctmp2;
- foundItInFile = TRUE;
+ /*
+ * Per Desktop Entry Specification and Icon Theme Specification, I don't
+ * believe that the iconName, unless it's an absolute path, should include
+ * the file extension.
+ *
+ * However, empirical evidence shows that -many- applications ignore that
+ * and may specify an icon of, for example, "foo.png". We'll also handle
+ * those special cases here.
+ */
+ for (j = 0; !myIconName && j < ARRAYSIZE(iconExtensions); j++) {
+ g_snprintf(ctmp2, PATH_MAX, "%s/%s%s", extraIconPaths[i], iconName,
+ iconExtensions[j]);
+ if (!g_file_test(ctmp2, G_FILE_TEST_EXISTS)) {
+ continue;
}
- } else {
- static const char *iconExtensions[] = {
- ".png",
- ".xpm",
- ".gif",
- ".svg",
- };
- int j;
-
- for (j = 0; j < ARRAYSIZE(iconExtensions); j++) {
- g_snprintf(ctmp2, PATH_MAX, "%s/%s%s",
- extraIconPaths[i],
- iconName, iconExtensions[j]);
- if (g_file_test(ctmp2, G_FILE_TEST_EXISTS)) {
- myIconName = ctmp2;
- foundItInFile = TRUE;
- break;
+
+ if (j != 0) {
+ /*
+ * Case 1: We located an icon by appending an image extension to
+ * IconName. Success!
+ */
+ myIconName = ctmp2; // Will break "i" loop.
+ foundItInFile = TRUE;
+ break;
+ } else {
+ /*
+ * Case 2: We found an icon without appending an extension. Verify
+ * that the filename contains a valid image extension.
+ */
+ int k;
+ char *ctmpext = strrchr(ctmp2, '.');
+ for (k = 1; ctmpext && k < ARRAYSIZE(iconExtensions); k++) {
+ if (strcmp(ctmpext, iconExtensions[k]) == 0) {
+ myIconName = ctmp2; // Will break "i" loop.
+ foundItInFile = TRUE;
+ break;
+ }
}
}
}
noinst_LTLIBRARIES = libDnd.la
libDnd_la_SOURCES =
+libDnd_la_SOURCES += dndClipboard.c
libDnd_la_SOURCES += dndCommon.c
libDnd_la_SOURCES += dndLinux.c
+libDnd_la_SOURCES += dndMsg.c
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+
+/*
+ * dndClipboard.c
+ *
+ * Implements dndClipboard.h
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "vm_assert.h"
+
+#include "dndClipboard.h"
+#include "dndInt.h"
+
+
+#define CPFormatToIndex(x) ((unsigned int)(x) - 1)
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipItemInit --
+ *
+ * CPClipboardItem constructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+CPClipItemInit(CPClipItem *item) // IN/OUT: the clipboard item
+{
+ ASSERT(item);
+
+ item->buf = NULL;
+ item->size = 0;
+ item->exists = FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipItemDestroy --
+ *
+ * CPCilpboardItem destructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+CPClipItemDestroy(CPClipItem *item) // IN/OUT: the clipboard item
+{
+ ASSERT(item);
+
+ free(item->buf);
+ item->buf = NULL;
+ item->size = 0;
+ item->exists = FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipItemCopy --
+ *
+ * Copy clipboard item from src to dest.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipItemCopy(CPClipItem *dest, // IN: dest clipboard item
+ const CPClipItem *src) // IN: source clipboard item
+{
+ ASSERT(dest);
+ ASSERT(src);
+
+ if (src->buf) {
+ void *tmp = dest->buf;
+ dest->buf = realloc(dest->buf, src->size);
+ if (!dest->buf) {
+ dest->buf = tmp;
+ return FALSE;
+ }
+ memcpy(dest->buf, src->buf, src->size);
+ }
+
+ dest->size = src->size;
+ dest->exists = src->exists;
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_Init --
+ *
+ * Constructor for CPClipboard.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+CPClipboard_Init(CPClipboard *clip) // IN/OUT: the clipboard
+{
+ unsigned int i;
+
+ ASSERT(clip);
+
+ clip->changed = TRUE;
+ for (i = CPFORMAT_MIN; i < CPFORMAT_MAX; ++i) {
+ CPClipItemInit(&clip->items[CPFormatToIndex(i)]);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_Destroy --
+ *
+ * Destroys a clipboard.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+CPClipboard_Destroy(CPClipboard *clip) // IN/OUT: the clipboard
+{
+ unsigned int i;
+
+ ASSERT(clip);
+
+ for (i = CPFORMAT_MIN; i < CPFORMAT_MAX; ++i) {
+ CPClipItemDestroy(&clip->items[CPFormatToIndex(i)]);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_Clear --
+ *
+ * Clears the items in CPClipboard.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+CPClipboard_Clear(CPClipboard *clip) // IN/OUT: the clipboard
+{
+ unsigned int i;
+
+ ASSERT(clip);
+
+ clip->changed = TRUE;
+ for (i = CPFORMAT_MIN; i < CPFORMAT_MAX; ++i) {
+ CPClipboard_ClearItem(clip, i);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_SetItem --
+ *
+ * Makes a copy of the item adds it to the clipboard. If something
+ * already exists for the format it is overwritten. To set a promised
+ * type, pass in NULL for buffer and 0 for the size.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipboard_SetItem(CPClipboard *clip, // IN/OUT: the clipboard
+ const DND_CPFORMAT fmt, // IN: the item format
+ const void *clipitem, // IN: the item
+ const size_t size) // IN: the item size
+{
+ CPClipItem *item;
+ void *newBuf = NULL;
+
+ ASSERT(clip);
+
+ if (!(CPFORMAT_UNKNOWN < fmt && fmt < CPFORMAT_MAX)) {
+ return FALSE;
+ }
+
+ if (!CPClipboard_ClearItem(clip, fmt)) {
+ return FALSE;
+ }
+
+ item = &clip->items[CPFormatToIndex(fmt)];
+
+ if (clipitem) {
+ newBuf = malloc(size);
+ if (!newBuf) {
+ return FALSE;
+ }
+ memcpy(newBuf, clipitem, size);
+ }
+
+ item->buf = newBuf;
+ item->size = size;
+ item->exists = TRUE;
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_ClearItem --
+ *
+ * Clears the item in the clipboard.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipboard_ClearItem(CPClipboard *clip, // IN: the clipboard
+ DND_CPFORMAT fmt) // IN: item to be cleared
+{
+ CPClipItem *item;
+
+ ASSERT(clip);
+
+ if (!(CPFORMAT_UNKNOWN < fmt && fmt < CPFORMAT_MAX)) {
+ return FALSE;
+ }
+
+ item = &clip->items[CPFormatToIndex(fmt)];
+
+ free(item->buf);
+ item->buf = NULL;
+ item->size = 0;
+ item->exists = FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_GetItem --
+ *
+ * Get the clipboard item of format fmt from the clipboard. The clipboard
+ * maintains ownership of the data. If the item is promised, the buffer
+ * will contain NULL and the size will be 0.
+ *
+ * Results:
+ * TRUE if item exists, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipboard_GetItem(const CPClipboard *clip, // IN: the clipboard
+ DND_CPFORMAT fmt, // IN: the format
+ void **buf, // OUT
+ size_t *size) // OUT
+{
+ ASSERT(clip);
+ ASSERT(size);
+ ASSERT(buf);
+
+ if(!(CPFORMAT_UNKNOWN < fmt && fmt < CPFORMAT_MAX)) {
+ return FALSE;
+ }
+
+ if (clip->items[CPFormatToIndex(fmt)].exists) {
+ *buf = clip->items[CPFormatToIndex(fmt)].buf;
+ *size = clip->items[CPFormatToIndex(fmt)].size;
+ return TRUE;
+ } else {
+ ASSERT(!clip->items[CPFormatToIndex(fmt)].size);
+ return FALSE;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_ItemExists --
+ *
+ * Check if the clipboard item of format fmt exists or not.
+ *
+ * Results:
+ * TRUE if item exists, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipboard_ItemExists(const CPClipboard *clip, // IN: the clipboard
+ DND_CPFORMAT fmt) // IN: the format
+{
+ ASSERT(clip);
+
+ if(!(CPFORMAT_UNKNOWN < fmt && fmt < CPFORMAT_MAX)) {
+ return FALSE;
+ }
+
+ return (clip->items[CPFormatToIndex(fmt)].exists &&
+ clip->items[CPFormatToIndex(fmt)].size > 0);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_IsEmpty --
+ *
+ * Check if the clipboard item of format fmt exists or not.
+ *
+ * Results:
+ * TRUE if item exists, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipboard_IsEmpty(const CPClipboard *clip) // IN: the clipboard
+{
+ unsigned int i;
+
+ ASSERT(clip);
+
+ for (i = CPFORMAT_MIN; i < CPFORMAT_MAX; ++i) {
+ if (clip->items[CPFormatToIndex(i)].exists &&
+ clip->items[CPFormatToIndex(i)].size > 0) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_SetChanged --
+ *
+ * Set clip->changed.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+CPClipboard_SetChanged(CPClipboard *clip, // IN/OUT: the clipboard
+ Bool changed) // IN
+{
+ clip->changed = changed;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_Changed --
+ *
+ * Return clip->changed.
+ *
+ * Results:
+ * Return clip->changed.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipboard_Changed(const CPClipboard *clip) // IN: the clipboard
+{
+ return clip->changed;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_Copy --
+ *
+ * Copies the clipboard contents from src to dest. Assumes that dest has
+ * been initialized and contains no data.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure. On failure the caller should
+ * destroy the object to ensure memory is cleaned up.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipboard_Copy(CPClipboard *dest, // IN: the desination clipboard
+ const CPClipboard *src) // IN: the source clipboard
+{
+ unsigned int i;
+
+ ASSERT(dest);
+ ASSERT(src);
+
+ for (i = CPFORMAT_MIN; i < CPFORMAT_MAX; ++i) {
+ if (!CPClipItemCopy(&dest->items[CPFormatToIndex(i)],
+ &src->items[CPFormatToIndex(i)])) {
+ return FALSE;
+ }
+ }
+ dest->changed = src->changed;
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_Serialize --
+ *
+ * Serialize the contents of the CPClipboard out to the provided dynbuf.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipboard_Serialize(const CPClipboard *clip, // IN
+ DynBuf *buf) // OUT: the output buffer
+{
+ DND_CPFORMAT fmt;
+ uint32 maxFmt = CPFORMAT_MAX;
+
+ ASSERT(clip);
+ ASSERT(buf);
+
+ /* First append number of formats in clip. */
+ if (!DynBuf_Append(buf, &maxFmt, sizeof maxFmt)) {
+ return FALSE;
+ }
+
+ /* Append format data one by one. */
+ for (fmt = CPFORMAT_MIN; fmt < CPFORMAT_MAX; ++fmt) {
+ CPClipItem *item = (CPClipItem *)&(clip->items[CPFormatToIndex(fmt)]);
+ if (!DynBuf_Append(buf, &item->exists, sizeof item->exists) ||
+ !DynBuf_Append(buf, &item->size, sizeof item->size)) {
+ return FALSE;
+ }
+ if (item->exists && (item->size > 0) &&
+ !DynBuf_Append(buf, item->buf, item->size)) {
+ return FALSE;
+ }
+ }
+
+ if (!DynBuf_Append(buf, &clip->changed, sizeof clip->changed)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPClipboard_Unserialize --
+ *
+ * Unserialize the arguments of the CPClipboard provided by the buffer.
+ * On failure the clip will be destroyed.
+ *
+ * Results:
+ * TRUE if success, FALSE otherwise
+ *
+ * Side effects:
+ * The clip passed in should be empty, otherwise will cause memory leakage.
+ * On success, arguments found in buf are unserialized into clip.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CPClipboard_Unserialize(CPClipboard *clip, // OUT: the clipboard
+ void *buf, // IN: input buffer
+ size_t len) // IN: buffer length
+{
+ DND_CPFORMAT fmt;
+ BufRead r;
+ uint32 maxFmt;
+
+ ASSERT(clip);
+ ASSERT(buf);
+
+ CPClipboard_Init(clip);
+
+ r.pos = buf;
+ r.unreadLen = len;
+
+ /* First get number of formats in the buf. */
+ if (!DnDReadBuffer(&r, &maxFmt, sizeof maxFmt)) {
+ goto error;
+ }
+
+ /* This version only supports number of formats up to CPFORMAT_MAX. */
+ maxFmt = MIN(CPFORMAT_MAX, maxFmt);
+
+ for (fmt = CPFORMAT_MIN; fmt < maxFmt; ++fmt) {
+ Bool exists;
+ uint32 size;
+
+ if (!DnDReadBuffer(&r, &exists, sizeof exists) ||
+ !DnDReadBuffer(&r, &size, sizeof size)) {
+ goto error;
+ }
+
+ if (exists && size) {
+ if (size > r.unreadLen) {
+ goto error;
+ }
+
+ if (!CPClipboard_SetItem(clip, fmt, r.pos, size)) {
+ goto error;
+ }
+ if (!DnDSlideBuffer(&r, size)) {
+ goto error;
+ }
+ }
+ }
+
+ /* It is possible that clip->changed is missing in some beta products. */
+ if (r.unreadLen == sizeof clip->changed &&
+ !DnDReadBuffer(&r, &clip->changed, sizeof clip->changed)) {
+ goto error;
+ }
+
+ return TRUE;
+
+error:
+ CPClipboard_Destroy(clip);
+ return FALSE;
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dndMsg.c --
+ *
+ * DnDMsg represents an rpc message which is sent across the
+ * wire. Any args that it holds will be written out exactly as stored.
+ *
+ * To protect itself there are many checks to ensure the data which is
+ * serialized and unserialized is sane. Defines and asserts are used to
+ * ensure the message stays under these limits when serializing out and
+ * checks are enforced to ensure that the data to be unserialized remains
+ * under these limits.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "vm_assert.h"
+
+#include "dndMsg.h"
+#include "dndInt.h"
+
+#define LOGLEVEL_MODULE dnd
+#include "loglevel_user.h"
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMsg_Init --
+ *
+ * DnDMsg constructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnDMsg_Init(DnDMsg *msg) // IN/OUT: the message
+{
+ ASSERT(msg);
+
+ msg->ver = 3;
+ msg->cmd = 0;
+ msg->nargs = 0;
+ DynBufArray_Init(&msg->args, 0);
+ msg->expectedArgsSz = 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMsg_Destroy --
+ *
+ * Destroys a message by clearing any of the data that is contained in it.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Frees the arguments' memory.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnDMsg_Destroy(DnDMsg *msg) // IN/OUT: the message
+{
+ uint32 i;
+ uint32 count;
+
+ ASSERT(msg);
+
+ count = DynArray_Count(&msg->args);
+
+ msg->ver = 0;
+ msg->cmd = 0;
+ msg->nargs = 0;
+ msg->expectedArgsSz = 0;
+
+ for (i = 0; i < count; ++i) {
+ DynBuf *b = DynArray_AddressOf(&msg->args, i);
+ DynBuf_Destroy(b);
+ }
+ DynArray_SetCount(&msg->args, 0);
+ DynBufArray_Destroy(&msg->args);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMsg_Cmd --
+ *
+ * Gets the dnd/copy paste command from the header.
+ *
+ * Results:
+ * An uint32 representing the command.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+uint32
+DnDMsg_GetCmd(DnDMsg *msg) // IN/OUT: the message
+{
+ ASSERT(msg);
+
+ return msg->cmd;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMsg_SetCmd --
+ *
+ * Sets the command for the message.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnDMsg_SetCmd(DnDMsg *msg, // IN/OUT: the message
+ uint32 cmd) // IN: the command
+{
+ ASSERT(msg);
+ ASSERT((DND_INVALID < cmd && cmd < DND_MAX) ||
+ (CP_INVALID < cmd && cmd < CP_MAX));
+
+ msg->cmd = cmd;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMsg_NumArgs --
+ *
+ * Determines the number of arguments currently in the DnDMsg.
+ *
+ * Results:
+ * The number of arguments.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+uint32
+DnDMsg_NumArgs(DnDMsg *msg) // IN/OUT: the message
+{
+ ASSERT(msg);
+
+ return DynBufArray_Count(&msg->args);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMsg_GetArg --
+ *
+ * Gets an argument stored in DnDMsg.
+ *
+ * Results:
+ * Null if the argument is out of bounds, otherwise a pointer to a dynbuf
+ * containing the argument.
+ * This dynbuf is still
+ * managed by the DnDMsg and should NOT be destroyed.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+DynBuf *
+DnDMsg_GetArg(DnDMsg *msg, // IN/OUT: the message
+ uint32 idx) // IN: the argument to return
+{
+ ASSERT(msg);
+ ASSERT(0 <= idx && idx < DynBufArray_Count(&msg->args));
+
+ return DynArray_AddressOf(&msg->args, idx);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMsg_AppendArg --
+ *
+ * Adds the data to the end of the argument list in the message. It will
+ * create a copy of the data to be mananged by DnDMsg until the message is
+ * destroyed.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * Increases the internal arg size counter.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+DnDMsg_AppendArg(DnDMsg *msg, // IN/OUT: the message
+ void *buf, // IN: the input buffer
+ size_t len) // IN: the length of the input buffer
+{
+ DynBuf clonebuf;
+
+ ASSERT(msg);
+ ASSERT(buf);
+
+ if (DynBufArray_Count(&msg->args) >= DNDMSG_MAX_ARGS) {
+ return FALSE;
+ }
+
+ DynBuf_Init(&clonebuf);
+ if (!DynBuf_Append(&clonebuf, buf, len)) {
+ goto err;
+ }
+
+ /* The dynbufarray now owns the clonebuf data. */
+ if (!DynBufArray_Push(&msg->args, clonebuf)) {
+ goto err;
+ }
+ return TRUE;
+
+err:
+ DynBuf_Destroy(&clonebuf);
+ return FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMsg_Serialize --
+ *
+ * Serialize the contents of the DnDMsg out to the provided dynbuf. It
+ * will ASSERT if any invariants are broken.
+ *
+ * Results:
+ * TRUE on success.
+ * FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+DnDMsg_Serialize(DnDMsg *msg, // IN/OUT: the message
+ DynBuf* buf) // OUT: the output buffer
+{
+ DynBuf *curArg;
+ uint32 nargs;
+ uint32 i;
+ uint32 serializeArgsSz = 0;
+
+ ASSERT(msg);
+ ASSERT(buf);
+ ASSERT((DND_INVALID < msg->cmd && msg->cmd < DND_MAX) ||
+ (CP_INVALID < msg->cmd && msg->cmd < CP_MAX));
+
+ nargs = DynBufArray_Count(&msg->args);
+
+ for (i = 0; i < nargs; ++i) {
+ DynBuf *b = DynArray_AddressOf(&msg->args, i);
+ serializeArgsSz += sizeof(uint32) + DynBuf_GetSize(b);
+ }
+
+ if (DynBuf_Append(buf, &msg->ver, sizeof msg->ver) &&
+ DynBuf_Append(buf, &msg->cmd, sizeof msg->cmd) &&
+ DynBuf_Append(buf, &nargs, sizeof nargs) &&
+ DynBuf_Append(buf, &serializeArgsSz, sizeof serializeArgsSz)) {
+ int i;
+ uint32 curArgsSz;
+
+ for (i = 0; i < nargs; i++) {
+ curArg = DynBufArray_AddressOf(&msg->args, i);
+ curArgsSz = DynBuf_GetSize(curArg);
+
+ if (!DynBuf_Append(buf, &curArgsSz, sizeof curArgsSz) ||
+ !DynBuf_Append(buf, DynBuf_Get(curArg), curArgsSz)) {
+ return FALSE;
+ }
+ }
+ } else {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMsg_UnserializeHeader --
+ *
+ * Read the header from the buffer into a DnDMsg. Any contents in the
+ * DnDMsg will be destroyed. This allows you to retrieve header
+ * information. These functions are specified in the dndMsg.h. Most
+ * notably, you can retrieve the size of the arguments so that you can
+ * pass a properly sized buffer to DnDMsg_UnserializeArgs.
+ *
+ * This is the one of the two places that nargs is set. The other is
+ * implicitly set by DnDMsg_AppendArg with the push and only ever
+ * realized through the DnDMsg_Serialize function. expectedArgsSz,
+ * curArgSz follows the same idea.
+ *
+ * Results:
+ * DNDMSG_SUCCESS on success.
+ * DNDMSG_INPUT_TOO_SMALL when provided buffer is too small.
+ * DNDMSG_INPUT_ERR when the provided buffer is inconsistant.
+ * DNDMSG_NOMEM when we run out of memory.
+ * DNDMSG_ERR on any other error.
+ *
+ * Side effects:
+ * On success the msg's header will be filled. On failure the msg will be
+ * destroyed.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+DnDMsgErr
+DnDMsg_UnserializeHeader(DnDMsg *msg, // IN/OUT: the message
+ void *buf, // IN: the input buffer
+ size_t len) // IN: the buffer length
+{
+ BufRead r;
+
+ ASSERT(msg);
+ ASSERT(buf);
+
+ r.pos = buf;
+ r.unreadLen = len;
+
+ if (len < DNDMSG_HEADERSIZE_V3) {
+ return DNDMSG_INPUT_TOO_SMALL;
+ }
+
+ /* Read buffer into msg. */
+ if (DnDReadBuffer(&r, &msg->ver, sizeof msg->ver) &&
+ DnDReadBuffer(&r, &msg->cmd, sizeof msg->cmd) &&
+ DnDReadBuffer(&r, &msg->nargs, sizeof msg->nargs) &&
+ DnDReadBuffer(&r, &msg->expectedArgsSz, sizeof msg->expectedArgsSz)) {
+ /* Sanity checks. */
+ if (msg->expectedArgsSz < DNDMSG_MAX_ARGSZ &&
+ (msg->cmd < DND_MAX || msg->cmd < CP_MAX) &&
+ 0 < msg->cmd &&
+ msg->ver >= 3 &&
+ msg->nargs < DNDMSG_MAX_ARGS) {
+ return DNDMSG_SUCCESS;
+ } else {
+ return DNDMSG_INPUT_ERR;
+ }
+ } else {
+ return DNDMSG_INPUT_TOO_SMALL;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMsg_UnserializeArgs --
+ *
+ * Unserialize the arguments of the message provided by the buffer.
+ * Each argument is a uint32 of the size followed by the buffer. On
+ * failure the message will revert to the state which was passed into the
+ * function.
+ *
+ * Results:
+ * DNDMSG_SUCCESS on success.
+ * DNDMSG_INPUT_TOO_SMALL when provided buffer is too small.
+ * DNDMSG_INPUT_ERR when the provided buffer is inconsistant.
+ * DNDMSG_NOMEM when we run out of memory.
+ * DNDMSG_ERR on any other error.
+ *
+ * Side effects:
+ * On success, arguments found in buf are unserialized into msg.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+DnDMsgErr
+DnDMsg_UnserializeArgs(DnDMsg *msg, // IN/OUT: the message
+ void *buf, // IN: input buffer
+ size_t len) // IN: buffer length
+{
+ uint32 i;
+ uint32 count;
+ BufRead r;
+ uint32 readArgsSz = 0;
+
+ void *data = NULL;
+ DnDMsgErr ret = DNDMSG_SUCCESS;
+
+ ASSERT(msg);
+ ASSERT(DynBufArray_Count(&msg->args) == 0);
+ ASSERT(buf);
+
+ r.pos = buf;
+ r.unreadLen = len;
+
+ if (len < msg->expectedArgsSz) {
+ return DNDMSG_INPUT_TOO_SMALL;
+ }
+
+ for (i = 0; i < msg->nargs; ++i) {
+ uint32 argSz;
+ if (!DnDReadBuffer(&r, &argSz, sizeof argSz)) {
+ ret = DNDMSG_INPUT_TOO_SMALL;
+ goto err;
+ }
+
+ if (argSz > DNDMSG_MAX_ARGSZ ||
+ readArgsSz + sizeof (uint32) + argSz > msg->expectedArgsSz) {
+ ret = DNDMSG_INPUT_ERR;
+ goto err;
+ }
+
+ data = malloc(argSz);
+ if (!data) {
+ ret = DNDMSG_NOMEM;
+ goto err;
+ }
+
+ if (!DnDReadBuffer(&r, data, argSz)) {
+ ret = DNDMSG_ERR;
+ goto err;
+ }
+
+ if (!DnDMsg_AppendArg(msg, data, argSz)) {
+ ret = DNDMSG_NOMEM;
+ goto err;
+ }
+ readArgsSz += argSz + sizeof (uint32);
+ free(data);
+ }
+
+ ASSERT(ret == DNDMSG_SUCCESS);
+ return ret;
+
+err:
+ if (data) {
+ free(data);
+ }
+
+ count = DynBufArray_Count(&msg->args);
+ for (i = 0; i < count; ++i) {
+ DynBuf *b = DynArray_AddressOf(&msg->args, i);
+ DynBuf_Destroy(b);
+ }
+ /*
+ * DnDMsg_AppendArg relies on DynBufArray_Push, hence the count needs to be
+ * reset.
+ */
+ DynBufArray_SetCount(&msg->args, 0);
+
+ return ret;
+}
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libDndGuest.la
+
+AM_CFLAGS = @GTK_CPPFLAGS@
+AM_CFLAGS += @GTKMM_CPPFLAGS@
+AM_CFLAGS += @VMWARE_USER_CPPFLAGS@
+AM_CFLAGS += -I$(top_builddir)/include
+
+AM_CPPFLAGS = @GTK_CPPFLAGS@
+AM_CPPFLAGS += @GTKMM_CPPFLAGS@
+AM_CPPFLAGS += @VMWARE_USER_CPPFLAGS@
+AM_CPPFLAGS += -I$(top_builddir)/include
+
+libDndGuest_la_SOURCES =
+libDndGuest_la_SOURCES += copyPaste.cc
+libDndGuest_la_SOURCES += copyPasteRpcV3.cc
+libDndGuest_la_SOURCES += dnd.cc
+libDndGuest_la_SOURCES += dndFileList.cc
+libDndGuest_la_SOURCES += dndTransportGuestRpc.cc
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * copyPaste.cc --
+ *
+ * Implementation of common layer CopyPaste object for guest.
+ */
+
+#include "copyPaste.hh"
+#include "copyPasteRpcV3.hh"
+#include "dndFileList.hh"
+
+extern "C" {
+ #include "util.h"
+ #include "debug.h"
+ #include "file.h"
+ #include "str.h"
+ #include "cpNameUtil.h"
+ #include "hostinfo.h"
+ #include "dndClipboard.h"
+}
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * CopyPaste::CopyPaste --
+ *
+ * Constructor for CopyPaste.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------
+ */
+
+CopyPaste::CopyPaste(void) // IN
+ : mRpc(NULL),
+ mVmxCopyPasteVersion(0)
+{
+ mState = CPSTATE_INVALID;
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * CopyPaste::~CopyPaste --
+ *
+ * Destructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------
+ */
+
+CopyPaste::~CopyPaste(void)
+{
+ delete mRpc;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPaste::VmxCopyPasteVersionChanged --
+ *
+ * Vmx CopyPaste version changed so should create corresponding Rpc and
+ * register callbacks for signals if version changed.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPaste::VmxCopyPasteVersionChanged(struct RpcIn *rpcIn, // IN
+ uint32 version) // IN
+{
+ /* Do nothing if version is not changed. */
+ if (mVmxCopyPasteVersion == version) {
+ return;
+ }
+
+ mVmxCopyPasteVersion = version;
+ Debug("%s: Version: %d", __FUNCTION__, version);
+
+ delete mRpc;
+ mRpc = NULL;
+
+ mState = CPSTATE_INVALID;
+ Hostinfo_GetTimeOfDay(&mStateChangeTime);
+
+ switch (version) {
+ case 1:
+ case 2:
+ /* Here should create CopyPasteRpcV2 for version 1 & 2. */
+ break;
+ case 3:
+ mRpc = new CopyPasteRpcV3(rpcIn);
+ break;
+ default:
+ Debug("%s: got unsupported guest CopyPaste version %u.\n",
+ __FUNCTION__, version);
+ return;
+ }
+
+ if (mRpc) {
+ mRpc->ghGetClipboardChanged.connect(
+ sigc::mem_fun(this, &CopyPaste::OnGetLocalClipboard));
+ mRpc->hgSetClipboardChanged.connect(
+ sigc::mem_fun(this, &CopyPaste::OnGetRemoteClipboardDone));
+ mRpc->hgFileCopyDoneChanged.connect(
+ sigc::mem_fun(this, &CopyPaste::OnHGFileCopyDone));
+ mState = CPSTATE_READY;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPaste::OnGetRemoteClipboardDone --
+ *
+ * Got clipboard data from host. Put it into local buffer and
+ * inform UI to process the clipboard data.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+CopyPaste::OnGetRemoteClipboardDone(const CPClipboard *clip) // IN: new clipboard
+{
+ newClipboard.emit(clip);
+ mState = CPSTATE_READY;
+ Hostinfo_GetTimeOfDay(&mStateChangeTime);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPaste::OnGetLocalClipboard --
+ *
+ * Host is asking for guest clipboard data. Try to get it from local
+ * UI and send to host with GHGetClipboardDone.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+CopyPaste::OnGetLocalClipboard(void)
+{
+ CPClipboard clip;
+ bool ready;
+
+ CPClipboard_Init(&clip);
+ ready = localGetClipboard.emit(&clip);
+ /*
+ * if caller decided to handle this asyncronously, it is responsible for
+ * calling SetRemoteClipboard() when it has completed. Otherwise, call it
+ * now.
+ */
+ if (ready) {
+ SetRemoteClipboard(&clip);
+ }
+ CPClipboard_Destroy(&clip);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPaste::OnHGFileCopyDone --
+ *
+ * Host finished file copy. Inform UI to remove the block.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+CopyPaste::OnHGFileCopyDone(bool success)
+{
+ if (!success && !mStagingDir.empty()) {
+ /* Delete all files if host canceled the file transfer. */
+ DnD_DeleteStagingFiles(mStagingDir.c_str(), FALSE);
+ mStagingDir.clear();
+ }
+ localGetFilesDoneChanged.emit(success);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPaste::SetRemoteClipboard --
+ *
+ * Sets the internal clipboard. Also synchronizes remote clipboard with
+ * the guest clipboard.
+ *
+ * Results:
+ * True if success, false otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+bool
+CopyPaste::SetRemoteClipboard(const CPClipboard* clip) // IN: new clipboard
+{
+ if (!mRpc) {
+ Debug("%s: no valid rpc, guest version is %u.\n",
+ __FUNCTION__, mVmxCopyPasteVersion);
+ return false;
+ }
+
+ if (mState == CPSTATE_INVALID) {
+ Debug("%s: Invalid state.", __FUNCTION__);
+ return false;
+ }
+
+ if (!IsCopyPasteAllowed()) {
+ Debug("%s: CopyPasteAllowed() returned false.", __FUNCTION__);
+ return false;
+ }
+
+ /* Send clipboard data to remote side. */
+ mRpc->GHGetClipboardDone(clip);
+
+ return true;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPaste::GetFiles --
+ *
+ * Gets the files that are referenced on the clipboard.
+ *
+ * Results:
+ * The destination directory if we can start file copy, otherwise empty
+ * string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+std::string
+CopyPaste::GetFiles(std::string dir) // IN: suggested destination directory
+ // in local format
+{
+ std::string destDir;
+ char cpName[FILE_MAXPATH];
+ int32 cpNameSize;
+
+ if (mState == CPSTATE_INVALID) {
+ Debug("%s: Invalid state.", __FUNCTION__);
+ return "";
+ }
+
+ /* Setup staging directory. */
+ destDir = SetupDestDir(dir);
+ if (destDir.empty()) {
+ return "";
+ }
+
+ /* XXX Here should first convert encoding to precomposed UTF8. */
+
+ /* Convert staging name to CP format. */
+ cpNameSize = CPNameUtil_ConvertToRoot(destDir.c_str(),
+ sizeof cpName,
+ cpName);
+ if (cpNameSize < 0) {
+ Debug("%s: Error, could not convert to CPName.\n", __FUNCTION__);
+ return "";
+ }
+
+ if (!mRpc->HGStartFileCopy(cpName, cpNameSize)) {
+ return "";
+ }
+
+ mStagingDir = destDir;
+
+ return destDir;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPaste::SetupDestDir --
+ *
+ * Creates a directory for file transfer. If the destination
+ * dir is provided, we will attempt to copy files to the directory.
+ *
+ * Input directory will be in local format.
+ *
+ * Results:
+ * The destination directory on success, an empty string on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+std::string
+CopyPaste::SetupDestDir(const std::string &destDir) // IN:
+{
+ static const std::string failDir = "";
+
+ if (!destDir.empty() && File_Exists(destDir.c_str())) {
+ mStagingDir = destDir;
+ const char *lastSep = Str_Strrchr(mStagingDir.c_str(), DIRSEPC);
+ if (lastSep && lastSep[1] != '\0') {
+ mStagingDir += DIRSEPS;
+ }
+
+ return mStagingDir;
+ } else {
+ char *newDir;
+
+ newDir = DnD_CreateStagingDirectory();
+ if (newDir != NULL) {
+ mStagingDir = newDir;
+
+ char *lastSep = Str_Strrchr(newDir, DIRSEPC);
+ if (lastSep && lastSep[1] != '\0') {
+ mStagingDir += DIRSEPS;
+ }
+ free(newDir);
+ Debug("%s: destdir: %s", __FUNCTION__, mStagingDir.c_str());
+
+ return mStagingDir;
+ } else {
+ Debug("%s: destdir not created", __FUNCTION__);
+ return failDir;
+ }
+ }
+}
+
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * CopyPasteRpcV3.cc --
+ *
+ * Implementation of the CopyPasteRpcV3 interface.
+ */
+
+
+#include "copyPasteRpcV3.hh"
+#include "dndTransportGuestRpc.hh"
+
+extern "C" {
+ #include "dndMsg.h"
+ #include "debug.h"
+ #include "dndClipboard.h"
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteRpcV3 --
+ *
+ * Constructor of CopyPasteRpcV3 class.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+CopyPasteRpcV3::CopyPasteRpcV3(struct RpcIn *rpcIn) // IN
+{
+ mTransport = new DnDTransportGuestRpc(rpcIn, "copypaste.transport");
+ mTransport->recvMsgChanged.connect(sigc::mem_fun(this, &CopyPasteRpcV3::OnRecvMsg));
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPasteRpcV3::~CopyPasteRpcV3 --
+ *
+ * Destructor of CopyPasteRpcV3.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+CopyPasteRpcV3::~CopyPasteRpcV3(void)
+{
+ delete mTransport;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPasteRpcV3::GHGetClipboardDone --
+ *
+ * Serialize all parameters and pass to transport layer for
+ * CP_GH_GET_CLIPBOARD_DONE signal.
+ *
+ * Results:
+ * TRUE if success, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+bool
+CopyPasteRpcV3::GHGetClipboardDone(const CPClipboard* clip) // IN
+{
+ DnDMsg msg;
+ DynBuf buf;
+ bool ret = FALSE;
+
+ DnDMsg_Init(&msg);
+ DynBuf_Init(&buf);
+
+ /* Serialize clip and output into buf. */
+ if (!CPClipboard_Serialize(clip, &buf)) {
+ Debug("%s: CPClipboard_Serialize failed.\n", __FUNCTION__);
+ goto exit;
+ }
+
+ /* Construct msg with both cmd CP_GH_GET_CLIPBOARD_DONE and buf. */
+ DnDMsg_SetCmd(&msg, CP_GH_GET_CLIPBOARD_DONE);
+ if (!DnDMsg_AppendArg(&msg, DynBuf_Get(&buf), DynBuf_GetSize(&buf))) {
+ Debug("%s: DnDMsg_AppendData failed.\n", __FUNCTION__);
+ goto exit;
+ }
+
+ /* Reset buf. */
+ DynBuf_Destroy(&buf);
+ DynBuf_Init(&buf);
+
+ /* Serialize msg and output to buf. */
+ if (!DnDMsg_Serialize(&msg, &buf)) {
+ Debug("%s: DnDMsg_Serialize failed.\n", __FUNCTION__);
+ goto exit;
+ }
+
+ ret = mTransport->SendMsg((uint8 *)DynBuf_Get(&buf), DynBuf_GetSize(&buf));
+
+exit:
+ DynBuf_Destroy(&buf);
+ DnDMsg_Destroy(&msg);
+ return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPasteRpcV3::HGStartFileCopy --
+ *
+ * Serialize all parameters and pass to transport layer for
+ * CP_HG_START_FILE_COPY signal.
+ *
+ * Results:
+ * TRUE if success, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+bool
+CopyPasteRpcV3::HGStartFileCopy(const char *stagingDirCP, // IN
+ size_t sz) // IN
+{
+ DnDMsg msg;
+ DynBuf buf;
+ bool ret = FALSE;
+
+ DnDMsg_Init(&msg);
+ DynBuf_Init(&buf);
+
+ /* Construct msg with both cmd CP_HG_START_FILE_COPY and stagingDirCP. */
+ DnDMsg_SetCmd(&msg, CP_HG_START_FILE_COPY);
+ if (!DnDMsg_AppendArg(&msg, (void *)stagingDirCP, sz)) {
+ Debug("%s: DnDMsg_AppendData failed.\n", __FUNCTION__);
+ goto exit;
+ }
+
+ /* Serialize msg and output to buf. */
+ if (!DnDMsg_Serialize(&msg, &buf)) {
+ Debug("%s: DnDMsg_Serialize failed.\n", __FUNCTION__);
+ goto exit;
+ }
+
+ ret = mTransport->SendMsg((uint8 *)DynBuf_Get(&buf), DynBuf_GetSize(&buf));
+
+exit:
+ DynBuf_Destroy(&buf);
+ DnDMsg_Destroy(&msg);
+ return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPasteRpcV3::OnRecvMsg --
+ *
+ * Received a new message from transport layer. Unserialize and
+ * translate it and emit corresponding signal.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+CopyPasteRpcV3::OnRecvMsg(const uint8 *data, // IN
+ size_t dataSize) // IN
+{
+ DnDMsg msg;
+ DnDMsgErr ret;
+ DynBuf *buf = NULL;
+
+ DnDMsg_Init(&msg);
+
+ ret = DnDMsg_UnserializeHeader(&msg, (void *)data, dataSize);
+ if (DNDMSG_SUCCESS != ret) {
+ Debug("%s: DnDMsg_UnserializeHeader failed with %d\n",
+ __FUNCTION__, ret);
+ goto exit;
+ }
+
+ ret = DnDMsg_UnserializeArgs(&msg,
+ (void *)&data[DNDMSG_HEADERSIZE_V3],
+ dataSize - DNDMSG_HEADERSIZE_V3);
+ if (DNDMSG_SUCCESS != ret) {
+ Debug("%s: DnDMsg_UnserializeArgs failed with %d\n",
+ __FUNCTION__, ret);
+ goto exit;
+ }
+
+ /* Translate command and emit signal. */
+ switch (DnDMsg_GetCmd(&msg)) {
+ case CP_GH_GET_CLIPBOARD:
+ ghGetClipboardChanged.emit();
+ break;
+ case CP_HG_SET_CLIPBOARD:
+ {
+ CPClipboard clip;
+
+ /* Unserialize clipboard data for the command. */
+ buf = DnDMsg_GetArg(&msg, 0);
+ if (!CPClipboard_Unserialize(&clip, DynBuf_Get(buf), DynBuf_GetSize(buf))) {
+ Debug("%s: CPClipboard_Unserialize failed.\n", __FUNCTION__);
+ goto exit;
+ }
+ hgSetClipboardChanged.emit(&clip);
+ break;
+ }
+ case CP_HG_FILE_COPY_DONE:
+ {
+ bool success = false;
+ buf = DnDMsg_GetArg(&msg, 0);
+ if (sizeof success == DynBuf_GetSize(buf)) {
+ memcpy(&success, DynBuf_Get(buf), DynBuf_GetSize(buf));
+ }
+ hgFileCopyDoneChanged.emit(success);
+ break;
+ }
+ default:
+ Debug("%s: got unsupported new command %d.\n",
+ __FUNCTION__, DnDMsg_GetCmd(&msg));
+ }
+exit:
+ DnDMsg_Destroy(&msg);
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dnd.cc --
+ *
+ * Implementation of common layer DnD object.
+ */
+
+#include "dnd.hh"
+#include "dndRpcV3.hh"
+
+extern "C" {
+ #include "util.h"
+ #include "debug.h"
+ #include "file.h"
+ #include "cpNameUtil.h"
+ #include "str.h"
+ #include "eventManager.h"
+}
+
+#define UNGRAB_TIMEOUT 50 // 0.5 s
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * DnDUngrabTimeout --
+ *
+ * UngrabTimeout callback for GH DnD.
+ *
+ * Results:
+ * Always TRUE.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------
+ */
+
+static Bool
+DnDUngrabTimeout(void *clientData) // IN
+{
+ ASSERT(clientData);
+ DnD *dnd = (DnD *)clientData;
+ dnd->UngrabTimeout();
+ return TRUE;
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * DnD::DnD --
+ *
+ * Constructor for DnD.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------
+ */
+
+DnD::DnD(DblLnkLst_Links *eventQueue) // IN
+ : mRpc(NULL),
+ mVmxDnDVersion(0),
+ mDnDAllowed(false),
+ mStagingDir(""),
+ mUngrabTimeout(NULL),
+ mEventQueue(eventQueue)
+{
+ mState = DNDSTATE_INVALID;
+ mFeedback = DROP_UNKNOWN;
+ CPClipboard_Init(&mClipboard);
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * DnD::~DnD --
+ *
+ * Destructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------
+ */
+
+DnD::~DnD(void)
+{
+ delete mRpc;
+ CPClipboard_Destroy(&mClipboard);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnD::VmxDnDVersionChanged --
+ *
+ * Guest DnD version changed so should create corresponding Rpc and
+ * register callbacks for signals if version changed.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+DnD::VmxDnDVersionChanged(struct RpcIn *rpcIn, // IN
+ uint32 version) // IN
+{
+ /* Do nothing if version is not changed. */
+ if (mVmxDnDVersion == version) {
+ return;
+ }
+
+ mVmxDnDVersion = version;
+
+ delete mRpc;
+ mRpc = NULL;
+ mState = DNDSTATE_INVALID;
+ Debug("%s: state changed to INVALID\n", __FUNCTION__);
+
+ switch (version) {
+ case 1:
+ case 2:
+ /* Here should create DnDRpcV2 for version 1 & 2. */
+ break;
+ case 3:
+ mRpc = new DnDRpcV3(rpcIn);
+ break;
+ default:
+ Debug("%s: got unsupported vmx DnD version %u.\n", __FUNCTION__, version);
+ return;
+ }
+
+ if (mRpc) {
+ mRpc->ghUpdateUnityDetWndChanged.connect(
+ sigc::mem_fun(this, &DnD::OnGHUpdateUnityDetWnd));
+ mRpc->ghQueryPendingDragChanged.connect(
+ sigc::mem_fun(this, &DnD::OnGHQueryPendingDrag));
+ mRpc->ghCancelChanged.connect(
+ sigc::mem_fun(this, &DnD::OnGHCancel));
+ mRpc->hgDragEnterChanged.connect(
+ sigc::mem_fun(this, &DnD::OnHGDragEnter));
+ mRpc->hgDragStartChanged.connect(
+ sigc::mem_fun(this, &DnD::OnHGDragStart));
+ mRpc->hgCancelChanged.connect(
+ sigc::mem_fun(this, &DnD::OnHGCancel));
+ mRpc->hgDropChanged.connect(
+ sigc::mem_fun(this, &DnD::OnHGDrop));
+ mRpc->hgFileCopyDoneChanged.connect(
+ sigc::mem_fun(this, &DnD::OnHGFileCopyDone));
+ mState = DNDSTATE_READY;
+ Debug("%s: state changed to READY\n", __FUNCTION__);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::OnHGDragEnter --
+ *
+ * This callback is trigged when host got dragEnter signal and
+ * related DnD data. Put data into local buffer, show detection
+ * window and inform host UI to simulate first mouse click in the
+ * guest.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::OnHGDragEnter(const CPClipboard *clip) // IN
+{
+ if (mState != DNDSTATE_READY &&
+ mState != DNDSTATE_ENTERING) {
+ /* Reset DnD for any wrong state. */
+ Debug("%s: Bad state: %d\n", __FUNCTION__, mState);
+ ResetDnD();
+ return;
+ }
+
+ CPClipboard_Clear(&mClipboard);
+ CPClipboard_Copy(&mClipboard, clip);
+
+ /* Show detection window in (0, 0). */
+ updateDetWndChanged.emit(true, 0, 0);
+
+ /*
+ * Ask host to simulate mouse click inside the detection window.
+ * Host should simulate all guest dragging for HG DnD.
+ */
+ mRpc->HGDragEnterDone(DRAG_DET_WINDOW_WIDTH / 2,
+ DRAG_DET_WINDOW_WIDTH / 2);
+ mState = DNDSTATE_ENTERING;
+ Debug("%s: state changed to ENTERING\n", __FUNCTION__);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::OnHGDragStart --
+ *
+ * Host just simulated the first mouse click inside the detection
+ * window. Now guest can initialize HG DnD.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::OnHGDragStart(void) // IN
+{
+ if (mState != DNDSTATE_ENTERING) {
+ /* Reset DnD for any wrong state. */
+ Debug("%s: Bad state: %d\n", __FUNCTION__, mState);
+ ResetDnD();
+ return;
+ }
+
+ /* Setup staging directory. */
+ mStagingDir = SetupDestDir("");
+ if (mStagingDir.empty()) {
+ return;
+ }
+
+ dragStartChanged.emit(&mClipboard, mStagingDir);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::HGDragStartDone --
+ *
+ * Tell host we are done with DnD initialization.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::HGDragStartDone(void)
+{
+ if (mState != DNDSTATE_ENTERING) {
+ /* Reset DnD for any wrong state. */
+ Debug("%s: Bad state: %d\n", __FUNCTION__, mState);
+ ResetDnD();
+ return;
+ }
+
+ mRpc->HGDragStartDone();
+ mState = DNDSTATE_DRAGGING_INSIDE;
+ Debug("%s: state changed to DRAGGING\n", __FUNCTION__);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::SetFeedback --
+ *
+ * Got feedback from local UI. Notify host to update. For HG DnD.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::SetFeedback(DND_DROPEFFECT effect) // IN
+{
+ if (mState == DNDSTATE_INVALID) {
+ /* Wrong state. */
+ Debug("%s: Bad state: %d\n", __FUNCTION__, mState);
+ return;
+ }
+
+ ASSERT(mRpc);
+ Debug("%s: feedback is %d\n", __FUNCTION__, effect);
+ mRpc->HGUpdateFeedback(effect);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::OnHGCancel --
+ *
+ * Host just cancelled the HG DnD.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::OnHGCancel(void)
+{
+ sourceCancelChanged.emit();
+ /* Hide detection window. */
+ updateDetWndChanged.emit(false, 0, 0);
+ mState = DNDSTATE_READY;
+ Debug("%s: state changed to READY\n", __FUNCTION__);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::OnHGDrop --
+ *
+ * Host just drop the data but not copy file yet. Provide staging
+ * directory and add block.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::OnHGDrop(void)
+{
+ char cpName[FILE_MAXPATH];
+ int32 cpNameSize;
+
+ if (mState != DNDSTATE_DRAGGING_INSIDE) {
+ /* Reset DnD for any wrong state. */
+ Debug("%s: Bad state: %d\n", __FUNCTION__, mState);
+ ResetDnD();
+ return;
+ }
+
+ if (CPClipboard_ItemExists(&mClipboard, CPFORMAT_FILELIST)) {
+ /* Convert staging name to CP format. */
+ cpNameSize = CPNameUtil_ConvertToRoot(mStagingDir.c_str(),
+ sizeof cpName,
+ cpName);
+ if (cpNameSize < 0) {
+ Debug("%s: Error, could not convert to CPName.\n", __FUNCTION__);
+ return;
+ }
+
+ mRpc->HGDropDone(cpName, cpNameSize);
+ sourceDropChanged.emit();
+ } else {
+ /* For non-file formats, the DnD is done. Hide detection window. */
+ updateDetWndChanged.emit(false, 0, 0);
+ }
+ mState = DNDSTATE_READY;
+ Debug("%s: state changed to READY\n", __FUNCTION__);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::OnHGFileCopyDone --
+ *
+ * Host just finished file copy for HG DnD. Remove the block from
+ * staging directory.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::OnHGFileCopyDone(bool success, // IN
+ std::vector<uint8> stagingDir) // IN
+{
+ if (!success && !mStagingDir.empty()) {
+ /* Delete all files if host canceled the file transfer. */
+ DnD_DeleteStagingFiles(mStagingDir.c_str(), FALSE);
+ mStagingDir.clear();
+ }
+ fileCopyDoneChanged.emit(success, stagingDir);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnD::SetupDestDir --
+ *
+ * Creates a directory for file transfer. If the destination
+ * dir is provided, we will attempt to copy files to the directory.
+ *
+ * Input directory will be in local format.
+ *
+ * Results:
+ * The destination directory on success, an empty string on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+std::string
+DnD::SetupDestDir(const std::string &destDir) // IN
+{
+ static const std::string failDir = "";
+
+ if (!destDir.empty() && File_Exists(destDir.c_str())) {
+ mStagingDir = destDir;
+ const char *lastSep = Str_Strrchr(mStagingDir.c_str(), DIRSEPC);
+ if (lastSep && lastSep[1] != '\0') {
+ mStagingDir += DIRSEPS;
+ }
+
+ return mStagingDir;
+ } else {
+ char *newDir;
+
+ newDir = DnD_CreateStagingDirectory();
+ if (newDir != NULL) {
+ mStagingDir = newDir;
+
+ char *lastSep = Str_Strrchr(newDir, DIRSEPC);
+ if (lastSep && lastSep[1] != '\0') {
+ mStagingDir += DIRSEPS;
+ }
+ free(newDir);
+ Debug("%s: destdir: %s", __FUNCTION__, mStagingDir.c_str());
+
+ return mStagingDir;
+ } else {
+ Debug("%s: destdir not created", __FUNCTION__);
+ return failDir;
+ }
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::OnGHUpdateUnityDetWnd --
+ *
+ * This callback is trigged when users clicks into any Unity window
+ * or just release the mouse button. Either show the full-screen
+ * detection window right after the Unity window, or hide the
+ * detection window.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::OnGHUpdateUnityDetWnd(bool bShow, // IN
+ uint32 unityWndId) // IN
+{
+ if (bShow && mState != DNDSTATE_READY) {
+ /*
+ * Reset DnD for any wrong state. Only do this when host asked to
+ * show the window.
+ */
+ Debug("%s: Bad state: %d\n", __FUNCTION__, mState);
+ ResetDnD();
+ return;
+ }
+
+ if (bShow) {
+ /*
+ * When show full screen window, also show the small top-most
+ * window in (1, 1). After detected a GH DnD, the full screen
+ * window will be hidden to avoid blocking other windows. So use
+ * this window to accept drop in cancel case.
+ */
+ updateDetWndChanged.emit(bShow, 1, 1);
+ }
+
+ /* Show/hide the full screent detection window. */
+ updateUnityDetWndChanged.emit(bShow, unityWndId);
+ Debug("%s: updating Unity detection window, bShow %d, id %u\n",
+ __FUNCTION__, bShow, unityWndId);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::OnGHQueryPendingDrag --
+ *
+ * This callback is trigged when host got initial GH DnD signal.
+ * UI will check if there is any pending GH dragging.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::OnGHQueryPendingDrag(int32 x, // IN
+ int32 y) // IN
+{
+ if (mState != DNDSTATE_READY) {
+ /* Reset DnD for any wrong state. */
+ Debug("%s: Bad state: %d\n", __FUNCTION__, mState);
+ ResetDnD();
+ return;
+ }
+
+ /* Show detection window to detect pending GH DnD. */
+ updateDetWndChanged.emit(true, x, y);
+ mState = DNDSTATE_QUERY_EXITING;
+ Debug("%s: state changed to QUERY_EXITING\n", __FUNCTION__);
+
+ /*
+ * Add event to fire and hide our window if a DnD is not pending. Note that
+ * this is here in case the drag isn't picked up by our drag detection window
+ * for some reason.
+ */
+ if (NULL == mUngrabTimeout) {
+ mUngrabTimeout = EventManager_Add(mEventQueue, UNGRAB_TIMEOUT,
+ DnDUngrabTimeout, this);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::UngrabTimeout --
+ *
+ * Can not detect pending GH DnD within UNGRAB_TIMEOUT, cancel it.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::UngrabTimeout(void)
+{
+ if (mState != DNDSTATE_QUERY_EXITING) {
+ /* Reset DnD for any wrong state. */
+ Debug("%s: Bad state: %d\n", __FUNCTION__, mState);
+ ResetDnD();
+ return;
+ }
+
+ ASSERT(mRpc);
+ mRpc->GHUngrabTimeout();
+
+ mUngrabTimeout = NULL;
+ OnGHCancel();
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::DragEnter --
+ *
+ * This is reponse to OnGHQueryPendingDrag if there is a pending
+ * GH dragging.
+ *
+ * If guest can not detect any pending GH dragging, UngrabTimeout
+ * will notify host to cancel GH DnD.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::DragEnter(const CPClipboard *clip)
+{
+ /*
+ * In Unity mode, there is no QueryPendingDrag signal, so may get called
+ * with state READY.
+ */
+ if (mState != DNDSTATE_QUERY_EXITING && mState != DNDSTATE_READY) {
+ /* Reset DnD for any wrong state. */
+ Debug("%s: Bad state: %d\n", __FUNCTION__, mState);
+ ResetDnD();
+ return;
+ }
+
+ /* Remove untriggered ungrab timer. */
+ if (mUngrabTimeout) {
+ EventManager_Remove(mUngrabTimeout);
+ mUngrabTimeout = NULL;
+ }
+
+ ASSERT(mRpc);
+ mRpc->GHDragEnter(clip);
+ mState = DNDSTATE_DRAGGING_OUTSIDE;
+ Debug("%s: state changed to DRAGGING_OUTSIDE\n", __FUNCTION__);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::OnGHCancel --
+ *
+ * Host cancelled current GH DnD.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::OnGHCancel(void)
+{
+ /* Hide detection window. */
+ updateDetWndChanged.emit(false, 0, 0);
+ /* Remove the timer. */
+ if (mUngrabTimeout) {
+ EventManager_Remove(mUngrabTimeout);
+ mUngrabTimeout = NULL;
+ }
+ mState = DNDSTATE_READY;
+ Debug("%s: state changed to READY\n", __FUNCTION__);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnD::ResetDnD --
+ *
+ * Cancel both HG and GH DnD.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DnD::ResetDnD(void)
+{
+ OnHGCancel();
+ OnGHCancel();
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dndFileList.cc
+ *
+ * Handles filelists for CPClipboard.
+ * Relative paths are read/write to allow placing data on the clipboard,
+ * but full paths are write only. Full path parsing depends on g->h/h->g
+ * as well as dnd/fcp versions. Given that the host ui never needs to
+ * parse it, full paths are only stored in binary format for consumption
+ * by the vmx.
+ *
+ * Local relative paths are expected to be encoded in Normalized UTF8 in
+ * local format.
+ *
+ * XXX This file is almost identical to bora/apps/lib/cui/dndFileList.cc
+ * but right now we can not find a way to share the file.
+ */
+
+#include "dndFileList.hh"
+
+extern "C" {
+ #include "dndClipboard.h"
+ #include "vm_assert.h"
+ #include "file.h"
+ #include "cpNameUtil.h"
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList --
+ *
+ * Constructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+DnDFileList::DnDFileList()
+{
+ mFileSize = 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::SetFileSize --
+ *
+ * Sets the expected size of the files.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnDFileList::SetFileSize(uint64 fsize) // IN: The size of the files.
+{
+ mFileSize = fsize;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::GetFileSize --
+ *
+ * Gets the size of the files if known.
+ *
+ * Results:
+ * 0 if the size of the files is not known, otherwise the expected size of
+ * the files.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+uint64
+DnDFileList::GetFileSize() const
+{
+ return mFileSize;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::AddFile --
+ *
+ * Add the full path and the relative path to the file list. Both strings
+ * should be normalized UTF8.
+ * Will not add file if the file list was created from a clipboard buffer.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnDFileList::AddFile(const std::string fullPath, // IN: filename
+ const std::string relPath) // IN: filename
+{
+ ASSERT(mFullPathsBinary.empty());
+
+ if (!mFullPathsBinary.empty()) {
+ return;
+ }
+
+ mRelPaths.push_back(relPath);
+ mFullPaths.push_back(fullPath);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::AddFileUri --
+ *
+ * Add the full uri UTF8 path the file list.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnDFileList::AddFileUri(const std::string uriPath) // IN
+{
+ mUriPaths.push_back(uriPath);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::AddFiles --
+ *
+ * Add the full path list and the relative path list. Both lists should be
+ * normalized UTF8.
+ *
+ * Will not add lists if the file list was created from a clipboard buffer.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnDFileList::AddFiles(const std::vector<std::string> fullPathList, // IN: filenames
+ const std::vector<std::string> relPathList) // IN: filenames
+{
+ ASSERT(mFullPathsBinary.empty());
+
+ if (!mFullPathsBinary.empty()) {
+ return;
+ }
+
+ mRelPaths = relPathList;
+ mFullPaths = fullPathList;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::SetRelPathsStr --
+ *
+ * Set the relative paths based on the serialized input string. Paths are
+ * in normalized utf-8 with local path separators. Exposed for dnd/cp
+ * version 2.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnDFileList::SetRelPathsStr(const std::string inpath) // IN:
+{
+ std::string::size_type mPos = 0;
+ std::string curFile;
+ std::string path;
+ const char* cpath;
+
+ if (inpath.empty()) {
+ return;
+ }
+
+ if (inpath[inpath.size()-1] != '\0') {
+ path = inpath + '\0';
+ } else {
+ path = inpath;
+ }
+
+ cpath = path.c_str();
+ mRelPaths.clear();
+ curFile = cpath;
+ mPos = path.find('\0', mPos);
+
+ while (mPos != std::string::npos) {
+ mPos++;
+ mRelPaths.push_back(curFile);
+ curFile = cpath + mPos;
+ mPos = path.find('\0', mPos);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::GetRelPaths --
+ *
+ * Gets a vector containing the reletive paths of the files.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+std::vector<std::string>
+DnDFileList::GetRelPaths() const
+{
+ return mRelPaths;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::GetFullPathsStr --
+ *
+ * Gets the serialized version of the full paths. If the file list was
+ * created from a CPClipboard, use the serialized input instead.
+ *
+ * Local paths are serialized inot NUL separated pathes.
+ * CPName paths are converted from local to CPName and serialized into
+ * uint32,cpname pairs.
+ *
+ * Results:
+ * An std::string containing the serialized full paths. Empty string on
+ * error.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+std::string
+DnDFileList::GetFullPathsStr(bool local) // IN: Use local format
+ const
+{
+ std::string stringList;
+ std::vector<std::string>::const_iterator i;
+
+ if (mFullPathsBinary.empty() && !mFullPaths.empty()) {
+ for (i = mFullPaths.begin(); i != mFullPaths.end(); ++i) {
+ if (local) {
+ stringList.append(i->c_str());
+ stringList.push_back('\0');
+ } else {
+ char outPath[FILE_MAXPATH + 100];
+ int32 outPathLen;
+
+ outPathLen = CPNameUtil_ConvertToRoot(i->c_str(),
+ sizeof outPath,
+ outPath);
+ if (outPathLen < 0) {
+ continue;
+ }
+
+ stringList.append(reinterpret_cast<char *>(&outPathLen),
+ sizeof outPathLen);
+ stringList.append(outPath, outPathLen);
+ }
+ }
+
+ return stringList;
+ } else if (!mFullPathsBinary.empty() && mFullPaths.empty()) {
+ return mFullPathsBinary;
+ } else {
+ return "";
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::GetRelPathsStr --
+ *
+ * Gets the serialized version of the relative paths. Primarily used for
+ * dnd/cp v2.
+ *
+ * Results:
+ * An std::string contatin the serialized full paths.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+std::string
+DnDFileList::GetRelPathsStr()
+ const
+{
+ std::string stringList;
+ std::vector<std::string>::const_iterator i;
+
+ for (i = mRelPaths.begin(); i != mRelPaths.end(); ++i) {
+ stringList.append(i->c_str());
+ stringList.push_back('\0');
+ }
+ return stringList;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::GetUriPathsStr --
+ *
+ * Gets the serialized version of the uri paths.
+ *
+ * Results:
+ * An std::string contatin the serialized uri paths.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+std::string
+DnDFileList::GetUriPathsStr(void)
+ const
+{
+ std::string stringList;
+ std::vector<std::string>::const_iterator i;
+
+ for (i = mUriPaths.begin(); i != mUriPaths.end(); i++) {
+ stringList.append(i->c_str());
+ stringList.push_back('\0');
+ }
+ return stringList;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::FromCPClipboard --
+ *
+ * Loads the filelist from a buffer, typically from CPClipboard.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+bool
+DnDFileList::FromCPClipboard(const void *buf, // IN: Source buffer
+ size_t len) // IN: Buffer length
+{
+ const CPFileList *flist;
+ std::string relPaths;
+
+ ASSERT(buf);
+ ASSERT(len);
+ if (!buf || !len) {
+ return false;
+ }
+
+ flist = reinterpret_cast<const CPFileList *>(buf);
+ relPaths.assign(
+ reinterpret_cast<const char *>(flist->filelists), flist->relPathsLen);
+
+ mRelPaths.clear();
+ mFullPaths.clear();
+
+ mFileSize = flist->fileSize;
+
+ SetRelPathsStr(relPaths);
+ mFullPathsBinary.assign(
+ reinterpret_cast<const char *>(flist->filelists + flist->relPathsLen),
+ flist->fulPathsLen);
+
+ return true;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::ToCPClipboard --
+ *
+ * Serializes contents for CPClipboard in eithr CPFormat or local format.
+ *
+ * Results:
+ * false on error, true on success.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+bool
+DnDFileList::ToCPClipboard(DynBuf *out, // OUT: Initialized output buffer
+ bool local) // IN: Use local format
+ const
+{
+ std::string strListRel;
+ std::string strListFul;
+ CPFileList header;
+
+ strListRel = GetRelPathsStr();
+ strListFul = GetFullPathsStr(local);
+
+ if (!out) {
+ return false;
+ }
+
+ /* Check if the size is too big. */
+ if (strListRel.size() > MAX_UINT32 ||
+ strListFul.size() > MAX_UINT32) {
+ return false;
+ }
+
+ header.fileSize = mFileSize;
+ header.relPathsLen = strListRel.size();
+ header.fulPathsLen = strListFul.size();
+
+ DynBuf_Append(out, &header, CPFILELIST_HEADER_SIZE);
+ DynBuf_Append(out, strListRel.c_str(), header.relPathsLen);
+ DynBuf_Append(out, strListFul.c_str(), header.fulPathsLen);
+
+ return true;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::ToCPClipboard --
+ *
+ * Serializes uri paths for CPClipboard in URI Format.
+ *
+ * Results:
+ * false on error, true on success.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+bool
+DnDFileList::ToUriClipboard(DynBuf *out) // OUT: Initialized output buffer
+ const
+{
+ std::string strListUri;
+ UriFileList header;
+
+ if (!out) {
+ return false;
+ }
+
+ strListUri = GetUriPathsStr();
+
+ /* Check if the size is too big. */
+ if (strListUri.size() > MAX_UINT32) {
+ return false;
+ }
+
+ header.fileSize = mFileSize;
+ header.uriPathsLen = strListUri.size();
+
+ DynBuf_Append(out, &header, URI_FILELIST_HEADER_SIZE);
+ DynBuf_Append(out, strListUri.c_str(), header.uriPathsLen);
+
+ return true;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFileList::Clear --
+ *
+ * Clears the contents of the filelist.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnDFileList::Clear()
+{
+ mRelPaths.clear();
+ mFullPaths.clear();
+ mUriPaths.clear();
+ mFullPathsBinary.clear();
+ mFileSize = 0;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dndTransportGuestRpc.cc --
+ *
+ * GuestRpc implementation of the dndTransport interface.
+ *
+ * A multiple packet transport protocol is implemented in this layer to
+ * support big buffer transfer. With the support, message size limit is
+ * improved from 64K to 4M (theoratically can be 4G).
+ *
+ * There are 3 different types of packet. If a message is smaller than
+ * 64K, it will be sent with type DND_TRANSPORT_PACKET_TYPE_SINGLE. If
+ * it is bigger than 64K, initial 64K will be first sent with
+ * DND_TRANSPORT_PACKET_TYPE_PAYLOAD. After received the packet, the
+ * receiver should reply with DND_TRANSPORT_PACKET_TYPE_REQUEST, then
+ * next 64K will be sent.
+ *
+ * This is a temporary solution before VICF is available. To simplify
+ * the implementation, there are some limitations:
+ * 1. Any time for any transport class, there is only one pending
+ * big buffer for each direction. Any following big size message will
+ * be dropped before the pending transfer is done.Small message (<64K)
+ * can be sent at any time.
+ * 2. Caller can not cancel any pending big buffer sending and
+ * receiving.
+ * 3. Pending big buffer will be dropped if there is any error.
+ */
+
+
+#include <sigc++/hide.h>
+
+#include "dndTransportGuestRpc.hh"
+
+extern "C" {
+ #include "util.h"
+ #include "rpcout.h"
+ #include "rpcin.h"
+ #include "debug.h"
+ #include "str.h"
+ #include "hostinfo.h"
+ #include "dndMsg.h"
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * RecvMsgCB --
+ *
+ * Reads msg from VMX.
+ *
+ * Results:
+ * TRUE if success, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+RecvMsgCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // IN: Size of args
+ void *clientData) // IN
+{
+ DnDTransportGuestRpc *transport = (DnDTransportGuestRpc *)clientData;
+ ASSERT(transport);
+
+ /* '- 1' is to ignore empty space between command and args. */
+ if ((argsSize - 1) <= 0) {
+ Debug("%s: invalid argsSize\n", __FUNCTION__);
+ return RpcIn_SetRetVals(result, resultLen, "invalid arg size", FALSE);
+ }
+ transport->RecvMsg((DnDTransportPacketHeader *)(args + 1), argsSize - 1);
+ return RpcIn_SetRetVals(result, resultLen, "", TRUE);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDTransportGuestRpc::DnDTransportGuestRpc --
+ *
+ * Constructor of DnDTransportGuestRpc class.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+DnDTransportGuestRpc::DnDTransportGuestRpc(struct RpcIn *rpcIn, // IN
+ const char *rpcCmd) // IN
+ : mRpcIn(rpcIn)
+{
+ ASSERT(rpcIn);
+ ASSERT(rpcCmd);
+
+ RpcIn_RegisterCallback(rpcIn, rpcCmd, RecvMsgCB, this);
+ mRpcCmd = Util_SafeStrdup(rpcCmd);
+
+ mSendBuf.buffer = NULL;
+ mRecvBuf.buffer = NULL;
+ DnD_TransportBufReset(&mSendBuf);
+ DnD_TransportBufReset(&mRecvBuf);
+ mSeqNum= 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DnDTransportGuestRpc::~DnDTransportGuestRpc --
+ *
+ * Destructor of DnDTransportGuestRpc.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+DnDTransportGuestRpc::~DnDTransportGuestRpc(void)
+{
+ RpcIn_UnregisterCallback(mRpcIn, mRpcCmd);
+ free(mRpcCmd);
+ free(mSendBuf.buffer);
+ free(mRecvBuf.buffer);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDTransportGuestRpc::SendMsg --
+ *
+ * Sends msg to the VMX.
+ *
+ * Results:
+ * TRUE if success, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+DnDTransportGuestRpc::SendMsg(uint8 *msg, // IN
+ size_t length) // IN
+{
+ DnDTransportPacketHeader *packet = NULL;
+ size_t packetSize;
+ bool ret = FALSE;
+
+ if (length > DNDMSG_MAX_ARGSZ) {
+ Debug("%s: message is too big, quit.\n", __FUNCTION__);
+ return FALSE;
+ }
+
+ Debug("%s: got message, size %"FMTSZ"u\n", __FUNCTION__, length);
+
+ if (length <= DND_MAX_TRANSPORT_PACKET_PAYLOAD_SIZE) {
+ /*
+ * It is a small size message, so it is not needed to buffer it in the transport
+ * layer. Just put message into a packet and send it.
+ */
+ packetSize = DnD_TransportMsgToPacket(msg, length, mSeqNum, &packet);
+ } else {
+ /*
+ * It is a big size message. First buffer it in the transport layer and send
+ * it with multiple packets.
+ */
+ if (mSendBuf.buffer) {
+ /*
+ * There is a pending big size message. If there is no update time more than
+ * DND_MAX_TRANSPORT_LATENCY_TIME, remove old message and send new message.
+ * Otherwise ignore this message.
+ *
+ * XXX This transport implementation is just a temporary solution before VICF
+ * is available. So any time there is only one pending big buffer. Any other
+ * big message during this time will be dropped. Current pending buffer will
+ * also be dropped if there is any error. Later on VICF should provide a
+ * better transportation.
+ */
+ VmTimeType curTime;
+
+ Hostinfo_GetTimeOfDay(&curTime);
+
+ if ((curTime - mSendBuf.lastUpdateTime) < DND_MAX_TRANSPORT_LATENCY_TIME) {
+ Debug("%s: got a big buffer, but there is already a pending one, quitting\n",
+ __FUNCTION__);
+ return FALSE;
+ }
+ }
+ DnD_TransportBufInit(&mSendBuf, msg, length, mSeqNum);
+ packetSize = DnD_TransportBufGetPacket(&mSendBuf, &packet);
+ }
+
+ mSeqNum++;
+ if (packetSize) {
+ ret = SendPacket((uint8 *)packet, packetSize);
+ }
+ free(packet);
+ return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDTransportGuestRpc::SendPacket --
+ *
+ * Sends packet to the VMX.
+ *
+ * Results:
+ * TRUE if success, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+DnDTransportGuestRpc::SendPacket(uint8 *packet, // IN
+ size_t packetSize) // IN
+{
+ char *rpc = NULL;
+ size_t rpcSize = 0;
+ size_t nrWritten = 0;
+ bool ret = FALSE;
+
+ if (packetSize == 0 || packetSize > DND_MAX_TRANSPORT_PACKET_SIZE) {
+ Debug("%s: invalid packet\n", __FUNCTION__);
+ return FALSE;
+ }
+
+ rpcSize = strlen(mRpcCmd) + 1 + packetSize;
+ rpc = (char *)Util_SafeMalloc(rpcSize);
+ nrWritten = Str_Sprintf(rpc, rpcSize, "%s ", mRpcCmd);
+ ASSERT(nrWritten + packetSize <= rpcSize);
+ memcpy(rpc + nrWritten, packet, packetSize);
+
+ ret = (TRUE == RpcOut_SendOneRaw(rpc, rpcSize, NULL, NULL));
+
+ if (!ret) {
+ Debug("%s: failed to send msg to host\n", __FUNCTION__);
+ }
+
+ free(rpc);
+ return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDTransportGuestRpc::RecvMsg --
+ *
+ * Receives packet from VMX.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+DnDTransportGuestRpc::RecvMsg(DnDTransportPacketHeader *packet, // IN
+ size_t packetSize) // IN
+{
+ if (packetSize <= 0 ||
+ packetSize != (packet->payloadSize + DND_TRANSPORT_PACKET_HEADER_SIZE) ||
+ packetSize > DND_MAX_TRANSPORT_PACKET_SIZE) {
+ Debug("%s: Received invalid data.\n", __FUNCTION__);
+ return;
+ }
+
+ Debug("%s: received data, size %"FMTSZ"u.\n", __FUNCTION__, packetSize);
+
+ switch (packet->type) {
+ case DND_TRANSPORT_PACKET_TYPE_SINGLE:
+ if (packet->payloadSize != packet->totalSize) {
+ Debug("%s: received invalid packet.\n", __FUNCTION__);
+ return;
+ }
+ recvMsgChanged.emit(packet->payload,
+ packet->payloadSize);
+ break;
+ case DND_TRANSPORT_PACKET_TYPE_REQUEST:
+ {
+ DnDTransportPacketHeader *replyPacket = NULL;
+ size_t replyPacketSize;
+
+ /* Validate received packet. */
+ if (packet->payloadSize ||
+ packet->seqNum != mSendBuf.seqNum ||
+ packet->offset != mSendBuf.offset) {
+ Debug("%s: received packet does not match local buffer.\n", __FUNCTION__);
+ return;
+ }
+
+ replyPacketSize = DnD_TransportBufGetPacket(&mSendBuf, &replyPacket);
+
+ if (!replyPacketSize) {
+ /*
+ * Not needed to reset mSendBuf because DnD_TransportBufGetPacket already
+ * did that.
+ */
+ Debug("%s: DnD_TransportBufGetPacket failed.\n", __FUNCTION__);
+ return;
+ }
+
+ if (!SendPacket((uint8 *)replyPacket, replyPacketSize) ||
+ mSendBuf.offset == mSendBuf.totalSize) {
+ /* Reset mSendBuf if whole buffer is sent or there is any error. */
+ DnD_TransportBufReset(&mSendBuf);
+ }
+
+ free(replyPacket);
+
+ break;
+ }
+ case DND_TRANSPORT_PACKET_TYPE_PAYLOAD:
+ if (!DnD_TransportBufAppendPacket(&mRecvBuf, packet, packetSize)) {
+ Debug("%s: DnD_TransportBufAppendPacket failed.\n", __FUNCTION__);
+ return;
+ }
+
+ if (mRecvBuf.offset == mRecvBuf.totalSize) {
+ /* Received all packets for the messge. */
+ recvMsgChanged.emit(mRecvBuf.buffer, mRecvBuf.totalSize);
+ DnD_TransportBufReset(&mRecvBuf);
+ } else {
+ /* Send request for next packet. */
+ DnDTransportPacketHeader *replyPacket = NULL;
+ size_t replyPacketSize;
+
+ replyPacketSize = DnD_TransportReqPacket(&mRecvBuf, &replyPacket);
+
+ if (!replyPacketSize) {
+ Debug("%s: DnD_TransportReqPacket failed.\n", __FUNCTION__);
+ return;
+ }
+
+ if (!SendPacket((uint8 *)replyPacket, replyPacketSize)) {
+ DnD_TransportBufReset(&mRecvBuf);
+ }
+ free(replyPacket);
+ }
+ break;
+ default:
+ Debug("%s: unknown packet.\n", __FUNCTION__);
+ break;
+ }
+}
# define DYNXDR_SIZE_T u_int
#endif
+/*
+ * Mac OS 64-bit defines the parameter to "x_putlong" as an int.
+ */
+#if defined __APPLE__ && defined __LP64__
+# define DYNXDR_LONG int
+#else
+# define DYNXDR_LONG long
+#endif
+
/*
*-----------------------------------------------------------------------------
*/
static bool_t
-DynXdrPutLong(XDR *xdrs, // IN/OUT
- DYNXDR_CONST long *lp) // IN
+DynXdrPutLong(XDR *xdrs, // IN/OUT
+ DYNXDR_CONST DYNXDR_LONG *lp) // IN
{
- int32 out = htonl((int32)*lp);
+ int32 out;
DynXdrData *priv = (DynXdrData *) xdrs->x_private;
+
+#ifdef __APPLE__
+ ASSERT_ON_COMPILE(sizeof *lp <= sizeof (int32));
+#endif
+ out = htonl((int32)*lp);
return DynBuf_Append(&priv->data, &out, sizeof out);
}
#include "su.h"
#if defined(__APPLE__)
-#include <sys/socket.h>
+#include "sysSocket.h" // Don't move this: it fixes a system header.
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
* Close a file
*
* Results:
- * On success: 0
- * On failure: non-zero
+ * TRUE: an error occured
+ * FALSE: no error occured
*
* Side effects:
* None
*----------------------------------------------------------------------
*/
-int
+Bool
FileIO_Close(FileIODescriptor *file) // IN
{
- int retval;
+ int err;
ASSERT(file);
- retval = close(file->posix);
+ err = (close(file->posix) == -1) ? errno : 0;
FileIO_StatsExit(file);
FileIO_Cleanup(file);
FileIO_Invalidate(file);
- return retval;
+ if (err) {
+ errno = err;
+ }
+
+ return err != 0;
}
#if !defined(_WIN32)
mode_t save;
- ASSERT(pathName);
-
save = umask(0);
-#else
- ASSERT(pathName);
#endif
+ ASSERT(pathName);
+
err = FileCreateDirectoryRobust(pathName);
#if !defined(_WIN32)
if (fileData.fileType == FILE_TYPE_REGULAR) {
/*
- * It's a file. Assume this is an (active?) old style lock
- * and err on the safe side - don't remove it (and
- * automatically upgrade to a new style lock).
+ * It's a file. Assume this is an (active?) old style lock and
+ * err on the safe side - don't remove it (and automatically
+ * upgrade to a new style lock).
*/
Log(LGPFX" %s: '%s' exists; an old style lock file?\n",
* Returns a string which uniquely identifies the underlying filesystem
* for a given path.
*
- * 'path' can be relative (including empty) or absolute, and any number of
- * non-existing components at the end of 'path' are simply ignored.
+ * 'path' can be relative (including empty) or absolute, and any number
+ * of non-existing components at the end of 'path' are simply ignored.
*
* XXX: On Posix systems, we choose the underlying device's name as the
- * unique ID. I make no claim that this is 100% unique so if you need
- * this functionality to be 100% perfect, I suggest you think about
- * it more deeply than I did. -meccleston
+ * unique ID. I make no claim that this is 100% unique so if you
+ * need this functionality to be 100% perfect, I suggest you think
+ * about it more deeply than I did. -meccleston
*
* Results:
* On success: Allocated and NUL-terminated filesystem ID.
* We acquire the full path name for testing in
* FilePosixCreateTestFileSize(). This is also done in the event that
* a user tries to create a virtual disk in the directory that they want
- * a vmdk created in (setting filePath only to the disk name, not the entire
- * path.
+ * a vmdk created in (setting filePath only to the disk name, not the
+ * entire path.
*/
fullPath = File_FullPath(pathName);
}
/*
- * This function expects a filename. If given one, truncate the name to point
- * to the parent directory so we can get accurate results from FileIsVMFS.
- * If handed a directory directly, no truncation is necessary.
+ * This function expects a filename. If given one, truncate the name to
+ * point to the parent directory so we can get accurate results from
+ * FileIsVMFS. If handed a directory directly, no truncation is necessary.
*/
if (File_IsDirectory(pathName)) {
*
* File_GetSizeAlternate --
*
- * An alternate way to determine the filesize. Useful for finding problems
- * with files on remote fileservers, such as described in bug 19036.
- * However, in Linux we do not have an alternate way, yet, to determine the
- * problem, so we call back into the regular getSize function.
+ * An alternate way to determine the filesize. Useful for finding
+ * problems with files on remote fileservers, such as described in bug
+ * 19036. However, in Linux we do not have an alternate way, yet, to
+ * determine the problem, so we call back into the regular getSize
+ * function.
*
* Results:
* Size of file or -1.
VixCommandResponseHeader *responseHeader;
size_t totalMessageSize;
- ASSERT(responseBodyLength >= 0);
ASSERT((NULL != responseBody) || (0 == responseBodyLength));
/*
size_t responseBodyLength;
ASSERT(NULL != responseHeader);
+ ASSERT(totalMessageSize >= sizeof(VixCommandResponseHeader));
responseBodyLength = totalMessageSize - sizeof(VixCommandResponseHeader);
- ASSERT(responseBodyLength >= 0);
/*
* Fill in the response header.
abort:
if (VIX_OK != err) {
free(serializeBuffer);
- *resultBuffer = NULL;
- *resultSize = 0;
+ if (NULL != resultBuffer) {
+ *resultBuffer = NULL;
+ }
+ if (NULL != resultSize) {
+ *resultSize = 0;
+ }
}
return err;
{
VixError err = VIX_OK;
FoundryWorkerThread *threadState = NULL;
+ static const char *createThreadFailureMsg =
+ "%s: thread creation failed with error %d.\n";
ASSERT(proc);
0,
&(threadState->threadId));
if (NULL == threadState->threadHandle) {
+ Log(createThreadFailureMsg, __FUNCTION__, GetLastError());
err = VIX_E_OUT_OF_MEMORY;
goto abort;
}
FoundryThreadWrapperProc,
threadState);
if (0 != result) {
+ Log(createThreadFailureMsg, __FUNCTION__, result);
err = VIX_E_OUT_OF_MEMORY;
goto abort;
}
* None.
*
* Side effects:
+ * May block while the given thread stops.
*
*-----------------------------------------------------------------------------
*/
void
FoundryThreads_StopThread(FoundryWorkerThread *threadState) // IN
{
+#ifdef _WIN32
+ DWORD waitResult;
+#endif
+
+ if (NULL == threadState) {
+ ASSERT(0);
+ return;
+ }
+
/*
- * Stop the poll thread.
+ * Stop the thread.
*/
threadState->stopThread = TRUE;
- if (NULL != threadState) {
-#ifdef _WIN32
- DWORD waitResult;
-
- ASSERT(threadState->threadId != GetCurrentThreadId());
-
- waitResult = WaitForSingleObject(threadState->threadHandle, 30000);
- if (WAIT_OBJECT_0 != waitResult) {
- TerminateThread(threadState->threadHandle, 0x1);
- }
+ ASSERT(!FoundryThreads_IsCurrentThread(threadState));
- CloseHandle(threadState->threadHandle);
- threadState->threadHandle = NULL;
+#ifdef _WIN32
+ waitResult = WaitForSingleObject(threadState->threadHandle, 30000);
+ if (WAIT_OBJECT_0 != waitResult) {
+ TerminateThread(threadState->threadHandle, 0x1);
+ }
#else
- pthread_join(threadState->threadInfo, NULL);
- threadState->threadInfo = 0;
+ pthread_join(threadState->threadInfo, NULL);
#endif
- }
- free(threadState);
+ FoundryThreads_Free(threadState);
}
+
/*
*-----------------------------------------------------------------------------
*
* None.
*
* Side effects:
+ * None.
*
*-----------------------------------------------------------------------------
*/
#else
threadState->threadInfo = 0;
#endif
- }
- free(threadState);
+ free(threadState);
+ }
}
+
/*
*-----------------------------------------------------------------------------
*
return FALSE;
}
#ifdef _WIN32
- {
- Util_ThreadID id = GetCurrentThreadId();
- if (id == threadState->threadId) {
- return TRUE;
- }
- }
+ return (GetCurrentThreadId() == threadState->threadId);
#else
- {
- pthread_t id = pthread_self();
- if (pthread_equal(id, threadState->threadInfo)) {
- return TRUE;
- }
- }
+ return pthread_equal(pthread_self(), threadState->threadInfo);
#endif
- return FALSE;
}
threadState = (FoundryWorkerThread *) threadParameter;
if (NULL == threadState) {
+ ASSERT(0);
goto abort;
}
-
- if (NULL != threadState) {
+
+ if (NULL != threadState->threadProc) {
(*(threadState->threadProc))(threadState);
}
#include "dictll.h"
#include "msg.h"
#include "file.h"
-#include "dynbuf.h"
-#include "vmstdio.h"
#include "codeset.h"
#include "productState.h"
#include "posix.h"
}
-/*
- *----------------------------------------------------------------------
- *
- * GuestApp_GetCmdOutput --
- *
- * Run a cmd & get its cmd line output
- *
- * Results:
- * An allocated string or NULL if an error occurred.
- *
- * Side effects:
- * The cmd is run.
- *
- *----------------------------------------------------------------------
- */
-
-char *
-GuestApp_GetCmdOutput(const char *cmd) // IN
-{
-#ifdef N_PLAT_NLM
- Debug("Trying to execute command \"%s\" and catch its output... No way on NetWare...\n", cmd);
- return NULL;
-#else
- DynBuf db;
- FILE *stream;
- char *out = NULL;
-
- DynBuf_Init(&db);
-
- stream = Posix_Popen(cmd, "r");
- if (stream == NULL) {
- Debug("Unable to get output of command \"%s\"\n", cmd);
-
- return NULL;
- }
-
- for (;;) {
- char *line = NULL;
- size_t size;
-
- switch (StdIO_ReadNextLine(stream, &line, 0, &size)) {
- case StdIO_Error:
- goto close;
- break;
-
- case StdIO_EOF:
- break;
-
- case StdIO_Success:
- break;
-
- default:
- ASSERT_NOT_IMPLEMENTED(FALSE);
- }
-
- if (line == NULL) {
- break;
- }
-
- DynBuf_Append(&db, line, size);
- free(line);
- }
-
- if (DynBuf_Get(&db)) {
- out = (char *)DynBuf_AllocGet(&db);
- }
- close:
- DynBuf_Destroy(&db);
-
-#ifndef _WIN32
- pclose(stream);
-#else
- _pclose(stream);
-#endif
-
- return out;
-#endif
-}
-
-
/*
*----------------------------------------------------------------------
*
libGuestInfo_la_SOURCES += guestInfoPosix.c
libGuestInfo_la_SOURCES += guestInfoPerfMonLinux.c
-if ENABLE_CORE_SERVICES
noinst_LTLIBRARIES += libGuestInfoCS.la
libGuestInfoCS_la_SOURCES =
libGuestInfoCS_la_SOURCES += guestInfo.c
libGuestInfoCS_la_SOURCES += guestInfoPosix.c
-endif
AM_CFLAGS = $(DNET_CPPFLAGS)
}
-/*
- *-----------------------------------------------------------------------------
- *
- * GuestInfoGetOSName --
- *
- * Return OS version information.
- *
- * osFullName format:
- * Linux/POSIX:
- * <OS NAME> <OS RELEASE> <SPECIFIC_DISTRO_INFO>
- * An example of such string would be:
- * Linux 2.4.18-3 Red Hat Linux release 7.3 (Valhalla)
- *
- * Win32:
- * <OS NAME> <SERVICE PACK> (BUILD <BUILD_NUMBER>)
- * An example of such string would be:
- * Windows XP Professional Service Pack 2 (Build 2600)
- *
- * osName contains an os name in the same format that is used
- * in .vmx file.
- *
- * Results:
- * Returns TRUE on success and FALSE on failure.
- * Returns the guest's full OS name (osNameFull)
- * Returns the guest's OS name in the same format as .vmx file (osName)
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-GuestInfo_GetOSName(unsigned int outBufFullLen, // IN
- unsigned int outBufLen, // IN
- char *osNameFull, // OUT
- char *osName) // OUT
-{
- return GuestInfoGetOSName(outBufFullLen, outBufLen, osNameFull, osName);
-}
-
-
/**
* Add a NIC into the given list. The macAddress of the new GuestNic is
* initialized with the given address.
Bool GuestInfoGetNicInfo(GuestNicList *nicInfo);
void GuestInfoMemset(void * mem, int value, unsigned int size);
Bool GuestInfoGetDiskInfo(PGuestDiskInfo di);
-Bool GuestInfoGetOSName(unsigned int outBufFullLen, unsigned int outBufLen,
- char *osNameFull, char *osName);
Bool GuestInfo_PerfMon(struct GuestMemInfo *vmStats);
GuestNic *GuestInfoAddNicEntry(GuestNicList *nicInfo,
{
#ifndef NO_PROCPS
ASSERT(vmStats);
+ vmStats->flags = 0;
GuestInfoMonitorGetStat(vmStats);
if (GuestInfoMonitorReadMeminfo(vmStats)) {
- vmStats->flags = LINUX_MEMINFO_FLAGS;
+ vmStats->flags |= LINUX_MEMINFO_FLAGS;
return TRUE;
}
#endif
#include "guestApp.h"
#include "guestInfo.h"
-#define DISTRO_BUF_SIZE 255
-
-typedef struct lsb_distro_info {
- char *name;
- char *scanstring;
-} LSBDistroInfo;
-
-
-LSBDistroInfo lsbFields[] = {
- {"DISTRIB_ID=", "DISTRIB_ID=%s"},
- {"DISTRIB_RELEASE=", "DISTRIB_RELEASE=%s"},
- {"DISTRIB_CODENAME=", "DISTRIB_CODENAME=%s"},
- {"DISTRIB_DESCRIPTION=", "DISTRIB_DESCRIPTION=%s"},
- {NULL, NULL},
-};
-
-
-typedef struct distro_info {
- char *name;
- char *filename;
-} DistroInfo;
-
-
-DistroInfo distroArray[] = {
- {"RedHat", "/etc/redhat-release"},
- {"RedHat", "/etc/redhat_version"},
- {"Sun", "/etc/sun-release"},
- {"SuSE", "/etc/SuSE-release"},
- {"SuSE", "/etc/novell-release"},
- {"SuSE", "/etc/sles-release"},
- {"Debian", "/etc/debian_version"},
- {"Debian", "/etc/debian_release"},
- {"Mandrake", "/etc/mandrake-release"},
- {"Mandriva", "/etc/mandriva-release"},
- {"Mandrake", "/etc/mandrakelinux-release"},
- {"TurboLinux", "/etc/turbolinux-release"},
- {"Fedora Core", "/etc/fedora-release"},
- {"Gentoo", "/etc/gentoo-release"},
- {"Novell", "/etc/nld-release"},
- {"Ubuntu", "/etc/lsb-release"},
- {"Annvix", "/etc/annvix-release"},
- {"Arch", "/etc/arch-release"},
- {"Arklinux", "/etc/arklinux-release"},
- {"Aurox", "/etc/aurox-release"},
- {"BlackCat", "/etc/blackcat-release"},
- {"Cobalt", "/etc/cobalt-release"},
- {"Conectiva", "/etc/conectiva-release"},
- {"Immunix", "/etc/immunix-release"},
- {"Knoppix", "/etc/knoppix_version"},
- {"Linux-From-Scratch", "/etc/lfs-release"},
- {"Linux-PPC", "/etc/linuxppc-release"},
- {"MkLinux", "/etc/mklinux-release"},
- {"PLD", "/etc/pld-release"},
- {"Slackware", "/etc/slackware-version"},
- {"Slackware", "/etc/slackware-release"},
- {"SMEServer", "/etc/e-smith-release"},
- {"Solaris", "/etc/release"},
- {"Tiny Sofa", "/etc/tinysofa-release"},
- {"UltraPenguin", "/etc/ultrapenguin-release"},
- {"UnitedLinux", "/etc/UnitedLinux-release"},
- {"VALinux", "/etc/va-release"},
- {"Yellow Dog", "/etc/yellowdog-release"},
- {NULL, NULL},
-};
-
-
/*
*-----------------------------------------------------------------------------
return FALSE;
#endif
}
-
-/*
- *-----------------------------------------------------------------------------
- *
- * GetShortName --
- *
- * Returns distro information based on .vmx format (distroShort).
- *
- * Return value:
- * Overwrited the short name if we recognise the OS.
- * Otherwise leave the short name as it is.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-GetShortName(char *distro, // IN: full distro name
- char *distroShort, // OUT: short distro name (based on .vmx file)
- int distroShortSize) // IN: size of the buffer allocated for short distro name
-
-{
- char *distroLower = NULL; /* Lower case distro name */
-
- distroLower = calloc(strlen(distro) + 1, sizeof *distroLower);
-
- if (distroLower == NULL) {
- Debug("GetShortName: could not allocate memory\n");
- return;
- }
-
- Str_Strcpy(distroLower, distro, distroShortSize);
- distroLower = Str_ToLower(distroLower);
-
- if (strstr(distroLower, "red hat")) {
- if (strstr(distroLower, "enterprise")) {
-
- /*
- * Looking for "release x" here instead of "x" as there could be
- * build version which can be misleading.
- * For example Red Hat Enterprise Linux ES release 4 (Nahant Update 3)
- */
-
- int release = 0;
- char *releaseStart = strstr(distroLower, "release");
-
- if (releaseStart) {
- sscanf(releaseStart, "release %d", &release);
- if (release > 0) {
- snprintf(distroShort, distroShortSize, STR_OS_RED_HAT_EN"%d", release);
- }
- }
-
- if (release <= 0) {
- Debug("GetShortName: could not read Red Hat Enterprise release version\n");
- Str_Strcpy(distroShort, STR_OS_RED_HAT_EN, distroShortSize);
- }
-
- } else {
- Str_Strcpy(distroShort, STR_OS_RED_HAT, distroShortSize);
- }
- } else if (strstr(distroLower, "suse")) {
- if (strstr(distroLower, "enterprise")) {
- Str_Strcpy(distroShort, STR_OS_SUSE_EN, distroShortSize);
- } else if (strstr(distroLower, "sun")) {
- Str_Strcpy(distroShort, STR_OS_SUN_DESK, distroShortSize);
- } else if (strstr(distroLower, "novell")) {
- Str_Strcpy(distroShort, STR_OS_NOVELL, distroShortSize);
- } else {
- Str_Strcpy(distroShort, STR_OS_SUSE, distroShortSize);
- }
- } else if (strstr(distroLower, "mandrake")) {
- Str_Strcpy(distroShort, STR_OS_MANDRAKE, distroShortSize);
- } else if (strstr(distroLower, "turbolinux")) {
- Str_Strcpy(distroShort, STR_OS_TURBO, distroShortSize);
- } else if (strstr(distroLower, "sun")) {
- Str_Strcpy(distroShort, STR_OS_SUN_DESK, distroShortSize);
- } else if (strstr(distroLower, "annvix")) {
- Str_Strcpy(distroShort, STR_OS_ANNVIX, distroShortSize);
- } else if (strstr(distroLower, "arch")) {
- Str_Strcpy(distroShort, STR_OS_ARCH, distroShortSize);
- } else if (strstr(distroLower, "arklinux")) {
- Str_Strcpy(distroShort, STR_OS_ARKLINUX, distroShortSize);
- } else if (strstr(distroLower, "aurox")) {
- Str_Strcpy(distroShort, STR_OS_AUROX, distroShortSize);
- } else if (strstr(distroLower, "black cat")) {
- Str_Strcpy(distroShort, STR_OS_BLACKCAT, distroShortSize);
- } else if (strstr(distroLower, "cobalt")) {
- Str_Strcpy(distroShort, STR_OS_COBALT, distroShortSize);
- } else if (strstr(distroLower, "conectiva")) {
- Str_Strcpy(distroShort, STR_OS_CONECTIVA, distroShortSize);
- } else if (strstr(distroLower, "debian")) {
- Str_Strcpy(distroShort, STR_OS_DEBIAN, distroShortSize);
- } else if (strstr(distroLower, "fedora")) {
- Str_Strcpy(distroShort, STR_OS_FEDORA, distroShortSize);
- } else if (strstr(distroLower, "gentoo")) {
- Str_Strcpy(distroShort, STR_OS_GENTOO, distroShortSize);
- } else if (strstr(distroLower, "immunix")) {
- Str_Strcpy(distroShort, STR_OS_IMMUNIX, distroShortSize);
- } else if (strstr(distroLower, "linux-from-scratch")) {
- Str_Strcpy(distroShort, STR_OS_LINUX_FROM_SCRATCH, distroShortSize);
- } else if (strstr(distroLower, "linux-ppc")) {
- Str_Strcpy(distroShort, STR_OS_LINUX_PPC, distroShortSize);
- } else if (strstr(distroLower, "mandriva")) {
- Str_Strcpy(distroShort, STR_OS_MANDRIVA, distroShortSize);
- } else if (strstr(distroLower, "mklinux")) {
- Str_Strcpy(distroShort, STR_OS_MKLINUX, distroShortSize);
- } else if (strstr(distroLower, "pld")) {
- Str_Strcpy(distroShort, STR_OS_PLD, distroShortSize);
- } else if (strstr(distroLower, "slackware")) {
- Str_Strcpy(distroShort, STR_OS_SLACKWARE, distroShortSize);
- } else if (strstr(distroLower, "sme server")) {
- Str_Strcpy(distroShort, STR_OS_SMESERVER, distroShortSize);
- } else if (strstr(distroLower, "tiny sofa")) {
- Str_Strcpy(distroShort, STR_OS_TINYSOFA, distroShortSize);
- } else if (strstr(distroLower, "ubuntu")) {
- Str_Strcpy(distroShort, STR_OS_UBUNTU, distroShortSize);
- } else if (strstr(distroLower, "ultra penguin")) {
- Str_Strcpy(distroShort, STR_OS_ULTRAPENGUIN, distroShortSize);
- } else if (strstr(distroLower, "united linux")) {
- Str_Strcpy(distroShort, STR_OS_UNITEDLINUX, distroShortSize);
- } else if (strstr(distroLower, "va linux")) {
- Str_Strcpy(distroShort, STR_OS_VALINUX, distroShortSize);
- } else if (strstr(distroLower, "yellow dog")) {
- Str_Strcpy(distroShort, STR_OS_YELLOW_DOG, distroShortSize);
- }
-
- free(distroLower);
-
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ReadDistroFile --
- *
- * Look for a distro version file /etc/xxx-release.
- * Once found, read the file in and figure out which distribution.
- *
- * Return value:
- * Returns TRUE on success and FALSE on failure.
- * Returns distro information verbatium from /etc/xxx-release (distro).
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-ReadDistroFile(char *filename, // IN: distro version file name
- int distroSize, // IN: size of the buffer allocated for OS distro name
- char *distro) // OUT: full distro name
-{
- int fd;
- int buf_sz;
- struct stat st;
- Bool ret = FALSE;
- char *distroOrig = NULL;
- char distroPart[DISTRO_BUF_SIZE];
- char *tmpDistroPos = NULL;
- int i = 0;
-
- if ((fd = open(filename, O_RDONLY)) < 0) {
- Debug("ReadDistroFile: could not open file%s: %d\n", filename, errno);
- return FALSE;
- }
-
- if (fstat(fd, &st)) {
- Debug("ReadDistroFile: could not stat the file %s: %d\n", filename, errno);
- goto out;
- }
-
- buf_sz = st.st_size;
- if (buf_sz >= distroSize) {
- Debug("ReadDistroFile: input buffer too small\n");
- goto out;
- }
- distroOrig = calloc(distroSize, sizeof *distroOrig);
-
- if (distroOrig == NULL) {
- Debug("ReadDistroFile: could not allocate memory\n");
- close(fd);
- return FALSE;
- }
-
- if (read(fd, distroOrig, buf_sz) != buf_sz) {
- Debug("ReadDistroFile: could not read file %s: %d\n", filename, errno);
- goto out;
- }
-
- distroOrig[buf_sz] = '\0';
-
- /*
- * For the case where we do have a release file in the LSB format,
- * but there is no LSB module, let's parse the LSB file for possible fields.
- */
-
- distro[0] = '\0';
-
- for (i = 0; lsbFields[i].name != NULL; i++) {
-
- tmpDistroPos = strstr(distroOrig, lsbFields[i].name);
- if (tmpDistroPos) {
- sscanf(tmpDistroPos, lsbFields[i].scanstring, distroPart);
- if (distroPart[0] == '"') {
- char *tmpMakeNull = NULL;
-
- tmpDistroPos += strlen(lsbFields[i].name) + 1;
- tmpMakeNull = strchr(tmpDistroPos + 1 , '"');
- if (tmpMakeNull) {
- *tmpMakeNull = '\0';
- Str_Strcat(distro, tmpDistroPos, distroSize);
- *tmpMakeNull = '"' ;
- }
- } else {
- Str_Strcat(distro, distroPart, distroSize);
- }
- Str_Strcat(distro, " ", distroSize);
- }
- }
-
- if (distro[0] == '\0') {
- /* Copy original string. What we got wasn't LSB compliant. */
- Str_Strcpy(distro, distroOrig, distroSize);
- }
-
- ret = TRUE;
-
-out:
- close(fd);
- free(distroOrig);
-
- return ret;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * GuestInfoGetOSName --
- *
- * Return OS version information. First retrieve OS information using
- * uname, then look in /etc/xxx-release file to get the distro info.
- * osFullName will be:
- * <OS NAME> <OS RELEASE> <SPECIFIC_DISTRO_INFO>
- * An example of such string would be:
- * Linux 2.4.18-3 Red Hat Linux release 7.3 (Valhalla)
- *
- * osName contains an os name in the same format that is used
- * in .vmx file.
- *
- * Return value:
- * Returns TRUE on success and FALSE on failure.
- * Returns the guest's full OS name (osNameFull)
- * Returns the guest's OS name in the same format as .vmx file (osName)
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-GuestInfoGetOSName(unsigned int outBufFullLen, // IN: length of osNameFull buffer
- unsigned int outBufLen, // IN: length of osName buffer
- char *osNameFull, // OUT: Full OS name
- char *osName) // OUT: OS name (.vmx file format)
-{
- struct utsname buf;
- unsigned int lastCharPos;
- const char *lsbCmd = "lsb_release -sd 2>/dev/null";
- char *lsbOutput = NULL;
-
- /*
- * Use uname to get complete OS information.
- */
-
- if (uname(&buf) < 0) {
- Debug("GuestInfoGetOSName: uname failed %d\n", errno);
- return FALSE;
- }
-
-
- if (strlen(buf.sysname) + strlen(buf.release) + 3 > outBufFullLen) {
- Debug("GuestInfoGetOSName: Error: buffer too small\n");
- return FALSE;
- }
-
- Str_Strcpy(osName, STR_OS_EMPTY, outBufLen);
- Str_Strcpy(osNameFull, buf.sysname, outBufFullLen);
- Str_Strcat(osNameFull, STR_OS_EMPTY, outBufFullLen);
- Str_Strcat(osNameFull, buf.release, outBufFullLen);
-
- /*
- * Check to see if this is Linux
- * If yes, determine the distro by looking for /etc/xxx file.
- */
-
- if (strstr(osNameFull, "Linux")) {
- char distro[DISTRO_BUF_SIZE];
- char distroShort[DISTRO_BUF_SIZE];
- int i = 0;
- int distroSize = sizeof distro;
-
- /*
- * Write default distro string depending on
- * the kernel version.
- * If later we find more detailed information
- * this will get overwritten.
- */
-
- if (strstr(buf.release, "2.4")) {
- Str_Strcpy(distro, STR_OS_OTHER_24_FULL, distroSize);
- Str_Strcpy(distroShort, STR_OS_OTHER_24, distroSize);
- } else if (strstr(buf.release, "2.6")) {
- Str_Strcpy(distro, STR_OS_OTHER_26_FULL, distroSize);
- Str_Strcpy(distroShort, STR_OS_OTHER_26, distroSize);
- } else {
- Str_Strcpy(distro, STR_OS_OTHER_FULL, distroSize);
- Str_Strcpy(distroShort, STR_OS_OTHER, distroSize);
- }
-
- /*
- * Try to get OS detailed information
- * from the lsb_release command.
- */
- lsbOutput = GuestApp_GetCmdOutput(lsbCmd);
-
- if (!lsbOutput) {
- /*
- * Try to get more detailed information
- * from the version file.
- */
-
- for (i = 0; distroArray[i].filename != NULL; i++) {
- if (ReadDistroFile(distroArray[i].filename, distroSize, distro)) {
- break;
- }
- }
-
- /*
- * If we failed to read every distro file, exit now, before calling
- * strlen on the distro buffer (which wasn't set).
- */
- if (distroArray[i].filename == NULL) {
- Debug("GuestInfoGetOSName: Error: no distro file found\n");
- return FALSE;
- }
- } else {
- char *lsbStart = lsbOutput;
- char *quoteEnd = NULL;
-
- if (lsbStart[0] == '"') {
- lsbStart++;
- quoteEnd = strchr(lsbStart, '"');
- if (quoteEnd) {
- *quoteEnd = '\0';
- }
- }
- Str_Strcpy(distro, lsbStart, distroSize);
- free(lsbOutput);
- }
-
- GetShortName(distro, distroShort, distroSize);
-
- if (strlen(distro) + strlen(osNameFull) + 2 > outBufFullLen) {
- Debug("GuestInfoGetOSName: Error: buffer too small\n");
- return FALSE;
- }
-
- Str_Strcat(osNameFull, " ", outBufFullLen);
- Str_Strcat(osNameFull, distro, outBufFullLen);
-
- if (strlen(distroShort) + 1 > outBufLen) {
- Debug("GuestInfoGetOSName: Error: buffer too small\n");
- return FALSE;
- }
-
- Str_Strcpy(osName, distroShort, outBufLen);
- } else if (strstr(osNameFull, "FreeBSD")) {
- size_t nameLen = sizeof STR_OS_FREEBSD - 1;
- size_t releaseLen = 0;
- char *dashPtr;
-
- /*
- * FreeBSD releases report their version as "x.y-RELEASE". We'll be naive
- * look for the first dash, and use everything before it as the version
- * number.
- */
- dashPtr = Str_Strchr(buf.release, '-');
- if (dashPtr != NULL) {
- releaseLen = dashPtr - buf.release;
- }
-
- if (nameLen + releaseLen + 1 > outBufLen) {
- Debug("GuestInfoGetOSName: Error: buffer too small\n");
- return FALSE;
- }
-
- Str_Strcpy(osName, STR_OS_FREEBSD, outBufLen);
- if (releaseLen != 0) {
- Str_Strncat(osName, outBufLen, buf.release, releaseLen);
- }
- } else if (strstr(osNameFull, "SunOS")) {
- size_t nameLen = sizeof STR_OS_SOLARIS - 1;
- size_t releaseLen = 0;
- char *periodPtr;
-
- /*
- * Solaris releases report their version as "x.y". For our supported
- * releases it seems that x is always "5", and is ignored in favor of
- * y for the version number. We'll be naive and look for the first
- * period, and use the entire string after that as the version number.
- */
- periodPtr = Str_Strchr(buf.release, '.');
- if (periodPtr != NULL) {
- releaseLen = (buf.release + strlen(buf.release)) - periodPtr;
- }
-
- if (nameLen + releaseLen + 1 > outBufLen) {
- Debug("GuestInfoGetOSName: Error: buffer too small\n");
- return FALSE;
- }
-
- Str_Strcpy(osName, STR_OS_SOLARIS, outBufLen);
- if (releaseLen != 0) {
- Str_Strcat(osName, periodPtr + 1, outBufLen);
- }
- }
-
- if (Hostinfo_GetSystemBitness() == 64) {
- if (strlen(osName) + sizeof STR_OS_64BIT_SUFFIX > outBufLen) {
- Debug("GuestInfoGetOSName: Error: buffer too small\n");
- return FALSE;
- }
- Str_Strcat(osName, STR_OS_64BIT_SUFFIX, outBufLen);
- }
-
- /*
- * Before returning, truncate
- * the \n character at the end of the full name.
- */
- lastCharPos = strlen(osNameFull) - 1;
- if (osNameFull[lastCharPos] == '\n') {
- osNameFull[lastCharPos] = '\0';
- }
-
- return TRUE;
-}
#include "util.h"
#include "rpcout.h"
#include "rpcvmx.h"
+#include "hostinfo.h"
#include "guestInfo.h"
#include "guestApp.h"
#include "guestInfoServer.h"
}
/* Gather all the relevant guest information. */
- if (!GuestInfoGetOSName(sizeof osNameFull, sizeof osName, osNameFull, osName)) {
+ if (!Hostinfo_GetOSName(sizeof osNameFull, sizeof osName, osNameFull,
+ osName)) {
Debug("Failed to get OS info.\n");
} else {
if (!GuestInfoUpdateVmdb(INFO_OS_NAME_FULL, osNameFull)) {
# to copy the sources to the build dir before compiling them.
ghiGetBinaryHandlers.h: ghiGetBinaryHandlers.x
- if [ $(top_builddir) != $(top_srcdir) ]; then \
- cp $(top_srcdir)/lib/guestRpc/ghiGetBinaryHandlers.x $(builddir); \
+ if [ $(top_builddir) != $(top_srcdir) ]; then \
+ cp -f $(top_srcdir)/lib/guestRpc/ghiGetBinaryHandlers.x $(builddir); \
fi
- $(RPCGEN) -h -o $@ ghiGetBinaryHandlers.x
+ $(RPCGEN) $(RPCGENFLAGS) -h -o $@ $(builddir)/ghiGetBinaryHandlers.x
$(SED) 's,rpc/rpc\.h,vmxrpc.h,' $@ > $@.tmp
mv $@.tmp $@
$(MKDIR_P) $(top_builddir)/lib/include/guestrpc
cp $@ $(top_builddir)/lib/include/guestrpc
ghiGetBinaryHandlers_xdr.c: ghiGetBinaryHandlers.x ghiGetBinaryHandlers.h
- $(RPCGEN) -c -o $@ ghiGetBinaryHandlers.x
+ $(RPCGEN) $(RPCGENFLAGS) -c -o $@ $(builddir)/ghiGetBinaryHandlers.x
ghiProtocolHandler.h: ghiProtocolHandler.x
- if [ $(top_builddir) != $(top_srcdir) ]; then \
- cp $(top_srcdir)/lib/guestRpc/ghiProtocolHandler.x $(builddir); \
+ if [ $(top_builddir) != $(top_srcdir) ]; then \
+ cp -f $(top_srcdir)/lib/guestRpc/ghiProtocolHandler.x $(builddir); \
fi
- $(RPCGEN) -h -o $@ ghiProtocolHandler.x
+ $(RPCGEN) $(RPCGENFLAGS) -h -o $@ $(builddir)/ghiProtocolHandler.x
$(SED) 's,rpc/rpc\.h,vmxrpc.h,' $@ > $@.tmp
mv $@.tmp $@
$(MKDIR_P) $(top_builddir)/lib/include/guestrpc
cp $@ $(top_builddir)/lib/include/guestrpc
ghiProtocolHandler_xdr.c: ghiProtocolHandler.x ghiProtocolHandler.h
- $(RPCGEN) -c -o $@ ghiProtocolHandler.x
+ $(RPCGEN) $(RPCGENFLAGS) -c -o $@ $(builddir)/ghiProtocolHandler.x
nicinfo.h: nicinfo.x
- if [ $(top_builddir) != $(top_srcdir) ]; then \
- cp $(top_srcdir)/lib/guestRpc/nicinfo.x $(builddir); \
+ if [ $(top_builddir) != $(top_srcdir) ]; then \
+ cp -f $(top_srcdir)/lib/guestRpc/nicinfo.x $(builddir); \
fi
- $(RPCGEN) -h -o $@ $<
+ $(RPCGEN) $(RPCGENFLAGS) -h -o $@ $(builddir)/nicinfo.x
$(SED) 's,rpc/rpc\.h,vmxrpc.h,' $@ > $@.tmp
mv $@.tmp $@
$(MKDIR_P) $(top_builddir)/lib/include/guestrpc
cp $@ $(top_builddir)/lib/include/guestrpc
+nicinfo_xdr.c: nicinfo.x nicinfo.h
+ $(RPCGEN) $(RPCGENFLAGS) -c -o $@ $(builddir)/nicinfo.x
+
guestlibV3.h: guestlibV3.x
- if [ $(top_builddir) != $(top_srcdir) ]; then \
- cp $(top_srcdir)/lib/guestRpc/guestlibV3.x $(builddir); \
+ if [ $(top_builddir) != $(top_srcdir) ]; then \
+ cp -f $(top_srcdir)/lib/guestRpc/guestlibV3.x $(builddir); \
fi
- $(RPCGEN) -h -o $@ $<
+ $(RPCGEN) $(RPCGENFLAGS) -h -o $@ $(builddir)/guestlibV3.x
$(SED) 's,rpc/rpc\.h,vmxrpc.h,' $@ > $@.tmp
mv $@.tmp $@
$(MKDIR_P) $(top_builddir)/lib/include/guestrpc
cp $@ $(top_builddir)/lib/include/guestrpc
-nicinfo_xdr.c: nicinfo.x nicinfo.h
- $(RPCGEN) -c -o $@ nicinfo.x
-
guestlibV3_xdr.c: guestlibV3.x guestlibV3.h
- $(RPCGEN) -c -o $@ guestlibV3.x
+ $(RPCGEN) $(RPCGENFLAGS) -c -o $@ $(builddir)/guestlibV3.x
unityActive.h: unityActive.x
- if [ $(top_builddir) != $(top_srcdir) ]; then \
- cp $(top_srcdir)/lib/guestRpc/unityActive.x $(builddir); \
+ if [ $(top_builddir) != $(top_srcdir) ]; then \
+ cp -f $(top_srcdir)/lib/guestRpc/unityActive.x $(builddir); \
fi
- $(RPCGEN) -h -o $@ unityActive.x
+ $(RPCGEN) $(RPCGENFLAGS) -h -o $@ $(builddir)/unityActive.x
$(SED) 's,rpc/rpc\.h,vmxrpc.h,' $@ > $@.tmp
mv $@.tmp $@
$(MKDIR_P) $(top_builddir)/lib/include/guestrpc
cp $@ $(top_builddir)/lib/include/guestrpc
unityActive_xdr.c: unityActive.x unityActive.h
- $(RPCGEN) -c -o $@ unityActive.x
- GetBinaryHandlers.h: ghiGetBinaryHandlers.x
+ $(RPCGEN) $(RPCGENFLAGS) -c -o $@ $(builddir)/unityActive.x
+
GUESTLIB_ELAPSED_MS = 17,
GUESTLIB_RESOURCE_POOL_PATH = 18,
+ GUESTLIB_CPU_STOLEN_MS = 19,
+ GUESTLIB_MEM_TARGET_SIZE_MB = 20,
/*------ Add any new statistics above this line. ------- */
/*------ Bump this when adding to this list. -------*/
- GUESTLIB_MAX_STATISTIC_ID = 19
+ GUESTLIB_MAX_STATISTIC_ID = 21
};
union GuestLibV3Stat switch (GuestLibV3TypeIds d) {
case GUESTLIB_RESOURCE_POOL_PATH:
struct GuestLibV3String resourcePoolPath;
+
+ case GUESTLIB_CPU_STOLEN_MS:
+ struct GuestLibV3StatUint64 cpuStolenMs;
+ case GUESTLIB_MEM_TARGET_SIZE_MB:
+ struct GuestLibV3StatUint64 memTargetSizeMB;
};
reply->attr.groupId = attr->groupId;
reply->attr.hostFileId = attr->hostFileId;
reply->attr.volumeId = attr->volumeId;
+ reply->attr.effectivePerms = attr->effectivePerms;
reply->reserved = 0;
*packetSize = HGFS_REP_PAYLOAD_SIZE_V3(reply) + utf8TargetNameLen;
break;
uint32 groupId; /* group identifier, ignored by Windows */
uint64 hostFileId; /* File Id of the file on host: inode_t on Linux */
uint32 volumeId; /* Volume Id of the volune on which the file resides */
+ uint32 effectivePerms; /* Permissions in effect for the current user */
} HgfsFileAttrInfo;
typedef struct HgfsCreateDirInfo {
static Bool HgfsIsShareRoot(char const *cpName, size_t cpNameSize);
static HgfsInternalStatus HgfsGetHiddenXAttr(char const *fileName, Bool *attribute);
static HgfsInternalStatus HgfsSetHiddenXAttr(char const *fileName, Bool value);
-
+static HgfsInternalStatus HgfsEffectivePermissions(char *fileName,
+ Bool readOnlyShare,
+ uint32 *permissions);
#ifdef HGFS_OPLOCKS
/*
*-----------------------------------------------------------------------------
Boolean wasAliased;
OSStatus osStatus;
+ ASSERT_ON_COMPILE(sizeof osStatus == sizeof (int32));
+
/*
* Create and resolve an FSRef of the desired path. We pass FALSE to
* resolveAliasChains because aliases to aliases should behave as
osStatus = FSPathMakeRef(fileName, &fileRef, NULL);
if (osStatus != noErr) {
LOG(4, ("HgfsGetattrResolveAlias: could not create file reference: "
- "error %lu\n", osStatus));
+ "error %d\n", (int32)osStatus));
goto exit;
}
/*
&wasAliased, kResolveAliasFileNoUI);
if (osStatus != noErr) {
LOG(4, ("HgfsGetattrResolveAlias: could not resolve reference: error "
- "%lu\n", osStatus));
+ "%d\n", (int32)osStatus));
goto exit;
}
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEffectivePermissions --
+ *
+ * Get permissions that are in efffect for the current user.
+ *
+ * Results:
+ * Zero on success.
+ * Non-zero on failure.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static HgfsInternalStatus
+HgfsEffectivePermissions(char *fileName, // IN: Input filename
+ Bool readOnlyShare, // IN: Share name
+ uint32 *permissions) // OUT: Effective permissions
+{
+ *permissions = 0;
+ if (access(fileName, R_OK) == 0) {
+ *permissions |= HGFS_PERM_READ;
+ }
+ if (access(fileName, X_OK) == 0) {
+ *permissions |= HGFS_PERM_EXEC;
+ }
+ if (!readOnlyShare && (access(fileName, W_OK) == 0)) {
+ *permissions |= HGFS_PERM_WRITE;
+ }
+ return 0;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
* readlink to get it. If not a symlink, the targetName argument is
* untouched. Does necessary translation between Unix file stats and the
* HgfsFileAttrInfo formats.
+ * NOTE: The function is different from HgfsGetAttrFromId: this function returns
+ * effectve permissions while HgfsGetAttrFromId does not.
+ * The reason for this asymmetry is that effective permissions are needed
+ * to get a new handle. If the file is already opened then
+ * getting effective permissions does not have any value. However getting
+ * effective permissions would hurt perfomance and should be avoided.
*
* Results:
* Zero on success.
*/
HgfsGetHiddenAttr(fileName, attr);
+ /* Get effective permissions if we can */
+ if (!(S_ISLNK(stats.st_mode))) {
+ HgfsOpenMode shareMode;
+ uint32 permissions;
+ HgfsNameStatus nameStatus;
+ nameStatus = HgfsServerPolicy_GetShareMode(shareName, strlen(shareName),
+ &shareMode);
+ if (nameStatus == HGFS_NAME_STATUS_COMPLETE &&
+ HgfsEffectivePermissions(fileName,
+ shareMode == HGFS_OPEN_MODE_READ_ONLY,
+ &permissions) == 0) {
+ attr->mask |= HGFS_ATTR_VALID_EFFECTIVE_PERMS;
+ attr->effectivePerms = permissions;
+ }
+ }
+
exit:
free(myTargetName);
return status;
status = HgfsGetattrFromName(fullName, configOptions, search.utf8ShareName,
&attr, NULL);
- free(fullName);
-
if (status != 0) {
- LOG(4, ("HgfsServerSearchRead: stat FAILED, removing\n"));
- free(HgfsGetSearchResult(hgfsSearchHandle, requestedOffset, TRUE));
- free(dent);
- continue;
+ HgfsOp savedOp = attr.requestType;
+ LOG(4, ("HgfsServerSearchRead: stat FAILED %s (%d)\n",
+ fullName, status));
+ memset(&attr, 0, sizeof attr);
+ attr.requestType = savedOp;
+ attr.type = HGFS_FILE_TYPE_REGULAR;
+ attr.mask = 0;
}
+ free(fullName);
+
#if defined(__APPLE__)
/*
* HGFS clients receive names in unicode normal form C,
#define BDOOR_CMD_ACPI_HOTPLUG_MEMORY 57
#define BDOOR_CMD_ACPI_HOTPLUG_CBRET 58
#define BDOOR_CMD_GET_HOST_VIDEO_MODES 59
-#define BDOOR_CMD_MAX 60
+#define BDOOR_CMD_ACPI_HOTPLUG_CPU 60
+#define BDOOR_CMD_MAX 61
/*
* IMPORTANT NOTE: When modifying the behavior of an existing backdoor command,
#define BUILD_NUMBER \
- "build-142982"
+ "build-148847"
#define BUILD_NUMBER_NUMERIC \
- 142982
+ 148847
#define BUILD_NUMBER_NUMERIC_STRING \
- "142982"
+ "148847"
#define PRODUCT_BUILD_NUMBER \
- "product-build-444"
+ "product-build-472"
#define PRODUCT_BUILD_NUMBER_NUMERIC \
- 444
+ 472
#define PRODUCT_BUILD_NUMBER_NUMERIC_STRING \
- "444"
+ "472"
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * copyPaste.hh --
+ *
+ * CopyPaste common layer object for guest.
+ */
+
+#ifndef COPY_PASTE_HH
+#define COPY_PASTE_HH
+
+#include <string>
+#include <sigc++/trackable.h>
+#include "copyPasteBase.h"
+#include "copyPasteRpc.hh"
+
+class CopyPaste
+ : public CopyPasteBase,
+ public sigc::trackable
+{
+ public:
+ CopyPaste(void);
+ virtual ~CopyPaste(void);
+
+ /* Common CopyPaste layer API exposed to UI (all platforms). */
+ /* Local UI as CopyPaste source. */
+ virtual bool SetRemoteClipboard(const CPClipboard *clip);
+
+ /* Local UI as CopyPaste target. */
+ virtual bool GetRemoteClipboard(void) {return false;}
+ virtual std::string GetFiles(std::string dir = "");
+
+ virtual bool IsCopyPasteAllowed(void) { return mCopyPasteAllowed; }
+
+ void VmxCopyPasteVersionChanged(struct RpcIn *rpcIn,
+ uint32 version);
+ void SetCopyPasteAllowed(bool isCopyPasteAllowed)
+ { mCopyPasteAllowed = isCopyPasteAllowed; }
+
+ private:
+ /* Callbacks from rpc. */
+ void OnGetLocalClipboard(void);
+ void OnGetRemoteClipboardDone(const CPClipboard *clip);
+ void OnHGFileCopyDone(bool success);
+
+ std::string SetupDestDir(const std::string &destDir);
+
+ bool mCanCopyPaste;
+ bool mCopyPasteAllowed;
+
+ CopyPasteRpc *mRpc;
+ uint32 mVmxCopyPasteVersion;
+ VmTimeType mStateChangeTime;
+
+ std::string mStagingDir;
+};
+
+#endif // COPY_PASTE_HH
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * copyPasteBase.h --
+ *
+ * Base object for CopyPaste. This is the common interface between UI and
+ * cui CopyPaste protocol layer. Both host side and guest side, and also
+ * different platforms, share this same interface.
+ */
+
+#ifndef COPYPASTE_BASE_H
+#define COPYPASTE_BASE_H
+
+#include <sigc++/connection.h>
+
+#ifdef VMX86_TOOLS
+ /*
+ * LIB_EXPORT definition is not needed on guest.
+ */
+# define LIB_EXPORT
+#else
+ /*
+ * The interface class on host side for Windows is in dll which needs
+ * LIB_EXPORT definition.
+ */
+# include "libExport.hh"
+#endif
+
+extern "C" {
+ #include "vm_basic_types.h"
+ #include "dnd.h"
+}
+
+class LIB_EXPORT CopyPasteBase
+{
+ public:
+ enum COPYPASTE_STATE {
+ CPSTATE_INVALID = 0,
+ CPSTATE_READY,
+ CPSTATE_REQUESTING_CLIPBOARD,
+ };
+
+ virtual ~CopyPasteBase(void) {};
+
+ /* sigc signals for local UI callbacks. */
+ /* Local UI as CopyPaste source. */
+ sigc::signal<void, const CPClipboard*> newClipboard;
+ /* Local UI as CopyPaste target. */
+ sigc::signal<bool, CPClipboard*> localGetClipboard;
+ sigc::signal<void, bool> localGetFilesDoneChanged;
+
+ /* cui CopyPaste protocol layer API exposed to UI (all platforms). */
+ /* Local UI as CopyPaste source. */
+ virtual bool SetRemoteClipboard(const CPClipboard *clip) = 0;
+
+ /* Local UI as CopyPaste target. */
+ virtual bool GetRemoteClipboard(void) = 0;
+
+ virtual bool IsCopyPasteAllowed(void) = 0;
+
+ protected:
+ COPYPASTE_STATE mState;
+};
+
+#endif // COPYPASTE_BASE_H
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * copyPasteRpc.hh --
+ *
+ * Rpc layer object for CopyPaste.
+ */
+
+#ifndef COPY_PASTE_RPC_HH
+#define COPY_PASTE_RPC_HH
+
+#include <sigc++/connection.h>
+#include "vm_basic_types.h"
+
+extern "C" {
+ #include "dnd.h"
+}
+
+class CopyPasteRpc
+{
+ public:
+ virtual ~CopyPasteRpc(void) {};
+
+ /* sigc signals for callback. */
+ sigc::signal<void> ghGetClipboardChanged;
+ sigc::signal<void, const CPClipboard*> hgSetClipboardChanged;
+ sigc::signal<void, bool> hgFileCopyDoneChanged;
+
+ /* CopyPaste Rpc functions. */
+ virtual bool GHGetClipboardDone(const CPClipboard* clip) = 0;
+ virtual bool HGStartFileCopy(const char *stagingDirCP, size_t sz) = 0;
+};
+
+#endif // COPY_PASTE_RPC_HH
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * copyPasteRpcV3.hh --
+ *
+ * Rpc layer object for CopyPaste.
+ */
+
+#ifndef COPY_PASTE_RPC_V3_HH
+#define COPY_PASTE_RPC_V3_HH
+
+#include <sigc++/trackable.h>
+#include "copyPasteRpc.hh"
+#include "dndTransport.hh"
+
+class CopyPasteRpcV3
+ : public CopyPasteRpc,
+ public sigc::trackable
+{
+ public:
+ CopyPasteRpcV3(struct RpcIn *rpcIn);
+ virtual ~CopyPasteRpcV3(void);
+
+ /* CopyPaste Rpc functions. */
+ virtual bool GHGetClipboardDone(const CPClipboard* clip);
+ virtual bool HGStartFileCopy(const char *stagingDirCP, size_t sz);
+
+ private:
+ void OnRecvMsg(const uint8 *data, size_t dataSize);
+ DnDTransport* mTransport;
+};
+
+#endif // COPY_PASTE_RPC_V3_HH
#define FCP_COPY_DELAY 1000000 // 1 second
#define TARGET_NAME_TIMESTAMP "TIMESTAMP"
+#define TARGET_NAME_STRING "STRING"
+#define TARGET_NAME_TEXT_PLAIN "text/plain"
+#define TARGET_NAME_UTF8_STRING "UTF8_STRING"
+#define TARGET_NAME_COMPOUND_TEXT "COMPOUND_TEXT"
+#define TARGET_NAME_APPLICATION_RTF "application/rtf"
+#define TARGET_NAME_TEXT_RICHTEXT "text/richtext"
#define DRAG_TARGET_NAME_URI_LIST "text/uri-list"
#define DRAG_LEAVE_TIMEOUT 500
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dnd.hh --
+ *
+ * DnD protocol object.
+ */
+
+#ifndef DND_HH
+#define DND_HH
+
+#include <string>
+#include <sigc++/trackable.h>
+#include "dndBase.h"
+#include "dndRpc.hh"
+
+struct Event;
+struct DblLnkLst_Links;
+
+class DnD
+ : public DnDBase,
+ public sigc::trackable
+{
+ public:
+ DnD(DblLnkLst_Links *eventQueue);
+ virtual ~DnD(void);
+
+ /* Common DnD layer API exposed to UI (all platforms). */
+ /* Local UI as DnD source. */
+ virtual DND_DROPEFFECT GetFeedback(void) { return DROP_UNKNOWN; }
+ virtual void SourceCancel(void) {}
+ virtual void SourceDrop(DND_DROPEFFECT feedback) {}
+
+ /* Local UI as DnD target. */
+ virtual void DragEnter(const CPClipboard *clip);
+ virtual void SetMouse(int32 x, int32 y, bool down) {}
+ virtual void SetFeedback(DND_DROPEFFECT feedback);
+ virtual void DragLeave(int32 x, int32 y) {}
+ virtual void TargetCancel(void) {}
+ virtual void TargetDrop(const CPClipboard *clip,
+ int32 x,
+ int32 y) {}
+
+ virtual bool IsDnDAllowed(void) { return mDnDAllowed; }
+
+ void VmxDnDVersionChanged(struct RpcIn *rpcIn,
+ uint32 version);
+
+ void SetDnDAllowed(bool isDnDAllowed)
+ { mDnDAllowed = isDnDAllowed; }
+ void UngrabTimeout(void);
+ void ResetDnD(void);
+ void HGDragStartDone(void);
+
+ private:
+ /* Callbacks from rpc. */
+ void OnGHUpdateUnityDetWnd(bool bShow, uint32 unityWndId);
+ void OnGHQueryPendingDrag(int x, int y);
+ void OnGHCancel(void);
+ void OnHGDragEnter(const CPClipboard *clip);
+ void OnHGDragStart(void);
+ void OnHGCancel(void);
+ void OnHGDrop(void);
+ void OnHGFileCopyDone(bool cancel,
+ std::vector<uint8> stagingDir);
+
+ std::string SetupDestDir(const std::string &destDir);
+
+ DnDRpc *mRpc;
+ uint32 mVmxDnDVersion;
+ bool mDnDAllowed;
+ std::string mStagingDir;
+ Event *mUngrabTimeout;
+ DblLnkLst_Links *mEventQueue;
+};
+
+#endif // DND_HH
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dndBase.h --
+ *
+ * Base object for DnD. This is the common interface between UI and
+ * cui DnD protocol layer. Both host side and guest side, and also
+ * different platforms, share this same interface.
+ */
+
+#ifndef DND_BASE_H
+#define DND_BASE_H
+
+#include <sigc++/connection.h>
+#include <vector>
+
+#ifdef VMX86_TOOLS
+ /*
+ * LIB_EXPORT definition is not needed on guest.
+ */
+# define LIB_EXPORT
+#else
+ /*
+ * The interface class on host side for Windows is in dll which needs
+ * LIB_EXPORT definition.
+ */
+# include "libExport.hh"
+#endif
+
+extern "C" {
+#include "dnd.h"
+#include "unityCommon.h"
+}
+
+class LIB_EXPORT DnDBase
+{
+ public:
+ virtual ~DnDBase(void) {};
+
+ /* sigc signals for local UI callbacks. */
+ /* Local UI as DnD source. */
+ sigc::signal<void, const CPClipboard*> dragExitChanged;
+ sigc::signal<void> dndUngrabChanged; /* X11's notion of ungrab. */
+ sigc::signal<void, bool, std::vector<uint8> > fileCopyDoneChanged;
+ sigc::signal<void> sourceDropChanged;
+ sigc::signal<void> sourceCancelChanged;
+ sigc::signal<void, const CPClipboard*, std::string> dragStartChanged;
+
+ /* Local UI as DnD target. */
+ sigc::signal<void, DND_DROPEFFECT> updateFeedbackChanged;
+ sigc::signal<void, bool, int, int> updateDetWndChanged;
+ sigc::signal<void, bool, uint32> updateUnityDetWndChanged;
+
+ sigc::signal<void> reset;
+ sigc::signal<void> disable;
+ sigc::signal<void> enable;
+ /* cui DnD protocol layer API exposed to UI (all platforms). */
+
+ /* Local UI as DnD source. */
+ virtual void UpdateUnityDetWnd(bool bShow, uint32 unityWndId) {};
+ virtual void DragLeave(int32 x, int32 y) = 0;
+ virtual void SourceCancel(void) = 0;
+ virtual void SourceDrop(DND_DROPEFFECT feedback) = 0;
+
+ /* Local UI as DnD target. */
+ virtual void DragEnter(const CPClipboard* clip) = 0;
+ /* Host only. */
+ virtual void SetMouse(int32 x, int32 y, bool down = true) = 0;
+ /* Guest only. */
+ virtual void SetFeedback(DND_DROPEFFECT feedback) = 0;
+ virtual void TargetCancel(void) = 0;
+ virtual void TargetDrop(const CPClipboard *clip,
+ int32 x,
+ int32 y) = 0;
+
+ const CPClipboard* GetClipboard(void) { return &mClipboard; }
+
+ virtual bool IsDnDAllowed(void) = 0;
+
+ protected:
+ /*
+ * For details about state machine definition, please refer to
+ * https://wiki.eng.vmware.com/ToolsDnDV3FlowChart
+ */
+ enum DND_STATE {
+ DNDSTATE_INVALID = 0,
+ DNDSTATE_READY,
+ /* H->G */
+ DNDSTATE_ENTERING,
+ DNDSTATE_STARTING,
+ DNDSTATE_DRAGGING_INSIDE,
+ /* G->H */
+ DNDSTATE_QUERY_EXITING,
+ DNDSTATE_UNGRABING, // ask mks to ungrab, v2 only
+ DNDSTATE_DRAGGING_OUTSIDE,
+ DNDSTATE_DRAGGING_PRIVATE,
+ };
+
+ DND_STATE mState;
+ DND_DROPEFFECT mFeedback;
+ CPClipboard mClipboard;
+};
+
+#endif // DND_BASE_H
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+
+/*
+ * dndClipboard.h
+ *
+ * This file maintains an interface for the clipboard object. The object
+ * may contain several representations of the same object. For
+ * example, we could have a plain text filename as well as the file's
+ * contents on the clipboard at the same time.
+ *
+ * The purpose of this structure is to store cross platform clipboard
+ * data for further processing. The UI is responsible for converting local
+ * clipboard data to a crossplatform format and inserting it into the
+ * cross platform clipboard.
+ */
+
+#ifndef _DND_CLIPBOARD_H_
+#define _DND_CLIPBOARD_H_
+
+#include "vm_basic_types.h"
+
+#include "dnd.h"
+#include "dynbuf.h"
+
+/*
+ * Make sure each clipboard item is at most 64kb - 100 b. This limitation is
+ * copied from the current text copy paste limit.
+ */
+#define CPCLIPITEM_MAX_SIZE_V1 ((1 << 16) - 100)
+#define CPCLIPITEM_MAX_SIZE_V2 ((1 << 16) - 100)
+#define CPCLIPITEM_MAX_SIZE_V3 (DNDMSG_MAX_ARGSZ - 100)
+
+/* Cross platform formats */
+typedef
+#include "vmware_pack_begin.h"
+struct CPFileList {
+ uint64 fileSize;
+ uint32 relPathsLen;
+ uint32 fulPathsLen;
+ uint8 filelists[1];
+}
+#include "vmware_pack_end.h"
+CPFileList;
+
+#define CPFILELIST_HEADER_SIZE (1* sizeof(uint64) + 2 * sizeof(uint32))
+
+typedef
+#include "vmware_pack_begin.h"
+struct UriFileList {
+ uint64 fileSize;
+ uint32 uriPathsLen;
+ uint8 filelists[1];
+}
+#include "vmware_pack_end.h"
+UriFileList;
+
+#define URI_FILELIST_HEADER_SIZE (1* sizeof(uint64) + 1 * sizeof(uint32))
+
+/* Types which can be stored on the clipboard. */
+/*
+ * XXX
+ * This is currently in dnd.h, but should be moved over to dndClipboard.h
+ * Ling's vmx code reorg should handle this.
+ */
+/*
+typedef enum
+{
+ CPFORMAT_UNKNOWN = 0
+ CPFORMAT_TEXT,
+ CPFORMAT_FILELIST,
+ CPFORMAT_MAX,
+} DND_CPFORMAT;
+*/
+
+#define CPFORMAT_MIN CPFORMAT_TEXT
+
+/* CPClipboard */
+void CPClipboard_Init(CPClipboard *clip);
+void CPClipboard_Destroy(CPClipboard *clip);
+
+void CPClipboard_Clear(CPClipboard *clip);
+Bool CPClipboard_SetItem(CPClipboard *clip, const DND_CPFORMAT fmt, const void *buf,
+ const size_t size);
+void CPClipboard_SetChanged(CPClipboard *clip, Bool changed);
+Bool CPClipboard_Changed(const CPClipboard *clip);
+Bool CPClipboard_ClearItem(CPClipboard *clip, DND_CPFORMAT fmt);
+Bool CPClipboard_GetItem(const CPClipboard *clip, DND_CPFORMAT fmt,
+ void **buf, size_t *size);
+Bool CPClipboard_ItemExists(const CPClipboard *clip, DND_CPFORMAT fmt);
+Bool CPClipboard_IsEmpty(const CPClipboard *clip);
+Bool CPClipboard_Copy(CPClipboard *dest, const CPClipboard *src);
+Bool CPClipboard_Serialize(const CPClipboard *clip, DynBuf *buf);
+Bool CPClipboard_Unserialize(CPClipboard *clip, void *buf, size_t len);
+
+#endif // _DND_CLIPBOARD_H_
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+
+/*
+ * dndFileContentsUtil.h
+ *
+ * Helper functions for format conversion for file contents.
+ */
+
+#ifndef _DND_FILE_CONTENTS_UTIL_H_
+#define _DND_FILE_CONTENTS_UTIL_H_
+
+#include "guestrpc/cpFileContents.h"
+
+#define CP_FILE_VALID_NONE 0
+#define CP_FILE_VALID_TYPE (1 << 0)
+#define CP_FILE_VALID_SIZE (1 << 1)
+#define CP_FILE_VALID_CREATE_TIME (1 << 2)
+#define CP_FILE_VALID_ACCESS_TIME (1 << 3)
+#define CP_FILE_VALID_WRITE_TIME (1 << 4)
+#define CP_FILE_VALID_CHANGE_TIME (1 << 5)
+#define CP_FILE_VALID_PERMS (1 << 6)
+#define CP_FILE_VALID_ATTR (1 << 7)
+#define CP_FILE_VALID_NAME (1 << 8)
+#define CP_FILE_VALID_CONTENT (1 << 9)
+
+#define CP_FILE_ATTR_NONE 0
+#define CP_FILE_ATTR_HIDDEN (1 << 0)
+#define CP_FILE_ATTR_SYSTEM (1 << 1)
+#define CP_FILE_ATTR_ARCHIVE (1 << 2)
+#define CP_FILE_ATTR_HIDDEN_FORCED (1 << 3)
+#define CP_FILE_ATTR_READONLY (1 << 4)
+
+#define CP_FILE_TYPE_REGULAR 1
+#define CP_FILE_TYPE_DIRECTORY 2
+#define CP_FILE_TYPE_SYMLINK 3
+
+#ifdef _WIN32
+
+#include <shlobj.h>
+
+FILEGROUPDESCRIPTORA *DnD_GroupDescWToGroupDescA(FILEGROUPDESCRIPTORW *groupDescW);
+Bool DnD_FileDescAToCPFileContents(FILEDESCRIPTORA *fileDescA,
+ CPFileItem* cpItem);
+Bool DnD_CPFileContentsToFileDescA(CPFileItem* cpItem,
+ FILEDESCRIPTORA *fileDescA,
+ Bool processName);
+Bool DnD_CPFileContentsToFileDescW(CPFileItem* cpItem,
+ FILEDESCRIPTORW *fileDescW);
+#endif // _WIN32
+
+#endif // _DND_FILE_CONTENTS_UTIL_H_
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dndFileList.hh
+ *
+ * Translates filelists to different formats.
+ */
+
+#ifndef DND_FILELIST_HH
+#define DND_FILELIST_HH
+
+#include <string>
+#include <vector>
+
+extern "C" {
+#include "vm_basic_types.h"
+#include "dynbuf.h"
+}
+
+class DnDFileList {
+ public:
+ DnDFileList();
+ ~DnDFileList() {};
+
+ void SetFileSize(uint64 fsize);
+ uint64 GetFileSize() const;
+ void AddFile(const std::string fullPath,
+ const std::string relPath);
+ void AddFileUri(const std::string uriPath);
+ void AddFiles(const std::vector<std::string> fullPathList,
+ const std::vector<std::string> relPathList);
+
+ /* Copy paste/dndV2 V2 rpc */
+ void SetRelPathsStr(const std::string inpath);
+
+ /* DnDFileTransfer & V2 RPC */
+ std::string GetRelPathsStr() const;
+ std::string GetFullPathsStr(bool local) const;
+ std::string GetUriPathsStr() const;
+
+ /* UI Local clipboard */
+ std::vector<std::string> GetRelPaths() const;
+
+ /* CPClipboard */
+ bool ToCPClipboard(DynBuf *out, bool local) const;
+ bool ToUriClipboard(DynBuf *out) const;
+ bool FromCPClipboard(const void *buf, size_t len);
+
+ void Clear();
+
+ private:
+
+ std::vector<std::string> mRelPaths;
+ std::vector<std::string> mFullPaths;
+ std::vector<std::string> mUriPaths;
+ std::string mFullPathsBinary;
+ uint64 mFileSize;
+};
+
+#endif // DND_FILELIST_HH
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dndMsg.h --
+ *
+ * DnDMsg represents an rpc message which is sent across the
+ * wire. Any args that it holds will be written out exactly as stored.
+ */
+
+#ifndef _DNDMSG_H_
+#define _DNDMSG_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+
+#include "includeCheck.h"
+#include "vm_basic_types.h"
+
+#include "dynbuf.h"
+#include "dynarray.h"
+#include "dnd.h"
+
+/* Various return types serialization/unserialization functions can return. */
+
+typedef enum {
+ DNDMSG_SUCCESS = 0,
+ DNDMSG_ERR,
+ DNDMSG_NOMEM,
+ DNDMSG_INPUT_TOO_SMALL, /* Input buffer needs to be bigger. */
+ DNDMSG_INPUT_ERR, /* Serialize/unserialized failed sanity checks. */
+} DnDMsgErr;
+
+/*
+ * DnD Commands.
+ */
+
+typedef enum {
+ DND_INVALID = 0,
+
+ /*
+ * We need to send mouse packets for old protocols because old guest tools
+ * manipulate the mouse directly, but in DnD Version 3+, the host controls the
+ * mouse pointer via foundry.
+ */
+ /* DnD Ver 1/2 Commands */
+ DND_HG_SEND_MOUSE_PACKET,
+
+ /* DnD version 3 commands */
+ // GHDnD (h->g)
+ DND_GH_QUERY_PENDING_DRAG,
+ DND_GH_CANCEL,
+ DND_GH_COPY_DONE,
+ // GHDnD (g->h)
+ DND_GH_DRAG_ENTER,
+ DND_GH_NOT_PENDING,
+
+ // HGDnD (h->g)
+ DND_HG_DRAG_ENTER,
+ DND_HG_DRAG_START,
+ DND_HG_CANCEL,
+ DND_HG_DROP,
+ DND_HG_FILE_COPY_DONE,
+ // HGDnD (g->h)
+ DND_HG_DRAG_ENTER_DONE,
+ DND_HG_DRAG_READY,
+ DND_HG_UPDATE_FEEDBACK,
+ DND_HG_DROP_DONE,
+ DND_HG_START_FILE_COPY,
+
+ // Add future commands here.
+ DND_GH_UPDATE_UNITY_DET_WND,
+ DND_MAX,
+} DnDCommand;
+
+/*
+ * Copy/Paste commands.
+ */
+
+typedef enum {
+ CP_INVALID = 0,
+
+ /* DnD version 3 commands. */
+ // GHCopyPaste (h->g)
+ CP_GH_GET_CLIPBOARD,
+ // GHCopyPaste (g->h)
+ CP_GH_GET_CLIPBOARD_DONE, // FORMAT DATA(property list?)
+
+ // HGCopyPaste (h->g)
+ CP_HG_SET_CLIPBOARD,
+ CP_HG_FILE_COPY_DONE,
+ // HGCopyPaste(g->h)
+ CP_HG_START_FILE_COPY,
+
+ // Add future commands here.
+ CP_MAX,
+} CopyPasteCommand;
+
+/*
+ * Opaque data structure.
+ * Members are listed in order of unserialization.
+ */
+
+typedef struct DnDMsg {
+ /* Header */
+ uint8 ver; // Must be first across all versions.
+ uint32 cmd;
+ uint32 nargs;
+ /* The expected size of the buffer needed to unserialize the arguments. */
+ uint32 expectedArgsSz;
+
+ /* Body */
+ DynBufArray args;
+} DnDMsg;
+
+#define DnDMsg_Success(x) ((x) == DNDMSG_SUCCESS)
+
+void DnDMsg_Init(DnDMsg *msg);
+void DnDMsg_Destroy(DnDMsg *msg);
+
+/* Header information. */
+uint32 DnDMsg_GetCmd(DnDMsg *msg);
+void DnDMsg_SetCmd(DnDMsg *msg, uint32 cmd);
+uint32 DnDMsg_NumArgs(DnDMsg *msg);
+
+DynBuf *DnDMsg_GetArg(DnDMsg *msg, uint32 arg);
+
+Bool DnDMsg_AppendArg(DnDMsg *msg, void *buf, size_t len);
+Bool DnDMsg_Serialize(DnDMsg *msg, DynBuf *buf);
+
+DnDMsgErr DnDMsg_UnserializeHeader(DnDMsg *msg, void *buf, size_t len);
+DnDMsgErr DnDMsg_UnserializeArgs(DnDMsg *msg, void *buf, size_t len);
+
+#endif /* _DNDMSG_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dndRpc.hh --
+ *
+ * Rpc layer object for DnD.
+ */
+
+#ifndef DND_RPC_HH
+#define DND_RPC_HH
+
+#include <sigc++/connection.h>
+#include <vector>
+#include "vm_basic_types.h"
+
+extern "C" {
+ #include "dndClipboard.h"
+}
+
+class DnDRpc
+{
+ public:
+ virtual ~DnDRpc(void) {};
+
+ /* sigc signals for callback. */
+ sigc::signal<void, bool, uint32> ghUpdateUnityDetWndChanged;
+ sigc::signal<void, int, int> ghQueryPendingDragChanged;
+ sigc::signal<void> ghCancelChanged;
+ sigc::signal<void, const CPClipboard*> hgDragEnterChanged;
+ sigc::signal<void> hgDragStartChanged;
+ sigc::signal<void> hgCancelChanged;
+ sigc::signal<void> hgDropChanged;
+ sigc::signal<void, bool, const std::vector<uint8> > hgFileCopyDoneChanged;
+
+ /* GH DnD. */
+ virtual bool GHDragEnter(const CPClipboard *clip) = 0;
+ virtual bool GHUngrabTimeout(void) = 0;
+
+ /* HG DnD. */
+ virtual bool HGDragEnterDone(int32 x, int32 y) = 0;
+ virtual bool HGDragStartDone(void) = 0;
+ virtual bool HGUpdateFeedback(DND_DROPEFFECT feedback) = 0;
+ virtual bool HGDropDone(const char *stagingDirCP, size_t sz) = 0;
+};
+
+#endif // DND_RPC_HH
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dndRpcV3.hh --
+ *
+ * Rpc layer object for DnD version 3.
+ */
+
+#ifndef DND_RPC_V3_HH
+#define DND_RPC_V3_HH
+
+#include <sigc++/trackable.h>
+#include "dndRpc.hh"
+#include "dndTransport.hh"
+
+extern "C" {
+ #include "dnd.h"
+ #include "dndMsg.h"
+}
+
+class DnDRpcV3
+ : public DnDRpc,
+ public sigc::trackable
+{
+ public:
+ DnDRpcV3(struct RpcIn *rpcIn);
+ virtual ~DnDRpcV3(void);
+
+ /* DnD functions. */
+ /* GH DnD. */
+ virtual bool GHDragEnter(const CPClipboard *clip);
+ virtual bool GHUngrabTimeout(void);
+
+ /* HG DnD. */
+ virtual bool HGDragEnterDone(int32 x, int32 y);
+ virtual bool HGDragStartDone(void);
+ virtual bool HGUpdateFeedback(DND_DROPEFFECT feedback);
+ virtual bool HGDropDone(const char *stagingDirCP, size_t sz);
+
+ private:
+ void OnRecvMsg(const uint8 *data, size_t dataSize);
+ bool SendSingleCmd(DnDCommand cmd);
+ bool SendCmdWithClip(DnDCommand cmd, const CPClipboard *clip);
+
+ DnDTransport *mTransport;
+};
+
+#endif // DND_RPC_V3_HH
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dndTransport.hh --
+ *
+ * DnDTransport provides a data transportation interface for both dnd and copyPaste.
+ */
+
+#ifndef DND_TRANSPORT_HH
+#define DND_TRANSPORT_HH
+
+#include <sigc++/connection.h>
+#include <sigc++/slot.h>
+
+#include "vm_basic_types.h"
+
+class DnDTransport
+{
+public:
+ virtual ~DnDTransport() {};
+
+ /* sigc signals for RecvMsg. */
+ sigc::signal<void, const uint8 *, size_t> recvMsgChanged;
+
+ virtual bool SendMsg(uint8 *msg,
+ size_t length) = 0;
+};
+
+#endif // DND_TRANSPORT_HH
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dndTransportGuestRpc.hh --
+ *
+ * GuestRpc implementation of the dndTransport interface.
+ */
+
+
+#ifndef DND_TRANSPORT_GUEST_RPC_HH
+#define DND_TRANSPORT_GUEST_RPC_HH
+
+#include <sigc++/trackable.h>
+#include "dndTransport.hh"
+
+extern "C" {
+ #include "dnd.h"
+}
+
+class DnDTransportGuestRpc
+ : public DnDTransport,
+ public sigc::trackable
+{
+public:
+ DnDTransportGuestRpc(struct RpcIn *rpcIn,
+ const char *rpcCmd);
+ virtual ~DnDTransportGuestRpc(void);
+
+ virtual bool SendMsg(uint8 *msg,
+ size_t length);
+ void RecvMsg(DnDTransportPacketHeader *packet,
+ size_t packetSize);
+
+private:
+ char *mRpcCmd;
+ struct RpcIn *mRpcIn;
+
+ DnDTransportBuffer mSendBuf;
+ DnDTransportBuffer mRecvBuf;
+ uint32 mSeqNum;
+
+ bool SendPacket(uint8 *packet,
+ size_t packetSize);
+};
+
+#endif // DND_TRANSPORT_GUEST_RPC_HH
int64 FileIO_GetSizeByPath(ConstUnicode pathName);
-int FileIO_Close(FileIODescriptor *file);
+Bool FileIO_Close(FileIODescriptor *file);
uint32 FileIO_GetFlags(FileIODescriptor *file);
char *
GuestApp_GetLogPath(void);
-char *
-GuestApp_GetCmdOutput(const char *cmd); // IN
-
Bool
GuestApp_IsHgfsCapable(void);
GUEST_OS_SOLARIS10 = GUEST_OS_BASE + 35,
GUEST_OS_SOLARIS10_64 = GUEST_OS_BASE + 36,
GUEST_OS_VMKERNEL = GUEST_OS_BASE + 37,
- GUEST_OS_DARWIN = GUEST_OS_BASE + 38,
- GUEST_OS_DARWIN_64 = GUEST_OS_BASE + 39,
- GUEST_OS_OPENSERVER5 = GUEST_OS_BASE + 40,
- GUEST_OS_OPENSERVER6 = GUEST_OS_BASE + 41,
- GUEST_OS_UNIXWARE7 = GUEST_OS_BASE + 42,
- GUEST_OS_DEBIAN45 = GUEST_OS_BASE + 43,
- GUEST_OS_DEBIAN45_64 = GUEST_OS_BASE + 44,
+ GUEST_OS_DARWIN9 = GUEST_OS_BASE + 38, // Mac OS 10.5
+ GUEST_OS_DARWIN9_64 = GUEST_OS_BASE + 39,
+ GUEST_OS_DARWIN10 = GUEST_OS_BASE + 40, // Mac OS 10.6
+ GUEST_OS_DARWIN10_64 = GUEST_OS_BASE + 41,
+ GUEST_OS_OPENSERVER5 = GUEST_OS_BASE + 42,
+ GUEST_OS_OPENSERVER6 = GUEST_OS_BASE + 43,
+ GUEST_OS_UNIXWARE7 = GUEST_OS_BASE + 44,
+ GUEST_OS_DEBIAN45 = GUEST_OS_BASE + 45,
+ GUEST_OS_DEBIAN45_64 = GUEST_OS_BASE + 46,
} GuestOSType;
BS(OTHERLINUX) | ALL26XLINUX32)
#define ALLLINUX64 (BS(OTHERLINUX_64) | BS(OTHER24XLINUX_64) | ALL26XLINUX64)
#define ALLLINUX (ALLLINUX32 | ALLLINUX64)
-#define ALLDARWIN (BS(DARWIN) | BS(DARWIN_64))
+#define ALLDARWIN32 (BS(DARWIN9) | BS(DARWIN10))
+#define ALLDARWIN64 (BS(DARWIN9_64) | BS(DARWIN10_64))
+#define ALLDARWIN (ALLDARWIN32 | ALLDARWIN64)
#define ALL64 (ALLWIN64 | ALLLINUX64 | \
BS(SOLARIS10_64) | BS(FREEBSD_64) | \
- BS(DARWIN_64) | BS(OTHER_64))
+ ALLDARWIN64 | BS(OTHER_64))
/*
#define STR_OS_WIN_2008_ENTERPRISE_CORE_FULL "Windows Server 2008 Enterprise Edition (core installation)"
#define STR_OS_WIN_2008_ENTERPRISE_ITANIUM "winServer2008EnterpriseItanium-32"
#define STR_OS_WIN_2008_ENTERPRISE_ITANIUM_FULL "Windows Server 2008 Enterprise Edition for Itanium-based Systems"
+#define STR_OS_WIN_2008_MEDIUM_MANAGEMENT "winServer2008MediumManagement-32"
+#define STR_OS_WIN_2008_MEDIUM_MANAGEMENT_FULL "Windows Essential Business Server Management Server"
+#define STR_OS_WIN_2008_MEDIUM_MESSAGING "winServer2008MediumMessaging-32"
+#define STR_OS_WIN_2008_MEDIUM_MESSAGING_FULL "Windows Essential Business Server Messaging Server"
+#define STR_OS_WIN_2008_MEDIUM_SECURITY "winServer2008MediumSecurity-32"
+#define STR_OS_WIN_2008_MEDIUM_SECURITY_FULL "Windows Essential Business Server Security Server"
+#define STR_OS_WIN_2008_SERVER_FOR_SMALLBUSINESS "winServer2008ForSmallBusiness-32"
+#define STR_OS_WIN_2008_SERVER_FOR_SMALLBUSINESS_FULL "Windows Server 2008 for Windows Essential Server Solutions"
#define STR_OS_WIN_2008_SMALL_BUSINESS "winServer2008SmallBusiness-32"
#define STR_OS_WIN_2008_SMALL_BUSINESS_FULL "Windows Server 2008 Small Business Server"
#define STR_OS_WIN_2008_SMALL_BUSINESS_PREMIUM "winServer2008SmallBusinessPremium-32"
#define STR_OS_WIN_2008_STANDARD_FULL "Windows Server 2008 Standard Edition"
#define STR_OS_WIN_2008_STANDARD_CORE "winServer2008StandardCore-32"
#define STR_OS_WIN_2008_STANDARD_CORE_FULL "Windows Server 2008 Standard Edition (core installation)"
+#define STR_OS_WIN_2008_STORAGE_ENTERPRISE "winServer2008StorageEnterprise-32"
+#define STR_OS_WIN_2008_STORAGE_ENTERPRISE_FULL "Windows Server 2008 Storage Server Enterprise"
+#define STR_OS_WIN_2008_STORAGE_EXPRESS "winServer2008StorageExpress-32"
+#define STR_OS_WIN_2008_STORAGE_EXPRESS_FULL "Windows Server 2008 Storage Server Express"
+#define STR_OS_WIN_2008_STORAGE_STANDARD "winServer2008StorageStandard-32"
+#define STR_OS_WIN_2008_STORAGE_STANDARD_FULL "Windows Server 2008 Storage Server Standard"
+#define STR_OS_WIN_2008_STORAGE_WORKGROUP "winServer2008StorageWorkgroup-32"
+#define STR_OS_WIN_2008_STORAGE_WORKGROUP_FULL "Windows Server 2008 Storage Server Workgroup"
#define STR_OS_WIN_2008_WEB_SERVER "winServer2008Web-32"
#define STR_OS_WIN_2008_WEB_SERVER_FULL "Windows Server 2008 Web Server Edition"
+
+/* Windows 64-bit */
#define STR_OS_WIN_VISTA_ULTIMATE_X64 "winVistaUltimate-64"
#define STR_OS_WIN_VISTA_HOME_PREMIUM_X64 "winVistaHomePremium-64"
#define STR_OS_WIN_VISTA_HOME_BASIC_X64 "winVistaHomeBasic-64"
#define STR_OS_WIN_2008_ENTERPRISE_X64 "winServer2008Enterprise-64"
#define STR_OS_WIN_2008_ENTERPRISE_CORE_X64 "winServer2008EnterpriseCore-64"
#define STR_OS_WIN_2008_ENTERPRISE_ITANIUM_X64 "winServer2008EnterpriseItanium-64"
+#define STR_OS_WIN_2008_MEDIUM_MANAGEMENT_X64 "winServer2008MediumManagement-64"
+#define STR_OS_WIN_2008_MEDIUM_MESSAGING_X64 "winServer2008MediumMessaging-64"
+#define STR_OS_WIN_2008_MEDIUM_SECURITY_X64 "winServer2008MediumSecurity-64"
+#define STR_OS_WIN_2008_SERVER_FOR_SMALLBUSINESS_X64 "winServer2008ForSmallBusiness-64"
#define STR_OS_WIN_2008_SMALL_BUSINESS_X64 "winServer2008SmallBusiness-64"
#define STR_OS_WIN_2008_SMALL_BUSINESS_PREMIUM_X64 "winServer2008SmallBusinessPremium-64"
#define STR_OS_WIN_2008_STANDARD_X64 "winServer2008Standard-64"
#define STR_OS_WIN_2008_STANDARD_CORE_X64 "winServer2008StandardCore-64"
+#define STR_OS_WIN_2008_STORAGE_ENTERPRISE_X64 "winServer2008StorageEnterprise-64"
+#define STR_OS_WIN_2008_STORAGE_EXPRESS_X64 "winServer2008StorageExpress-64"
+#define STR_OS_WIN_2008_STORAGE_STANDARD_X64 "winServer2008StorageStandard-64"
+#define STR_OS_WIN_2008_STORAGE_WORKGROUP_X64 "winServer2008StorageWorkgroup-64"
#define STR_OS_WIN_2008_WEB_SERVER_X64 "winServer2008Web-64"
+/* XXX */
+#define STR_OS_HYPERV "winHyperV"
+#define STR_OS_HYPERV_FULL "Hyper-V Server"
+
/* Modifiers for Windows Vista and Windows Server 2008 */
#define STR_OS_WIN_32_BIT_EXTENSION ", 32-bit"
#define STR_OS_WIN_64_BIT_EXTENSION ", 64-bit"
#define HGFS_PERM_WRITE 2
#define HGFS_PERM_EXEC 1
+/*
+ * Access mode bits.
+ *
+ * Different operating systems have different set of file access mode.
+ * Here are constants that are rich enough to describe all access modes in an OS
+ * independent way.
+ */
+
+typedef uint32 HgfsAccessMode;
+/*
+ * Generic access rights control coarse grain access for the file.
+ * A particular generic rigth can be expanded into different set of specific rights
+ * on different OS.
+ */
+
+/*
+ * HGFS_MODE_GENERIC_READ means ability to read file data and read various file
+ * attributes and properties.
+ */
+#define HGFS_MODE_GENERIC_READ (1 << 0)
+/*
+ * HGFS_MODE_GENERIC_WRITE means ability to write file data and updaate various file
+ * attributes and properties.
+ */
+#define HGFS_MODE_GENERIC_WRITE (1 << 1)
+/*
+ * HGFS_MODE_GENERIC_EXECUE means ability to execute file. For network redirectors
+ * ability to execute usualy implies ability to read data; for local file systems
+ * HGFS_MODE_GENERIC_EXECUTE does not imply ability to read data.
+ */
+#define HGFS_MODE_GENERIC_EXECUTE (1 << 2)
+
+/* Specific rights define fine grain access modes. */
+#define HGFS_MODE_READ_DATA (1 << 3) // Ability to read file data
+#define HGFS_MODE_WRITE_DATA (1 << 4) // Ability to writge file data
+#define HGFS_MODE_APPEND_DATA (1 << 5) // Appending data to the end of file
+#define HGFS_MODE_DELETE (1 << 6) // Ability to delete the file
+#define HGFS_MODE_TRAVERSE_DIRECTORY (1 << 7) // Ability to access files in a directory
+#define HGFS_MODE_LIST_DIRECTORY (1 << 8) // Ability to list file names
+#define HGFS_MODE_ADD_SUBDIRECTORY (1 << 9) // Ability to create a new subdirectory
+#define HGFS_MODE_ADD_FILE (1 << 10) // Ability to create a new file
+#define HGFS_MODE_DELETE_CHILD (1 << 11) // Ability to delete file/subdirectory
+#define HGFS_MODE_READ_ATTRIBUTES (1 << 12) // Ability to read attributes
+#define HGFS_MODE_WRITE_ATTRIBUTES (1 << 13) // Ability to write attributes
+#define HGFS_MODE_READ_EXTATTRIBUTES (1 << 14) // Ability to read extended attributes
+#define HGFS_MODE_WRITE_EXTATTRIBUTES (1 << 15) // Ability to write extended attributes
+#define HGFS_MODE_READ_SECURITY (1 << 16) // Ability to read permissions/ACLs/owner
+#define HGFS_MODE_WRITE_SECURITY (1 << 17) // Ability to change permissions/ACLs
+#define HGFS_MODE_TAKE_OWNERSHIP (1 << 18) // Ability to change file owner/group
/*
* Server-side locking (oplocks and leases).
* only to determine if the ID is valid.
*/
#define HGFS_ATTR_VALID_NON_STATIC_FILEID (1 << 16)
+/*
+ * File permissions that are in effect for the user which runs HGFS server.
+ * Client needs to know effective permissions in order to implement access(2).
+ * Client can't derive it from group/owner/other permissions because of two resaons:
+ * 1. It does not know user/group id of the user which runs HGFS server
+ * 2. Effective permissions account for additional restrictions that may be imposed
+ * by host file system, for example by ACL.
+ */
+#define HGFS_ATTR_VALID_EFFECTIVE_PERMS (1 << 17)
/*
uint32 groupId; /* group identifier, ignored by Windows */
uint64 hostFileId; /* File Id of the file on host: inode_t on Linux */
uint32 volumeId; /* volume identifier, non-zero is valid. */
- uint32 reserved1; /* Reserved for future use */
+ uint32 effectivePerms; /* Permissions in effect for the user on the host. */
uint64 reserved2; /* Reserved for future use */
}
#include "vmware_pack_end.h"
extern int Hostinfo_OSVersion(int i);
extern int Hostinfo_GetSystemBitness(void);
extern const char *Hostinfo_OSVersionString(void);
+
+extern Bool Hostinfo_GetOSName(uint32 outBufFullLen,
+ uint32 outBufLen,
+ char *osNameFull,
+ char *osName);
+
extern Bool Hostinfo_OSIsSMP(void);
#if defined(_WIN32)
extern Bool Hostinfo_OSIsWinNT(void);
#endif
#if defined(_WIN32)
+typedef enum {
+ OS_WIN95 = 1,
+ OS_WIN98 = 2,
+ OS_WINME = 3,
+ OS_WINNT = 4,
+ OS_WIN2K = 5,
+ OS_WINXP = 6,
+ OS_WIN2K3 = 7,
+ OS_VISTA = 8,
+ OS_UNKNOWN = 99999 // last, highest value
+} OS_TYPE;
+
+typedef enum {
+ OS_DETAIL_WIN95 = 1,
+ OS_DETAIL_WIN98 = 2,
+ OS_DETAIL_WINME = 3,
+ OS_DETAIL_WINNT = 4,
+ OS_DETAIL_WIN2K = 5,
+ OS_DETAIL_WIN2K_PRO = 6,
+ OS_DETAIL_WIN2K_SERV = 7,
+ OS_DETAIL_WIN2K_ADV_SERV = 8,
+ OS_DETAIL_WINXP = 9,
+ OS_DETAIL_WINXP_HOME = 10,
+ OS_DETAIL_WINXP_PRO = 11,
+ OS_DETAIL_WINXP_X64_PRO = 12,
+ OS_DETAIL_WIN2K3 = 13,
+ OS_DETAIL_WIN2K3_WEB = 14,
+ OS_DETAIL_WIN2K3_ST = 15,
+ OS_DETAIL_WIN2K3_EN = 16,
+ OS_DETAIL_WIN2K3_BUS = 17,
+ OS_DETAIL_VISTA = 18,
+ OS_DETAIL_UNKNOWN = 99999 // last, highest value
+} OS_DETAIL_TYPE;
+
+/* generic names (to protect the future) but Windows specific for now */
+OS_TYPE Hostinfo_GetOSType(void);
+OS_DETAIL_TYPE Hostinfo_GetOSDetailType(void);
+
Bool Hostinfo_GetPCFrequency(uint64 *pcHz);
Bool Hostinfo_GetMhzOfProcessor(int32 processorNumber,
uint32 *currentMhz, uint32 *maxMhz);
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * libExport.hh --
+ *
+ * Declares proper decorations for dll-export interface
+ * for all modules in libs.
+ */
+
+#ifndef LIB_EXPORT_HH
+#define LIB_EXPORT_HH
+
+#ifdef _WIN32
+ #ifdef LIB_EXPORT_SOURCE
+ #define LIB_EXPORT __declspec(dllexport)
+ #else
+ #define LIB_EXPORT __declspec(dllimport)
+ #endif
+
+ #ifdef LIB_EXPORT_WUI_SOURCE
+ #define LIB_EXPORT_WUI __declspec(dllexport)
+ #else
+ #define LIB_EXPORT_WUI __declspec(dllimport)
+ #endif
+
+ #ifdef VMSTRING_EXPORT_SOURCE
+ #define VMSTRING_EXPORT __declspec(dllexport)
+ #else
+ #define VMSTRING_EXPORT __declspec(dllimport)
+ #endif
+#else
+ #define LIB_EXPORT
+ #define LIB_EXPORT_WUI
+ #define VMSTRING_EXPORT
+#endif // WIN32
+
+#endif // LIB_EXPORT_HH
typedef void (LogBasicFunc)(const char *fmt, va_list args);
-struct LogState;
-
typedef struct
{
const char *fileName; // File name, if known
# undef Bool
typedef Display * InitHandle;
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) || defined(RESOLUTION_WIN32)
typedef void * InitHandle;
#else
# error Unknown display backend
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _RPCCHANNEL_H_
+#define _RPCCHANNEL_H_
+
+/**
+ * @file rpcChannel.h
+ *
+ * Defines the interface between applications and the underlying GuestRPC
+ * channel. The goal is to have an abstraction so applications can run over
+ * the backdoor, VMCI sockets or TCP/IP sockets by just picking up the
+ * desired channel at runtime, without the need to modify the code.
+ *
+ * For this reason, the behavior of all channels is modeled after the RpcIn
+ * channel currently used in Tools, so the socket-based channels won't
+ * provide much better functionality than what the backdoor provides (aside
+ * from being interrupt-based rather than poll-based).
+ *
+ * @addtogroup vmtools_guestrpc
+ * @{
+ */
+
+#if !defined(VMTOOLS_USE_GLIB)
+# error "This library needs to be compiled with VMTOOLS_USE_GLIB."
+#endif
+
+#include <rpc/rpc.h>
+#include "vm_basic_types.h"
+#include "rpcin.h"
+
+struct RpcChannel;
+
+/** Defines the registration data for a GuestRPC application. */
+typedef struct RpcChannelCallback {
+ /** String identifying the RPC message. */
+ const char *name;
+ /** Function to call when data arrives. */
+ RpcIn_Callback callback;
+ /** Data to provide to callback function. */
+ gpointer clientData;
+ /** If not NULL, the input data will be deserialized using this function. */
+ gpointer xdrIn;
+ /**
+ * If not NULL, the output data will be serialized using this function. The
+ * output data should be stored in the @a result field of the RpcInData
+ * structure, and should have been allocated with glib's @a g_malloc() if
+ * @a freeResult is TRUE.
+ */
+ gpointer xdrOut;
+ /**
+ * If xdrIn is not NULL, this should be the amount of memory to allocate
+ * for deserializing the input data.
+ */
+ size_t xdrInSize;
+} RpcChannelCallback;
+
+
+typedef Bool (*RpcChannelStartFn)(struct RpcChannel *);
+typedef Bool (*RpcChannelStopFn)(struct RpcChannel *);
+typedef Bool (*RpcChannelShutdownFn)(struct RpcChannel *);
+typedef Bool (*RpcChannelSendFn)(struct RpcChannel *,
+ char *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen);
+
+
+/**
+ * Signature for the callback function called after a channel reset.
+ *
+ * @param[in] chan The RPC channel.
+ * @param[in] success Whether reset was successful.
+ * @param[in] data Client data.
+ */
+typedef void (*RpcChannelResetCb)(struct RpcChannel *chan,
+ gboolean success,
+ gpointer data);
+
+
+/** Defines the interface between the application and the RPC channel. */
+typedef struct RpcChannel {
+ RpcChannelStartFn start;
+ RpcChannelStopFn stop;
+ RpcChannelSendFn send;
+ /* Private section: don't use the fields below directly. */
+ RpcChannelShutdownFn shutdown;
+ gchar *appName;
+ GHashTable *rpcs;
+ GMainContext *mainCtx;
+ GSource *resetCheck;
+ gpointer appCtx;
+ RpcChannelCallback resetReg;
+ RpcChannelResetCb resetCb;
+ gpointer resetData;
+ gboolean rpcError;
+ guint rpcErrorCount;
+ gpointer _private;
+} RpcChannel;
+
+
+/**
+ * Wrapper for the send function of an RPC channel struct.
+ *
+ * @param[in] chan The RPC channel instance.
+ * @param[in] data Data to send.
+ * @param[in] dataLen Number of bytes to send.
+ * @param[out] result Response from other side.
+ * @param[out] resultLen Number of bytes in response.
+ *
+ * @return The status from the remote end (TRUE if call was successful).
+ */
+
+static INLINE Bool
+RpcChannel_Send(RpcChannel *chan,
+ char *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen)
+{
+ return chan->send(chan, data, dataLen, result, resultLen);
+}
+
+Bool
+RpcChannel_BuildXdrCommand(const char *cmd,
+ void *xdrProc,
+ void *xdrData,
+ char **result,
+ size_t *resultLen);
+
+gboolean
+RpcChannel_Destroy(RpcChannel *chan);
+
+Bool
+RpcChannel_Dispatch(RpcInData *data);
+
+void
+RpcChannel_Setup(RpcChannel *chan,
+ const gchar *appName,
+ GMainContext *mainCtx,
+ gpointer appCtx,
+ RpcChannelResetCb resetCb,
+ gpointer resetData);
+
+void
+RpcChannel_RegisterCallback(RpcChannel *chan,
+ RpcChannelCallback *rpc);
+
+void
+RpcChannel_UnregisterCallback(RpcChannel *chan,
+ RpcChannelCallback *rpc);
+
+
+RpcChannel *
+RpcChannel_NewBackdoorChannel(GMainContext *mainCtx);
+
+/** @} */
+
+#endif
+
void System_Shutdown(Bool reboot);
Bool System_IsUserAdmin(void);
-char *System_GetEnv(Bool global, char *valueName);
-int System_SetEnv(Bool global, char *valueName, char *value);
+char *System_GetEnv(Bool global, const char *valueName);
+int System_SetEnv(Bool global, const char *valueName, const char *value);
#ifdef _WIN32
-typedef enum {
- OS_WIN95 = 1,
- OS_WIN98 = 2,
- OS_WINME = 3,
- OS_WINNT = 4,
- OS_WIN2K = 5,
- OS_WINXP = 6,
- OS_WIN2K3 = 7,
- OS_VISTA = 8,
- OS_UNKNOWN = 9
-} OS_TYPE;
-
-typedef enum {
- OS_DETAIL_WIN95 = 1,
- OS_DETAIL_WIN98 = 2,
- OS_DETAIL_WINME = 3,
- OS_DETAIL_WINNT = 4,
- OS_DETAIL_WIN2K = 5,
- OS_DETAIL_WIN2K_PRO = 6,
- OS_DETAIL_WIN2K_SERV = 7,
- OS_DETAIL_WIN2K_ADV_SERV = 8,
- OS_DETAIL_WINXP = 9,
- OS_DETAIL_WINXP_HOME = 10,
- OS_DETAIL_WINXP_PRO = 11,
- OS_DETAIL_WINXP_X64_PRO = 12,
- OS_DETAIL_WIN2K3 = 13,
- OS_DETAIL_WIN2K3_WEB = 14,
- OS_DETAIL_WIN2K3_ST = 15,
- OS_DETAIL_WIN2K3_EN = 16,
- OS_DETAIL_WIN2K3_BUS = 17,
- OS_DETAIL_VISTA = 18,
- OS_DETAIL_UNKNOWN = 19
-} OS_DETAIL_TYPE;
-
typedef void (*DesktopSwitchNotifyCB)(void *);
typedef struct {
DesktopSwitchNotifyCB cb; // callback to invoke.
#define VM_SERVICE_STATE_UNKNOWN 0xffffffff
BOOL System_SetProcessPrivilege(LPCTSTR lpszPrivilege, Bool bEnablePrivilege);
-OS_TYPE System_GetOSType(void);
-OS_DETAIL_TYPE System_GetOSDetailType(void);
int32 System_GetSPVersion(void);
Bool System_IsLoginScreenActive(void);
Bool System_IsScreenSaverActive(void);
SYSTEMTIME *systemTime); // OUT
#endif
-EXTERN int TimeUtil_GetLocalWindowsTimeZoneIndex(void);
+EXTERN int TimeUtil_GetLocalWindowsTimeZoneIndexAndName(char **ptzName);
#endif // _TIMEUTIL_H_
VIX_E_INTERACTIVE_SESSION_USER_MISMATCH = 3035,
VIX_E_UNABLE_TO_REPLAY_VM = 3039,
VIX_E_CANNOT_POWER_ON_VM = 3041,
+ VIX_E_NO_DISPLAY_SERVER = 3043,
/* VM Errors */
VIX_E_VM_NOT_FOUND = 4000,
VIX_E_TOOLS_INSTALL_SIG_CHECK_FAILED = 21008,
VIX_E_TOOLS_INSTALL_ERROR = 21009,
VIX_E_TOOLS_INSTALL_ALREADY_UP_TO_DATE = 21010,
+ VIX_E_TOOLS_INSTALL_IN_PROGRESS = 21011,
/* Wrapper Errors */
VIX_E_WRAPPER_WORKSTATION_NOT_INSTALLED = 22001,
#ifndef VIX_HIDE_FROM_JAVA
extern int vixDebugGlobalSpewLevel;
-extern char *VixAllocDebugString(char *fmt, ...);
-extern void VixDebugInit(int level, Bool panicOnVixAssert);
+extern int vixApiTraceGlobalSpewLevel;
+extern char *VixAllocDebugString(char *fmt, ...) PRINTF_DECL(1,2);
+extern void VixDebugInit(int debugLevel, int apiTraceLevel,
+ Bool panicOnVixAssert);
extern const char *VixDebug_GetFileBaseName(const char *path);
extern void VixAssert(const char *cond, const char *file, int lineNum);
*/
#define VIX_DEBUG_PREFERENCE_NAME "vix.debugLevel"
#define VIX_ASSERT_PREFERENCE_NAME "vix.doAssert"
+#define VIX_API_TRACE_PREFERENCE_NAME "vix.apiTraceLevel"
/*
* Assertions. Normally we'd just use ASSERT(), but we've hit many cases
#endif
#define DEFAULT_VIX_LOG_LEVEL 0
+#define DEFAULT_VIX_API_TRACE_LEVEL 0
#define VIX_DEBUG_LEVEL(logLevel, s) if (logLevel <= vixDebugGlobalSpewLevel) \
{ char *debugString = VixAllocDebugString s; \
VixDebug_GetFileBaseName(__FILE__), __LINE__, debugString); \
free(debugString); }
-#define VIX_DEBUG(s) if (0 != vixDebugGlobalSpewLevel) \
+#define VIX_DEBUG(s) if (0 != vixDebugGlobalSpewLevel) \
{ char *debugString = VixAllocDebugString s; \
Log("Vix: [%lu %s:%d]: %s", (unsigned long)Util_GetCurrentThreadId(), \
VixDebug_GetFileBaseName(__FILE__), __LINE__, debugString); \
VixDebug_GetFileBaseName(__FILE__), __LINE__, debugString); \
free(debugString); }
+#define VIX_API_TRACE_ON() (vixApiTraceGlobalSpewLevel > 0)
+
+#define VIX_API_LOG(s) if (VIX_API_TRACE_ON()) \
+ { char *debugString = VixAllocDebugString s; \
+ Log("VixApiLog: %lu %s %s\n", (unsigned long) Util_GetCurrentThreadId(),\
+ __FUNCTION__, debugString); \
+ free(debugString); }
+
#endif // VIX_HIDE_FROM_JAVA
#ifdef __cplusplus
size_t *bufferSize, // IN/OUT
char *pathBuffer); // OUT
+/*
+ * CPU stolen time. The time (in ms) that the VM was runnable but not scheduled
+ * to run.
+ */
+
+VMGuestLibError VMGuestLib_GetCpuStolenMs(VMGuestLibHandle handle, // IN
+ uint64 *cpuStolenMs); // OUT
+/*
+ * Memory Target Size.
+ */
+
+VMGuestLibError VMGuestLib_GetMemTargetSizeMB(VMGuestLibHandle handle, // IN
+ uint64 *memTargetSizeMB); // OUT
+
#ifdef __cplusplus
}
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
AtomicEpilogue(void)
{
#ifdef ATOMIC_USE_FENCE
+#ifdef VMM
+ /* The monitor conditionally patches out the lfence when not needed.*/
+ /* Construct a MonitorPatchTextEntry in the .patchtext section. */
+ asm volatile ("1:\n\t"
+ "lfence\n\t"
+ "2:\n\t"
+ ".pushsection .patchtext\n\t"
+#ifdef VMM32
+ ".long 1b\n\t"
+ ".long 0\n\t"
+ ".long 2b\n\t"
+ ".long 0\n\t"
+#else
+ ".quad 1b\n\t"
+ ".quad 2b\n\t"
+#endif
+ ".popsection\n\t" ::: "memory");
+#else
if (UNLIKELY(AtomicUseFence)) {
asm volatile ("lfence" ::: "memory");
}
#endif
+#endif
}
#error No compiler defined for RDTSC
#endif /* __GNUC__ */
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DEBUGBREAK --
+ *
+ * Does an int3 for MSVC / GCC. This is a macro to make sure int3 is
+ * always inlined.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef _MSC_VER
+#define DEBUGBREAK() __debugbreak()
+#else
+#define DEBUGBREAK() __asm__ (" int $3 ")
+#endif
+
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
/*
* The current Tools version, derived from vm_tools_version.h. Do not modify this.
*/
-#define TOOLS_VERSION "2009.01.21"
+#define TOOLS_VERSION "2009.02.18"
#ifdef VMX86_VPX
#define VIM_API_TYPE "VirtualCenter"
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _VMRPCDBG_H_
+#define _VMRPCDBG_H_
+
+/**
+ * @file vmrpcdbg.h
+ *
+ * Defines the public API for the "GuestRPC Debug Channel" implementation, and
+ * the interface between the debug library and debug plugins.
+ *
+ * @addtogroup vmtools_debug
+ * @{
+ */
+
+#include "vmtoolsApp.h"
+#include "util.h"
+
+struct RpcDebugPlugin;
+
+/**
+ * Signature for the plugin's "receive" function, to validate the data
+ * applications send using RpcChannel_Send.
+ */
+typedef gboolean (*RpcDebugRecvFn)(char *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen);
+
+/** Defines a mapping between a message and a "receive" function. */
+typedef struct RpcDebugRecvMapping {
+ gchar *name;
+ RpcDebugRecvFn recvFn;
+ /**
+ * If not NULL, should be a xdrproc_t function for deserializing the data
+ * in the received message.
+ */
+ gpointer xdrProc;
+ /** If xdrProc is provided, should be the size of the structure to allocate. */
+ size_t xdrSize;
+} RpcDebugRecvMapping;
+
+
+/**
+ * Signature for validation functions. Validation functions are called after
+ * an application has processed an "incoming" RPC, so that the plugin can
+ * validate the response.
+ */
+typedef gboolean (*RpcDebugValidateFn)(RpcInData *data,
+ Bool ret);
+
+/** Defines a mapping between a message and a "validate" function. */
+typedef struct RpcDebugMsgMapping {
+ gchar *message;
+ size_t messageLen;
+ RpcDebugValidateFn validateFn;
+ gboolean freeMsg;
+} RpcDebugMsgMapping;
+
+/** Defines a (NULL-terminated) list of message / validator mappings. */
+typedef struct RpcDebugMsgList {
+ RpcDebugMsgMapping *mappings;
+ size_t index;
+} RpcDebugMsgList;
+
+
+/**
+ * Signature for the plugin's "send" function, which provides the data
+ * to be sent when the service tries to read from the RPC Channel.
+ *
+ * The function should return FALSE if the service should finish the
+ * test (any data provided when this function returns FALSE is ignored).
+ */
+typedef gboolean (*RpcDebugSendFn)(RpcDebugMsgMapping *rpcdata);
+
+/** Signature for the plugin's "shutdown" function. */
+typedef void (*RpcDebugShutdownFn)(ToolsAppCtx *ctx,
+ struct RpcDebugPlugin *plugin);
+
+/**
+ * Registration data for debug plugins, should be returned by the plugin's
+ * entry point function.
+ */
+typedef struct RpcDebugPlugin {
+ /** Maps "incoming" RPCs to specific receive functions. NULL-terminated. */
+ RpcDebugRecvMapping *recvFns;
+ /**
+ * Default receive function for when no mapping matches the incoming command.
+ * May be NULL.
+ */
+ RpcDebugRecvFn dfltRecvFn;
+ /** Send function. */
+ RpcDebugSendFn sendFn;
+ /** Shutdown function. */
+ RpcDebugShutdownFn shutdownFn;
+} RpcDebugPlugin;
+
+
+/**
+ * Signature for the plugin's entry point. The function works in a similar
+ * way to the "ToolsOnLoad" function for regular plugins.
+ */
+typedef RpcDebugPlugin *(*RpcDebugOnLoadFn)(ToolsAppCtx *ctx);
+
+struct RpcDebugLibData;
+
+/**
+ * Describes the external interface of the library. An instance of this struct
+ * is returned by RpcDebug_Initialize() and can be used by applications using
+ * the library to use the debugging functionality.
+ */
+typedef struct RpcDebugLibData {
+ RpcChannel * (*newDebugChannel) (ToolsAppCtx *, struct RpcDebugLibData *);
+ void (*shutdown) (ToolsAppCtx *, struct RpcDebugLibData *);
+ RpcDebugPlugin *debugPlugin;
+} RpcDebugLibData;
+
+/** Signature of the library's initialization function. */
+typedef RpcDebugLibData *(* RpcDebugInitializeFn)(ToolsAppCtx *, gchar *);
+
+
+/**
+ * Helper macro to set @a result / @a resultLen when responding to an RPC.
+ *
+ * @param[in] resultStr The string to set.
+ * @param[out] result Where to store the result.
+ * @param[out] resultLen Where to store the length.
+ */
+
+#define RPCDEBUG_SET_RESULT(resultStr, result, resultLen) do { \
+ char *__resultStr = (resultStr); \
+ char **__result = (result); \
+ size_t *__resultLen = (resultLen); \
+ if (__result != NULL) { \
+ *__result = Util_SafeStrdup(__resultStr); \
+ } \
+ if (__resultLen != NULL) { \
+ *__resultLen = strlen(__resultStr); \
+ } \
+} while (0)
+
+void
+RpcDebug_DecRef(ToolsAppCtx *ctx);
+
+void
+RpcDebug_IncRef(void);
+
+RpcDebugLibData *
+RpcDebug_Initialize(ToolsAppCtx *ctx,
+ gchar *dbgPlugin);
+
+RpcChannel *
+RpcDebug_NewDebugChannel(ToolsAppCtx *ctx,
+ RpcDebugLibData *data);
+
+gboolean
+RpcDebug_SendNext(RpcDebugMsgMapping *rpcdata,
+ RpcDebugMsgList *list);
+
+void
+RpcDebug_Shutdown(ToolsAppCtx *ctx,
+ RpcDebugLibData *data);
+
+/** @} */
+
+#endif /* _VMRPCDBG_H_ */
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _VMTOOLSAPP_H_
+#define _VMTOOLSAPP_H_
+
+/**
+ * @file vmtoolsApp.h
+ *
+ * Defines the interface between the core tools services and the plugins
+ * that are dynamically loaded into the service.
+ *
+ * @addtogroup vmtools_plugins
+ * @{
+ */
+
+#include <glib.h>
+#if defined(G_PLATFORM_WIN32)
+# include <windows.h>
+# include <objbase.h>
+#endif
+#include "guestCaps.h"
+#include "rpcChannel.h"
+
+/**
+ * Error reporting macro. Call this if the app encounters an error
+ * that requires the service to quit. The service's main loop will stop
+ * as soon as it regains control of the application.
+ *
+ * @param[in] ctx The application context.
+ * @param[in] err Error code. Must not be 0.
+ */
+#define VMTOOLSAPP_ERROR(ctx, err) do { \
+ g_assert((err) != 0); \
+ (ctx)->errorCode = (err); \
+ g_main_loop_quit((ctx)->mainLoop); \
+} while (0)
+
+
+/**
+ * Attaches the given event source to the app context's main loop.
+ *
+ * @param[in] ctx The application context.
+ * @param[in] src Source to attach.
+ * @param[in] cb Callback to call when event is "ready".
+ * @param[in] data Data to provide to the callback.
+ * @param[in] destroy Destruction notification callback.
+ */
+#define VMTOOLSAPP_ATTACH_SOURCE(ctx, src, cb, data, destroy) do { \
+ GSource *__src = (src); \
+ g_source_set_callback(__src, (GSourceFunc) (cb), (data), (destroy)); \
+ g_source_attach(__src, g_main_loop_get_context((ctx)->mainLoop)); \
+} while (0)
+
+
+/**
+ * Signal sent when registering or unregistering capabilities.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx ToolsAppCtx *: the application context.
+ * @param[in] set gboolean: TRUE if setting capabilities, FALSE if unsetting them.
+ * @param[in] data Client data.
+ *
+ * @return A GArray instance with the capabilities to be set or unset. The
+ * elements should be of type ToolsAppCapability.
+ */
+#define TOOLS_CORE_SIG_CAPABILITIES "tcs_capabilities"
+
+/**
+ * Signal sent when a successful RpcChannel reset occurs.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx ToolsAppCtx *: The application context.
+ * @param[in] data Client data.
+ */
+#define TOOLS_CORE_SIG_RESET "tcs_reset"
+
+/**
+ * Signal sent when a "set option" RPC message arrives.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx ToolsAppCtx *: The application context.
+ * @param[in] option gchar *: Option being set.
+ * @param[in] value gchar *: Option value.
+ * @param[in] data Client data.
+ *
+ * @return A gboolean saying whether the option was recognized and the value
+ * was valid.
+ */
+#define TOOLS_CORE_SIG_SET_OPTION "tcs_set_option"
+
+/**
+ * Signal sent when shutting down the service.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx ToolsAppCtx *: The application context.
+ * @param[in] data Client data.
+ */
+#define TOOLS_CORE_SIG_SHUTDOWN "tcs_shutdown"
+
+#if defined(G_PLATFORM_WIN32)
+/**
+ * Signal sent when there's a change in the state of a user's session.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx ToolsAppCtx *: The application context.
+ * @param[in] code DWORD: Session state change code.
+ * @param[in] id DWORD: Session ID.
+ * @param[in] data Client data.
+ */
+#define TOOLS_CORE_SIG_SESSION_CHANGE "tcs_session_change"
+#endif
+
+
+/**
+ * Defines the context of a tools application. This data is provided by the
+ * core services to applications when they're loaded.
+ */
+typedef struct ToolsAppCtx {
+ /** Name of the application. */
+ const gchar *name;
+ /** Whether we're running under a VMware hypervisor. */
+ gboolean isVMware;
+ /** Error code to return from the main loop. */
+ int errorCode;
+ /** The main loop instance for the service. */
+ GMainLoop *mainLoop;
+ /** The RPC channel used to communicate with the VMX. */
+ RpcChannel *rpc;
+ /** Service configuration from the config file. */
+ GKeyFile *config;
+#if defined(G_PLATFORM_WIN32)
+ /** Whether COM is initialized. */
+ gboolean comInitialized;
+#else
+ /** The FD to access the VMware blocking fs. -1 if no FD available. */
+ int blockFD;
+#endif
+ /**
+ * A GObject instance shared among all plugins. The object itself doesn't
+ * provide any functionality; but the service emits a few signals on this
+ * object (see the signal name declarations in this header), and plugins can
+ * register and emit their own signals using this object.
+ */
+ gpointer serviceObj;
+} ToolsAppCtx;
+
+#if defined(G_PLATFORM_WIN32)
+/**
+ * Initializes COM if it hasn't been initialized yet.
+ *
+ * @param[in] ctx The application context.
+ *
+ * @return TRUE if COM is initialized when the function returns.
+ */
+static INLINE gboolean
+ToolsCore_InitializeCOM(ToolsAppCtx *ctx)
+{
+ if (!ctx->comInitialized) {
+ HRESULT ret = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ ctx->comInitialized = SUCCEEDED(ret);
+ if (!ctx->comInitialized) {
+ g_log(ctx->name, G_LOG_LEVEL_WARNING,
+ "COM initialization failed(0x%x)\n", ret);
+ }
+ }
+ return ctx->comInitialized;
+}
+#endif
+
+
+/* Capabilities. */
+
+/** Identifies the type of a Tools capability. */
+typedef enum {
+ TOOLS_CAP_OLD = 0,
+ TOOLS_CAP_OLD_NOVAL = 1,
+ TOOLS_CAP_NEW = 2
+} ToolsCapabilityType;
+
+/**
+ * Information about a capability supported by the application. This structure
+ * supports both old-style capabilities (which have a separate RPC message for
+ * each capability) and new-style capabilities (as defined in guestCaps.h).
+ *
+ * The service will register all capabilities with non-zero values when the
+ * service is started (or the host asks for the service to register its
+ * capabilities).
+ */
+typedef struct ToolsAppCapability {
+ /** Identifies the type of the capability. */
+ ToolsCapabilityType type;
+ /**
+ * For old-style, the capability name. The RPC message for setting the
+ * capability will be "tools.capability.[name]". Ignored for TOOLS_CAP_NEW.
+ */
+ gchar *name;
+ /**
+ * The capability entry in the enum defined in guestCaps.h.
+ * Used only for TOOLS_CAP_NEW.
+ */
+ GuestCapabilities index;
+ /** The capability value. 0 means disabled. Ignored for TOOLS_CAP_OLD_NOVAL. */
+ guint value;
+} ToolsAppCapability;
+
+
+/* Application registration. */
+
+/** Type of the application feature being registered. */
+typedef enum {
+ /**
+ * Denotes a list of GuestRPC registrations (type RpcChannelCallback).
+ */
+ TOOLS_APP_GUESTRPC = 1,
+ /**
+ * Denotes a list of signals the application is interested in (type
+ * ToolsPluginSignalCb).
+ */
+ TOOLS_APP_SIGNALS = 2
+} ToolsAppType;
+
+
+/**
+ * Defines a "transport-specific" registration. The array contains data specific
+ * to a "transport" implementation.
+ *
+ * When the service is shutting down, if the @a data field is not NULL, the
+ * array instance will be freed, including its backing element array.
+ * See the documentation for g_array_free(). This will happen only after any
+ * plugin's shutdown callback is called, so plugins have a chance of performing
+ * custom clean up of this data.
+ */
+typedef struct ToolsAppReg {
+ ToolsAppType type;
+ GArray *data;
+} ToolsAppReg;
+
+
+/**
+ * Defines a struct for mapping callbacks to signals. Normally it would suffice
+ * to use g_signal_connect() directly to register interest in signals; but to
+ * allow dynamic registration of signals by plugins, using this struct allows
+ * registration to be delayed until all plugins have been loaded and have had
+ * the chance to register their own signals. The daemon code then can go
+ * through the plugins' registration data and connect all desired signals.
+ */
+
+typedef struct ToolsPluginSignalCb {
+ const gchar *signame;
+ gpointer callback;
+ gpointer clientData;
+} ToolsPluginSignalCb;
+
+
+/**
+ * The registration data for an application. This gives the service information
+ * about all functionality exported by the application, and any events that the
+ * application may be interested in.
+ *
+ * All fields are optional. When the plugin is shut down, if the @a regs field
+ * is not NULL, it (and its element array) are freed with g_array_free().
+ */
+typedef struct ToolsPluginData {
+ /** Name of the application. */
+ char *name;
+ /** List of features provided by the app. */
+ GArray *regs;
+ /** Private plugin data. */
+ gpointer _private;
+} ToolsPluginData;
+
+/**
+ * Definition for tagging functions to be exported in the plugin binary. Use this
+ * to tag the plugin entry point function, and any other functions that the plugin
+ * needs to export.
+ */
+#if defined(G_PLATFORM_WIN32)
+# define TOOLS_MODULE_EXPORT __declspec(dllexport)
+#elif defined(GCC_EXPLICIT_EXPORT)
+# define TOOLS_MODULE_EXPORT __attribute__((visibility("default")))
+#else
+# define TOOLS_MODULE_EXPORT
+#endif
+
+/**
+ * Signature for the plugin entry point function. The function should be called
+ * @a ToolsOnLoad, and be exported in the plugin binary (e.g., by tagging it
+ * with TOOLS_MODULE_EXPORT).
+ *
+ * If the plugin wants to stay loaded, it always should return the registration
+ * data, even if all it contains is the (mandatory) plugin name. Plugins which
+ * return NULL will be unloaded before the service is started, so they shouldn't
+ * modify the service state (for example, by adding callbacks to the service's
+ * main loop).
+ */
+typedef ToolsPluginData *(*ToolsPluginOnLoad)(ToolsAppCtx *ctx);
+
+/** @} */
+
+#endif /* _VMTOOLSAPP_H_ */
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _VMTOOLSD_VERSION_H_
+#define _VMTOOLSD_VERSION_H_
+
+#include "vm_tools_version.h"
+#define VMTOOLSD_VERSION_COMMAS TOOLS_VERSION_EXT_CURRENT_CSV
+#define VMTOOLSD_VERSION_STRING TOOLS_VERSION_EXT_CURRENT_STR
+
+#endif /* _VMTOOLS_VERSION_H_ */
+
FLAGDEF( 87, EDX, AMD, 5, 1, STC, NA, IGNORE, 0, FALSE) \
FLAGDEF( 87, EDX, AMD, 6, 1, 100MHZSTEPS, NA, IGNORE, 0, FALSE) \
FLAGDEF( 87, EDX, AMD, 7, 1, HWPSTATE, NA, IGNORE, 0, FALSE) \
-FLAGDEF( 87, EDX, AMD, 8, 1, TSC_INVARIANT, NA, IGNORE, 0, FALSE) \
+FLAGDEF( 87, EDX, COMMON, 8, 1, TSC_INVARIANT, NA, IGNORE, 0, FALSE) \
FIELDDEFA(88, EAX, COMMON, 0, 8, PHYSBITS, NA, IGNORE, 0, FALSE, PHYS_BITS) \
FIELDDEFA(88, EAX, COMMON, 8, 8, VIRTBITS, NA, IGNORE, 0, FALSE, VIRT_BITS) \
FIELDDEFA(88, ECX, AMD, 0, 8, CORE_COUNT, NA, IGNORE, 0, FALSE, AMD_CORE_COUNT) \
#define CPUID_MODEL_PIII_08 8
#define CPUID_MODEL_PIII_0A 10
+/* AMD model information */
+#define CPUID_MODEL_BARCELONA_02 0x02 // Barcelona (both Opteron & Phenom kind)
+
/*
*----------------------------------------------------------------------
*
CPUID_FAMILY_IS_K8MOBILE(_eax);
}
+/*
+ * AMD Barcelona (of either Opteron or Phenom kind).
+ */
+static INLINE Bool
+CPUID_MODEL_IS_BARCELONA(uint32 v) // IN: %eax from CPUID with %eax=1.
+{
+ /* Assumes the CPU manufacturer is AMD. */
+ return CPUID_FAMILY_IS_K8L(v) &&
+ CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_BARCELONA_02;
+}
+
#define CPUID_TYPE_PRIMARY 0
#define CPUID_TYPE_OVERDRIVE 1
#include "hostinfo.h"
#include "safetime.h"
#include "str.h"
+#include "guest_os.h"
+#include "dynbuf.h"
+#include "vmstdio.h"
+#include "posix.h"
#define SYSINFO_STRING_32 "i386"
#define SYSINFO_STRING_64 "amd64"
static int hostinfoOSVersion[3];
static char hostinfoOSVersionString[SYS_NMLN];
+#define DISTRO_BUF_SIZE 255
+
+typedef struct lsb_distro_info {
+ char *name;
+ char *scanstring;
+} LSBDistroInfo;
+
+
+static LSBDistroInfo lsbFields[] = {
+ {"DISTRIB_ID=", "DISTRIB_ID=%s"},
+ {"DISTRIB_RELEASE=", "DISTRIB_RELEASE=%s"},
+ {"DISTRIB_CODENAME=", "DISTRIB_CODENAME=%s"},
+ {"DISTRIB_DESCRIPTION=", "DISTRIB_DESCRIPTION=%s"},
+ {NULL, NULL},
+};
+
+
+typedef struct distro_info {
+ char *name;
+ char *filename;
+} DistroInfo;
+
+
+static DistroInfo distroArray[] = {
+ {"RedHat", "/etc/redhat-release"},
+ {"RedHat", "/etc/redhat_version"},
+ {"Sun", "/etc/sun-release"},
+ {"SuSE", "/etc/SuSE-release"},
+ {"SuSE", "/etc/novell-release"},
+ {"SuSE", "/etc/sles-release"},
+ {"Debian", "/etc/debian_version"},
+ {"Debian", "/etc/debian_release"},
+ {"Mandrake", "/etc/mandrake-release"},
+ {"Mandriva", "/etc/mandriva-release"},
+ {"Mandrake", "/etc/mandrakelinux-release"},
+ {"TurboLinux", "/etc/turbolinux-release"},
+ {"Fedora Core", "/etc/fedora-release"},
+ {"Gentoo", "/etc/gentoo-release"},
+ {"Novell", "/etc/nld-release"},
+ {"Ubuntu", "/etc/lsb-release"},
+ {"Annvix", "/etc/annvix-release"},
+ {"Arch", "/etc/arch-release"},
+ {"Arklinux", "/etc/arklinux-release"},
+ {"Aurox", "/etc/aurox-release"},
+ {"BlackCat", "/etc/blackcat-release"},
+ {"Cobalt", "/etc/cobalt-release"},
+ {"Conectiva", "/etc/conectiva-release"},
+ {"Immunix", "/etc/immunix-release"},
+ {"Knoppix", "/etc/knoppix_version"},
+ {"Linux-From-Scratch", "/etc/lfs-release"},
+ {"Linux-PPC", "/etc/linuxppc-release"},
+ {"MkLinux", "/etc/mklinux-release"},
+ {"PLD", "/etc/pld-release"},
+ {"Slackware", "/etc/slackware-version"},
+ {"Slackware", "/etc/slackware-release"},
+ {"SMEServer", "/etc/e-smith-release"},
+ {"Solaris", "/etc/release"},
+ {"Tiny Sofa", "/etc/tinysofa-release"},
+ {"UltraPenguin", "/etc/ultrapenguin-release"},
+ {"UnitedLinux", "/etc/UnitedLinux-release"},
+ {"VALinux", "/etc/va-release"},
+ {"Yellow Dog", "/etc/yellowdog-release"},
+ {NULL, NULL},
+};
+
/*
*----------------------------------------------------------------------
return -1;
#endif
}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HostinfoGetOSShortName --
+ *
+ * Returns distro information based on .vmx format (distroShort).
+ *
+ * Return value:
+ * Overwrited the short name if we recognise the OS.
+ * Otherwise leave the short name as it is.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HostinfoGetOSShortName(char *distro, // IN: full distro name
+ char *distroShort, // OUT: short distro name
+ int distroShortSize) // IN: size of short distro name
+
+{
+ char *distroLower = NULL; /* Lower case distro name */
+
+ distroLower = calloc(strlen(distro) + 1, sizeof *distroLower);
+
+ if (distroLower == NULL) {
+ Warning("%s: could not allocate memory\n", __FUNCTION__);
+ return;
+ }
+
+ Str_Strcpy(distroLower, distro, distroShortSize);
+ distroLower = Str_ToLower(distroLower);
+
+ if (strstr(distroLower, "red hat")) {
+ if (strstr(distroLower, "enterprise")) {
+
+ /*
+ * Looking for "release x" here instead of "x" as there could be
+ * build version which can be misleading. For example Red Hat
+ * Enterprise Linux ES release 4 (Nahant Update 3)
+ */
+
+ int release = 0;
+ char *releaseStart = strstr(distroLower, "release");
+
+ if (releaseStart) {
+ sscanf(releaseStart, "release %d", &release);
+ if (release > 0) {
+ snprintf(distroShort, distroShortSize, STR_OS_RED_HAT_EN"%d", release);
+ }
+ }
+
+ if (release <= 0) {
+ Warning("%s: could not read Red Hat Enterprise release version\n",
+ __FUNCTION__);
+ Str_Strcpy(distroShort, STR_OS_RED_HAT_EN, distroShortSize);
+ }
+
+ } else {
+ Str_Strcpy(distroShort, STR_OS_RED_HAT, distroShortSize);
+ }
+ } else if (strstr(distroLower, "suse")) {
+ if (strstr(distroLower, "enterprise")) {
+ Str_Strcpy(distroShort, STR_OS_SUSE_EN, distroShortSize);
+ } else if (strstr(distroLower, "sun")) {
+ Str_Strcpy(distroShort, STR_OS_SUN_DESK, distroShortSize);
+ } else if (strstr(distroLower, "novell")) {
+ Str_Strcpy(distroShort, STR_OS_NOVELL, distroShortSize);
+ } else {
+ Str_Strcpy(distroShort, STR_OS_SUSE, distroShortSize);
+ }
+ } else if (strstr(distroLower, "mandrake")) {
+ Str_Strcpy(distroShort, STR_OS_MANDRAKE, distroShortSize);
+ } else if (strstr(distroLower, "turbolinux")) {
+ Str_Strcpy(distroShort, STR_OS_TURBO, distroShortSize);
+ } else if (strstr(distroLower, "sun")) {
+ Str_Strcpy(distroShort, STR_OS_SUN_DESK, distroShortSize);
+ } else if (strstr(distroLower, "annvix")) {
+ Str_Strcpy(distroShort, STR_OS_ANNVIX, distroShortSize);
+ } else if (strstr(distroLower, "arch")) {
+ Str_Strcpy(distroShort, STR_OS_ARCH, distroShortSize);
+ } else if (strstr(distroLower, "arklinux")) {
+ Str_Strcpy(distroShort, STR_OS_ARKLINUX, distroShortSize);
+ } else if (strstr(distroLower, "aurox")) {
+ Str_Strcpy(distroShort, STR_OS_AUROX, distroShortSize);
+ } else if (strstr(distroLower, "black cat")) {
+ Str_Strcpy(distroShort, STR_OS_BLACKCAT, distroShortSize);
+ } else if (strstr(distroLower, "cobalt")) {
+ Str_Strcpy(distroShort, STR_OS_COBALT, distroShortSize);
+ } else if (strstr(distroLower, "conectiva")) {
+ Str_Strcpy(distroShort, STR_OS_CONECTIVA, distroShortSize);
+ } else if (strstr(distroLower, "debian")) {
+ Str_Strcpy(distroShort, STR_OS_DEBIAN, distroShortSize);
+ } else if (strstr(distroLower, "fedora")) {
+ Str_Strcpy(distroShort, STR_OS_FEDORA, distroShortSize);
+ } else if (strstr(distroLower, "gentoo")) {
+ Str_Strcpy(distroShort, STR_OS_GENTOO, distroShortSize);
+ } else if (strstr(distroLower, "immunix")) {
+ Str_Strcpy(distroShort, STR_OS_IMMUNIX, distroShortSize);
+ } else if (strstr(distroLower, "linux-from-scratch")) {
+ Str_Strcpy(distroShort, STR_OS_LINUX_FROM_SCRATCH, distroShortSize);
+ } else if (strstr(distroLower, "linux-ppc")) {
+ Str_Strcpy(distroShort, STR_OS_LINUX_PPC, distroShortSize);
+ } else if (strstr(distroLower, "mandriva")) {
+ Str_Strcpy(distroShort, STR_OS_MANDRIVA, distroShortSize);
+ } else if (strstr(distroLower, "mklinux")) {
+ Str_Strcpy(distroShort, STR_OS_MKLINUX, distroShortSize);
+ } else if (strstr(distroLower, "pld")) {
+ Str_Strcpy(distroShort, STR_OS_PLD, distroShortSize);
+ } else if (strstr(distroLower, "slackware")) {
+ Str_Strcpy(distroShort, STR_OS_SLACKWARE, distroShortSize);
+ } else if (strstr(distroLower, "sme server")) {
+ Str_Strcpy(distroShort, STR_OS_SMESERVER, distroShortSize);
+ } else if (strstr(distroLower, "tiny sofa")) {
+ Str_Strcpy(distroShort, STR_OS_TINYSOFA, distroShortSize);
+ } else if (strstr(distroLower, "ubuntu")) {
+ Str_Strcpy(distroShort, STR_OS_UBUNTU, distroShortSize);
+ } else if (strstr(distroLower, "ultra penguin")) {
+ Str_Strcpy(distroShort, STR_OS_ULTRAPENGUIN, distroShortSize);
+ } else if (strstr(distroLower, "united linux")) {
+ Str_Strcpy(distroShort, STR_OS_UNITEDLINUX, distroShortSize);
+ } else if (strstr(distroLower, "va linux")) {
+ Str_Strcpy(distroShort, STR_OS_VALINUX, distroShortSize);
+ } else if (strstr(distroLower, "yellow dog")) {
+ Str_Strcpy(distroShort, STR_OS_YELLOW_DOG, distroShortSize);
+ }
+
+ free(distroLower);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HostinfoReadDistroFile --
+ *
+ * Look for a distro version file /etc/xxx-release.
+ * Once found, read the file in and figure out which distribution.
+ *
+ * Return value:
+ * Returns TRUE on success and FALSE on failure.
+ * Returns distro information verbatium from /etc/xxx-release (distro).
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HostinfoReadDistroFile(char *filename, // IN: distro version file name
+ int distroSize, // IN: size of OS distro name buffer
+ char *distro) // OUT: full distro name
+{
+ int fd;
+ int buf_sz;
+ struct stat st;
+ Bool ret = FALSE;
+ char *distroOrig = NULL;
+ char distroPart[DISTRO_BUF_SIZE];
+ char *tmpDistroPos = NULL;
+ int i = 0;
+
+ if ((fd = open(filename, O_RDONLY)) < 0) {
+ Warning("%s: could not open file%s: %d\n", __FUNCTION__, filename, errno);
+ return FALSE;
+ }
+
+ if (fstat(fd, &st)) {
+ Warning("%s: could not stat the file %s: %d\n", __FUNCTION__, filename,
+ errno);
+ goto out;
+ }
+
+ buf_sz = st.st_size;
+ if (buf_sz >= distroSize) {
+ Warning("%s: input buffer too small\n", __FUNCTION__);
+ goto out;
+ }
+ distroOrig = calloc(distroSize, sizeof *distroOrig);
+
+ if (distroOrig == NULL) {
+ Warning("%s: could not allocate memory\n", __FUNCTION__);
+ close(fd);
+ return FALSE;
+ }
+
+ if (read(fd, distroOrig, buf_sz) != buf_sz) {
+ Warning("%s: could not read file %s: %d\n", __FUNCTION__, filename, errno);
+ goto out;
+ }
+
+ distroOrig[buf_sz] = '\0';
+
+ /*
+ * For the case where we do have a release file in the LSB format,
+ * but there is no LSB module, let's parse the LSB file for possible fields.
+ */
+
+ distro[0] = '\0';
+
+ for (i = 0; lsbFields[i].name != NULL; i++) {
+ tmpDistroPos = strstr(distroOrig, lsbFields[i].name);
+ if (tmpDistroPos) {
+ sscanf(tmpDistroPos, lsbFields[i].scanstring, distroPart);
+ if (distroPart[0] == '"') {
+ char *tmpMakeNull = NULL;
+
+ tmpDistroPos += strlen(lsbFields[i].name) + 1;
+ tmpMakeNull = strchr(tmpDistroPos + 1 , '"');
+ if (tmpMakeNull) {
+ *tmpMakeNull = '\0';
+ Str_Strcat(distro, tmpDistroPos, distroSize);
+ *tmpMakeNull = '"' ;
+ }
+ } else {
+ Str_Strcat(distro, distroPart, distroSize);
+ }
+ Str_Strcat(distro, " ", distroSize);
+ }
+ }
+
+ if (distro[0] == '\0') {
+ /* Copy original string. What we got wasn't LSB compliant. */
+ Str_Strcpy(distro, distroOrig, distroSize);
+ }
+
+ ret = TRUE;
+
+out:
+ close(fd);
+ free(distroOrig);
+
+ return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HostinfoGetCmdOutput --
+ *
+ * Run a cmd & get its cmd line output
+ *
+ * Results:
+ * An allocated string or NULL if an error occurred.
+ *
+ * Side effects:
+ * The cmd is run.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static char *
+HostinfoGetCmdOutput(const char *cmd) // IN:
+{
+#if defined(N_PLAT_NLM)
+ Warning("Trying to execute command \"%s\" and catch its output... No way on NetWare...\n", cmd);
+ return NULL;
+#else
+ DynBuf db;
+ FILE *stream;
+ char *out = NULL;
+
+ DynBuf_Init(&db);
+
+ stream = Posix_Popen(cmd, "r");
+ if (stream == NULL) {
+ Warning("Unable to get output of command \"%s\"\n", cmd);
+
+ return NULL;
+ }
+
+ for (;;) {
+ char *line = NULL;
+ size_t size;
+
+ switch (StdIO_ReadNextLine(stream, &line, 0, &size)) {
+ case StdIO_Error:
+ goto closeIt;
+ break;
+
+ case StdIO_EOF:
+ break;
+
+ case StdIO_Success:
+ break;
+
+ default:
+ ASSERT_NOT_IMPLEMENTED(FALSE);
+ }
+
+ if (line == NULL) {
+ break;
+ }
+
+ DynBuf_Append(&db, line, size);
+ free(line);
+ }
+
+ if (DynBuf_Get(&db)) {
+ out = (char *) DynBuf_AllocGet(&db);
+ }
+ closeIt:
+ DynBuf_Destroy(&db);
+
+ pclose(stream);
+
+ return out;
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Hostinfo_GetOSName --
+ *
+ * Return OS version information. First retrieve OS information using
+ * uname, then look in /etc/xxx-release file to get the distro info.
+ * osFullName will be:
+ * <OS NAME> <OS RELEASE> <SPECIFIC_DISTRO_INFO>
+ * An example of such string would be:
+ * Linux 2.4.18-3 Red Hat Linux release 7.3 (Valhalla)
+ *
+ * osName contains an os name in the same format that is used
+ * in .vmx file.
+ *
+ * Return value:
+ * Returns TRUE on success and FALSE on failure.
+ * Returns the guest's full OS name (osNameFull)
+ * Returns the guest's OS name in the same format as .vmx file (osName)
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+Hostinfo_GetOSName(uint32 outBufFullLen, // IN: length of osNameFull buffer
+ uint32 outBufLen, // IN: length of osName buffer
+ char *osNameFull, // OUT: Full OS name
+ char *osName) // OUT: OS name (.vmx file format)
+{
+ struct utsname buf;
+ unsigned int lastCharPos;
+ const char *lsbCmd = "lsb_release -sd 2>/dev/null";
+ char *lsbOutput = NULL;
+
+ /*
+ * Use uname to get complete OS information.
+ */
+
+ if (uname(&buf) < 0) {
+ Warning("%s: uname failed %d\n", __FUNCTION__, errno);
+ return FALSE;
+ }
+
+
+ if (strlen(buf.sysname) + strlen(buf.release) + 3 > outBufFullLen) {
+ Warning("%s: Error: buffer too small\n", __FUNCTION__);
+ return FALSE;
+ }
+
+ Str_Strcpy(osName, STR_OS_EMPTY, outBufLen);
+ Str_Strcpy(osNameFull, buf.sysname, outBufFullLen);
+ Str_Strcat(osNameFull, STR_OS_EMPTY, outBufFullLen);
+ Str_Strcat(osNameFull, buf.release, outBufFullLen);
+
+ /*
+ * Check to see if this is Linux
+ * If yes, determine the distro by looking for /etc/xxx file.
+ */
+
+ if (strstr(osNameFull, "Linux")) {
+ char distro[DISTRO_BUF_SIZE];
+ char distroShort[DISTRO_BUF_SIZE];
+ int i = 0;
+ int distroSize = sizeof distro;
+
+ /*
+ * Write default distro string depending on the kernel version. If
+ * later we find more detailed information this will get overwritten.
+ */
+
+ if (strstr(buf.release, "2.4")) {
+ Str_Strcpy(distro, STR_OS_OTHER_24_FULL, distroSize);
+ Str_Strcpy(distroShort, STR_OS_OTHER_24, distroSize);
+ } else if (strstr(buf.release, "2.6")) {
+ Str_Strcpy(distro, STR_OS_OTHER_26_FULL, distroSize);
+ Str_Strcpy(distroShort, STR_OS_OTHER_26, distroSize);
+ } else {
+ Str_Strcpy(distro, STR_OS_OTHER_FULL, distroSize);
+ Str_Strcpy(distroShort, STR_OS_OTHER, distroSize);
+ }
+
+ /*
+ * Try to get OS detailed information
+ * from the lsb_release command.
+ */
+
+ lsbOutput = HostinfoGetCmdOutput(lsbCmd);
+
+ if (!lsbOutput) {
+ /*
+ * Try to get more detailed information from the version file.
+ */
+
+ for (i = 0; distroArray[i].filename != NULL; i++) {
+ if (HostinfoReadDistroFile(distroArray[i].filename, distroSize,
+ distro)) {
+ break;
+ }
+ }
+
+ /*
+ * If we failed to read every distro file, exit now, before calling
+ * strlen on the distro buffer (which wasn't set).
+ */
+
+ if (distroArray[i].filename == NULL) {
+ Warning("%s: Error: no distro file found\n", __FUNCTION__);
+ return FALSE;
+ }
+ } else {
+ char *lsbStart = lsbOutput;
+ char *quoteEnd = NULL;
+
+ if (lsbStart[0] == '"') {
+ lsbStart++;
+ quoteEnd = strchr(lsbStart, '"');
+ if (quoteEnd) {
+ *quoteEnd = '\0';
+ }
+ }
+ Str_Strcpy(distro, lsbStart, distroSize);
+ free(lsbOutput);
+ }
+
+ HostinfoGetOSShortName(distro, distroShort, distroSize);
+
+ if (strlen(distro) + strlen(osNameFull) + 2 > outBufFullLen) {
+ Warning("%s: Error: buffer too small\n", __FUNCTION__);
+ return FALSE;
+ }
+
+ Str_Strcat(osNameFull, " ", outBufFullLen);
+ Str_Strcat(osNameFull, distro, outBufFullLen);
+
+ if (strlen(distroShort) + 1 > outBufLen) {
+ Warning("%s: Error: buffer too small\n", __FUNCTION__);
+ return FALSE;
+ }
+
+ Str_Strcpy(osName, distroShort, outBufLen);
+ } else if (strstr(osNameFull, "FreeBSD")) {
+ size_t nameLen = sizeof STR_OS_FREEBSD - 1;
+ size_t releaseLen = 0;
+ char *dashPtr;
+
+ /*
+ * FreeBSD releases report their version as "x.y-RELEASE". We'll be naive
+ * look for the first dash, and use everything before it as the version
+ * number.
+ */
+
+ dashPtr = Str_Strchr(buf.release, '-');
+ if (dashPtr != NULL) {
+ releaseLen = dashPtr - buf.release;
+ }
+
+ if (nameLen + releaseLen + 1 > outBufLen) {
+ Warning("GuestInfoGetOSName: Error: buffer too small\n");
+ return FALSE;
+ }
+
+ Str_Strcpy(osName, STR_OS_FREEBSD, outBufLen);
+ } else if (strstr(osNameFull, "SunOS")) {
+ size_t nameLen = sizeof STR_OS_SOLARIS - 1;
+ size_t releaseLen = 0;
+ char *periodPtr;
+
+ /*
+ * Solaris releases report their version as "x.y". For our supported
+ * releases it seems that x is always "5", and is ignored in favor of
+ * y for the version number. We'll be naive and look for the first
+ * period, and use the entire string after that as the version number.
+ */
+
+ periodPtr = Str_Strchr(buf.release, '.');
+ if (periodPtr != NULL) {
+ releaseLen = (buf.release + strlen(buf.release)) - periodPtr;
+ }
+
+ if (nameLen + releaseLen + 1 > outBufLen) {
+ Warning("GuestInfoGetOSName: Error: buffer too small\n");
+ return FALSE;
+ }
+
+ Str_Strcpy(osName, STR_OS_SOLARIS, outBufLen);
+ }
+
+ if (Hostinfo_GetSystemBitness() == 64) {
+ if (strlen(osName) + sizeof STR_OS_64BIT_SUFFIX > outBufLen) {
+ Warning("%s: Error: buffer too small\n", __FUNCTION__);
+ return FALSE;
+ }
+ Str_Strcat(osName, STR_OS_64BIT_SUFFIX, outBufLen);
+ }
+
+ /*
+ * Before returning, truncate
+ * the \n character at the end of the full name.
+ */
+
+ lastCharPos = strlen(osNameFull) - 1;
+ if (osNameFull[lastCharPos] == '\n') {
+ osNameFull[lastCharPos] = '\0';
+ }
+
+ return TRUE;
+}
+
if (ret == errAuthorizationSuccess) {
return auth;
} else {
- Warning("%s: AuthorizationCreate failed, error %ld.\n",
- __FUNCTION__, ret);
+ ASSERT_ON_COMPILE(sizeof ret == sizeof (int32));
+ Warning("%s: AuthorizationCreate failed, error %d.\n",
+ __FUNCTION__, (int32)ret);
return NULL;
}
}
#include "safetime.h"
+#include "unicode.h"
#if defined(N_PLAT_NLM)
# include <sys/timeval.h>
/*
- * Function to guess Windows TZ Index by using time offset in
+ * Function to guess Windows TZ Index and Name by using time offset in
* a lookup table
*/
-static int TimeUtilFindIndexByUTCOffset(int utcToStdOffsetMins);
+static int TimeUtilFindIndexAndNameByUTCOffset(int utcStdOffMins, const char **ptzName);
#if defined(_WIN32)
/*
/*
*----------------------------------------------------------------------
*
- * TimeUtil_GetLocalWindowsTimeZoneIndex --
+ * TimeUtil_GetLocalWindowsTimeZoneIndexAndName --
*
- * Gets Windows TZ index for local time zone.
+ * Gets Windows TZ Index and Name for local time zone.
*
* Results:
* -1 if there is any error, else the Windows Time Zone ID of the
*----------------------------------------------------------------------
*/
int
-TimeUtil_GetLocalWindowsTimeZoneIndex(void)
+TimeUtil_GetLocalWindowsTimeZoneIndexAndName(char **ptzName) // OUT: returning TZ Name
{
int utcStdOffMins = 0;
int winTimeZoneIndex = (-1);
+ const char *tzNameByUTCOffset = NULL;
+
+ *ptzName = NULL;
#if defined(_WIN32)
- TIME_ZONE_INFORMATION tz;
- char name[256] = { 0 };
- size_t nameLen = 0, nc = 0;
- if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_INVALID) {
- return (-1);
- }
+ {
+ TIME_ZONE_INFORMATION tz;
+ if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_INVALID) {
+ return (-1);
+ }
- /* 'Bias' = diff between UTC and local standard time */
- utcStdOffMins = 0-tz.Bias; // already in minutes
+ /* 'Bias' = diff between UTC and local standard time */
+ utcStdOffMins = 0 - tz.Bias; // already in minutes
- /* Get TZ name */
- nameLen = wcslen(tz.StandardName);
- if (wcstombs(name, tz.StandardName, 255) <= 0) {
- return (-1);
+ /* Find Windows TZ index */
+ *ptzName = Unicode_AllocWithUTF16(tz.StandardName);
+ winTimeZoneIndex = Win32TimeUtilLookupZoneIndex(*ptzName);
+ if (winTimeZoneIndex < 0) {
+ Unicode_Free(*ptzName);
+ *ptzName = NULL;
+ }
}
- /* Convert name to Windows TZ index */
- winTimeZoneIndex = Win32TimeUtilLookupZoneIndex(name);
-
#else // NOT _WIN32
- /*
- * Use localtime_r() to get offset between our local
- * time and UTC. This varies by platform. Also, the structure
- * fields are named "*gmt*" but the man pages claim offsets are
- * to UTC, not GMT.
- */
-
- time_t now = time(NULL);
- struct tm tim;
- localtime_r(&now, &tim);
-
- #if defined SOL9 || defined SOL10 || defined N_PLAT_NLM
- /*
- * Offset is to standard (no need for DST adjustment).
- * Negative is east of prime meridian.
- */
- utcStdOffMins = 0 - timezone/60;
- #else
+ {
/*
- * FreeBSD, Apple, Linux only:
- * Offset is to local (need to adjust for DST).
- * Negative is west of prime meridian.
+ * Use localtime_r() to get offset between our local
+ * time and UTC. This varies by platform. Also, the structure
+ * fields are named "*gmt*" but the man pages claim offsets are
+ * to UTC, not GMT.
*/
- utcStdOffMins = tim.tm_gmtoff/60;
- if (tim.tm_isdst) {
- utcStdOffMins -= 60;
- }
- #endif
- /* can't figure this out directly for non-Win32 */
- winTimeZoneIndex = (-1);
+ time_t now = time(NULL);
+ struct tm tim;
+ localtime_r(&now, &tim);
+
+ #if defined SOL9 || defined SOL10 || defined N_PLAT_NLM
+ /*
+ * Offset is to standard (no need for DST adjustment).
+ * Negative is east of prime meridian.
+ */
+ utcStdOffMins = 0 - timezone/60;
+ #else
+ /*
+ * FreeBSD, Apple, Linux only:
+ * Offset is to local (need to adjust for DST).
+ * Negative is west of prime meridian.
+ */
+ utcStdOffMins = tim.tm_gmtoff/60;
+ if (tim.tm_isdst) {
+ utcStdOffMins -= 60;
+ }
+ #endif
+
+ /* can't figure this out directly for non-Win32 */
+ winTimeZoneIndex = (-1);
+ }
#endif
/* If we don't have it yet, look up windowsCode. */
if (winTimeZoneIndex < 0) {
- winTimeZoneIndex = TimeUtilFindIndexByUTCOffset(utcStdOffMins);
+ winTimeZoneIndex = TimeUtilFindIndexAndNameByUTCOffset(utcStdOffMins, &tzNameByUTCOffset);
+ if (winTimeZoneIndex >= 0) {
+ *ptzName = Unicode_AllocWithUTF8(tzNameByUTCOffset);
+ }
}
return winTimeZoneIndex;
/*
*----------------------------------------------------------------------
*
- * TimeUtilFindIndexByUTCOffset --
+ * TimeUtilFindIndexAndNameByUTCOffset --
*
* Private function. Scans a table for a given UTC-to-Standard
* offset and returns the Windows TZ Index of the first match
- * found.
- *
- * Parameters:
- * utcStdOffMins Offset to look for (in minutes)
- * <0 is west of PM, >0 is east of PM.
+ * found together with its Windows TZ Name.
*
* Results:
* Returns Windows TZ Index (>=0) if found, else -1.
*
*----------------------------------------------------------------------
*/
-static int TimeUtilFindIndexByUTCOffset(int utcStdOffMins)
+static int
+TimeUtilFindIndexAndNameByUTCOffset(int utcStdOffMins, // IN: offset (in minutes)
+ const char **ptzName) // OUT: returning TZ Name
{
static struct _tzinfo {
int winTzIndex;
+ char winTzName[256];
int utcStdOffMins;
} TABLE[] = {
- { 0, /* "Dateline Standard Time",*/ -720 }, // -12
- { 1, /* "Samoa Standard Time",*/ -660 }, // -11
- { 2, /* "Hawaiian Standard Time",*/ -600 }, // -10
- { 3, /* "Alaskan Standard Time",*/ -540 }, // -9
- { 4, /* "Pacific Standard Time",*/ -480 }, // -8
- { 10, /* "Mountain Standard Time",*/ -420 }, // -7
- { 13, /* "Mexico Standard Time 2",*/ -420 }, // -7
- { 15, /* "U.S. Mountain Standard Time",*/ -420 }, // -7
- { 20, /* "Central Standard Time",*/ -360 }, // -6
- { 25, /* "Canada Central Standard Time",*/ -360 }, // -6
- { 30, /* "Mexico Standard Time",*/ -360 }, // -6
- { 33, /* "Central America Standard Time",*/ -360 }, // -6
- { 35, /* "Eastern Standard Time",*/ -300 }, // -5
- { 40, /* "U.S. Eastern Standard Time",*/ -300 }, // -5
- { 45, /* "S.A. Pacific Standard Time",*/ -300 }, // -5
- { 50, /* "Atlantic Standard Time",*/ -240 }, // -4
- { 55, /* "S.A. Western Standard Time",*/ -240 }, // -4
- { 56, /* "Pacific S.A. Standard Time",*/ -240 }, // -4
- { 60, /* "Newfoundland Standard Time",*/ -210 }, // -3.5
- { 65, /* "E. South America Standard Time",*/-180 }, // -3
- { 70, /* "S.A. Eastern Standard Time",*/ -180 }, // -3
- { 73, /* "Greenland Standard Time",*/ -180 }, // -3
- { 75, /* "Mid-Atlantic Standard Time",*/ -120 }, // -2
- { 80, /* "Azores Standard Time",*/ -60 }, // -1
- { 83, /* "Cape Verde Standard Time",*/ -60 }, // -1
- { 85, /* "GMT Standard Time",*/ 0 }, // 0
- { 90, /* "Greenwich Standard Time",*/ 0 }, // 0
- { 95, /* "Central Europe Standard Time",*/ 60 }, // +1
- { 100, /* "Central European Standard Time",*/ 60 }, // +1
- { 105, /* "Romance Standard Time",*/ 60 }, // +1
- { 110, /* "W. Europe Standard Time",*/ 60 }, // +1
- { 113, /* "W. Central Africa Standard Time",*/ 60 }, // +1
- { 115, /* "E. Europe Standard Time",*/ 120 }, // +2
- { 120, /* "Egypt Standard Time",*/ 120 }, // +2
- { 125, /* "FLE Standard Time",*/ 120 }, // +2
- { 130, /* "GTB Standard Time",*/ 120 }, // +2
- { 135, /* "Israel Standard Time",*/ 120 }, // +2
- { 140, /* "South Africa Standard Time",*/ 120 }, // +2
- { 145, /* "Russian Standard Time",*/ 180 }, // +3
- { 150, /* "Arab Standard Time",*/ 180 }, // +3
- { 155, /* "E. Africa Standard Time",*/ 180 }, // +3
- { 158, /* "Arabic Standard Time",*/ 180 }, // +3
- { 160, /* "Iran Standard Time",*/ 210 }, // +3.5
- { 165, /* "Arabian Standard Time",*/ 240 }, // +4
- { 170, /* "Caucasus Standard Time",*/ 240 }, // +4
- { 175, /* "Afghanistan Standard Time",*/ 270 }, // +4.5
- { 180, /* "Ekaterinburg Standard Time",*/ 300 }, // +5
- { 185, /* "West Asia Standard Time",*/ 300 }, // +5
- { 190, /* "India Standard Time",*/ 330 }, // +5.5
- { 193, /* "Nepal Standard Time",*/ 345 }, // +5.75
- { 195, /* "Central Asia Standard Time",*/ 360 }, // +6
- { 200, /* "Sri Lanka Standard Time",*/ 360 }, // +6
- { 201, /* "N. Central Asia Standard Time",*/ 360 }, // +6
- { 203, /* "Myanmar Standard Time",*/ 390 }, // +6.5
- { 205, /* "S.E. Asia Standard Time",*/ 420 }, // +7
- { 207, /* "North Asia Standard Time",*/ 420 }, // +7
- { 210, /* "China Standard Time",*/ 480 }, // +8
- { 215, /* "Singapore Standard Time",*/ 480 }, // +8
- { 220, /* "Taipei Standard Time",*/ 480 }, // +8
- { 225, /* "W. Australia Standard Time",*/ 480 }, // +8
- { 227, /* "North Asia East Standard Time",*/ 480 }, // +8
- { 230, /* "Korea Standard Time",*/ 540 }, // +9
- { 235, /* "Tokyo Standard Time",*/ 540 }, // +9
- { 240, /* "Yakutsk Standard Time",*/ 540 }, // +9
- { 245, /* "A.U.S. Central Standard Time",*/ 570 }, // +9.5
- { 250, /* "Cen. Australia Standard Time",*/ 570 }, // +9.5
- { 255, /* "A.U.S. Eastern Standard Time",*/ 600 }, // +10
- { 260, /* "E. Australia Standard Time",*/ 600 }, // +10
- { 265, /* "Tasmania Standard Time",*/ 600 }, // +10
- { 270, /* "Vladivostok Standard Time",*/ 600 }, // +10
- { 275, /* "West Pacific Standard Time",*/ 600 }, // +10
- { 280, /* "Central Pacific Standard Time",*/ 660 }, // +11
- { 285, /* "Fiji Islands Standard Time",*/ 720 }, // +12
- { 290, /* "New Zealand Standard Time",*/ 720 }, // +12
- { 300, /* "Tonga Standard Time",*/ 780 }};// +13
-
- int tableSize = sizeof(TABLE) / sizeof(TABLE[0]);
- int look;
+
+ /*
+ * These values are from Microsoft's TimeZone documentation:
+ *
+ * http://technet.microsoft.com/en-us/library/cc749073.aspx
+ */
+
+ { 0, "Dateline Standard Time", -720 }, // -12
+ { 1, "Samoa Standard Time", -660 }, // -11
+ { 2, "Hawaiian Standard Time", -600 }, // -10
+ { 3, "Alaskan Standard Time", -540 }, // -9
+ { 4, "Pacific Standard Time", -480 }, // -8
+ { 10, "Mountain Standard Time", -420 }, // -7
+ { 13, "Mountain Standard Time (Mexico)", -420 }, // -7
+ { 15, "US Mountain Standard Time", -420 }, // -7
+ { 20, "Central Standard Time", -360 }, // -6
+ { 25, "Canada Central Standard Time", -360 }, // -6
+ { 30, "Central Standard Time (Mexico)", -360 }, // -6
+ { 33, "Central America Standard Time", -360 }, // -6
+ { 35, "Eastern Standard Time", -300 }, // -5
+ { 40, "US Eastern Standard Time", -300 }, // -5
+ { 45, "SA Pacific Standard Time", -300 }, // -5
+ { 50, "Atlantic Standard Time", -240 }, // -4
+ { 55, "SA Western Standard Time", -240 }, // -4
+ { 56, "Pacific SA Standard Time", -240 }, // -4
+ { 60, "Newfoundland Standard Time", -210 }, // -3.5
+ { 65, "E. South America Standard Time", -180 }, // -3
+ { 70, "SA Eastern Standard Time", -180 }, // -3
+ { 73, "Greenland Standard Time", -180 }, // -3
+ { 75, "Mid-Atlantic Standard Time", -120 }, // -2
+ { 80, "Azores Standard Time", -60 }, // -1
+ { 83, "Cape Verde Standard Time", -60 }, // -1
+ { 85, "GMT Standard Time", 0 }, // 0
+ { 90, "Greenwich Standard Time", 0 }, // 0
+ { 110, "W. Europe Standard Time", 60 }, // +1
+ { 95, "Central Europe Standard Time", 60 }, // +1
+ { 100, "Central European Standard Time", 60 }, // +1
+ { 105, "Romance Standard Time", 60 }, // +1
+ { 113, "W. Central Africa Standard Time", 60 }, // +1
+ { 115, "E. Europe Standard Time", 120 }, // +2
+ { 120, "Egypt Standard Time", 120 }, // +2
+ { 125, "FLE Standard Time", 120 }, // +2
+ { 130, "GTB Standard Time", 120 }, // +2
+ { 135, "Israel Standard Time", 120 }, // +2
+ { 140, "South Africa Standard Time", 120 }, // +2
+ { 145, "Russian Standard Time", 180 }, // +3
+ { 150, "Arab Standard Time", 180 }, // +3
+ { 155, "E. Africa Standard Time", 180 }, // +3
+ { 158, "Arabic Standard Time", 180 }, // +3
+ { 160, "Iran Standard Time", 210 }, // +3.5
+ { 165, "Arabian Standard Time", 240 }, // +4
+ { 170, "Caucasus Standard Time", 240 }, // +4
+ { 175, "Afghanistan Standard Time", 270 }, // +4.5
+ { 180, "Ekaterinburg Standard Time", 300 }, // +5
+ { 185, "West Asia Standard Time", 300 }, // +5
+ { 190, "India Standard Time", 330 }, // +5.5
+ { 193, "Nepal Standard Time", 345 }, // +5.75
+ { 195, "Central Asia Standard Time", 360 }, // +6
+ { 200, "Sri Lanka Standard Time", 360 }, // +6
+ { 201, "N. Central Asia Standard Time", 360 }, // +6
+ { 203, "Myanmar Standard Time", 390 }, // +6.5
+ { 205, "SE Asia Standard Time", 420 }, // +7
+ { 207, "North Asia Standard Time", 420 }, // +7
+ { 210, "China Standard Time", 480 }, // +8
+ { 215, "Singapore Standard Time", 480 }, // +8
+ { 220, "Taipei Standard Time", 480 }, // +8
+ { 225, "W. Australia Standard Time", 480 }, // +8
+ { 227, "North Asia East Standard Time", 480 }, // +8
+ { 230, "Korea Standard Time", 540 }, // +9
+ { 235, "Tokyo Standard Time", 540 }, // +9
+ { 240, "Yakutsk Standard Time", 540 }, // +9
+ { 245, "AUS Central Standard Time", 570 }, // +9.5
+ { 250, "Cen. Australia Standard Time", 570 }, // +9.5
+ { 255, "AUS Eastern Standard Time", 600 }, // +10
+ { 260, "E. Australia Standard Time", 600 }, // +10
+ { 265, "Tasmania Standard Time", 600 }, // +10
+ { 270, "Vladivostok Standard Time", 600 }, // +10
+ { 275, "West Pacific Standard Time", 600 }, // +10
+ { 280, "Central Pacific Standard Time", 660 }, // +11
+ { 285, "Fiji Standard Time", 720 }, // +12
+ { 290, "New Zealand Standard Time", 720 }, // +12
+ { 300, "Tonga Standard Time", 780 }};// +13
+
+ size_t tableSize = ARRAYSIZE(TABLE);
+ size_t look;
int tzIndex = (-1);
+ *ptzName = NULL;
+
/* XXX Finds the first match, not necessariy the right match! */
- for (look = 0; look < tableSize && tzIndex < 0; look++) {
+ for (look = 0; look < tableSize; look++) {
if (TABLE[look].utcStdOffMins == utcStdOffMins) {
tzIndex = TABLE[look].winTzIndex;
+ *ptzName = TABLE[look].winTzName;
+ break;
}
}
Util_IsAbsolutePath(const char *path) // IN: path to check
{
#if defined(__linux__) || defined(__APPLE__)
+ // path[0] is valid even for the empty string.
return path && path[0] == DIRSEPC;
#elif defined(_WIN32)
- if (!path) {
+ // if the length is 2, path[2] will be valid because of the null terminator.
+ if (!path || strlen(path) < 2) {
return FALSE;
}
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libRpcChannel.la
+
+libRpcChannel_la_SOURCES =
+libRpcChannel_la_SOURCES += bdoorChannel.c
+libRpcChannel_la_SOURCES += rpcChannel.c
+
+libRpcChannel_la_CPPFLAGS =
+libRpcChannel_la_CPPFLAGS += @VMTOOLS_CPPFLAGS@
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file bdoorChannel.c
+ *
+ * Implements a backdoor-based RPC channel. This is based on the
+ * RpcIn / RpcOut libraries.
+ */
+
+#include "vm_assert.h"
+#include "rpcChannelInt.h"
+#include "rpcout.h"
+#include "util.h"
+
+/** Max amount of time (in .01s) that the RpcIn loop will sleep for. */
+#define RPCIN_MAX_DELAY 10
+
+typedef struct BackdoorChannel {
+ RpcIn *in;
+ RpcOut *out;
+ gboolean inStarted;
+ gboolean outStarted;
+} BackdoorChannel;
+
+
+/**
+ * Stops a channel, optionally destroying the channel. It's safe to call
+ * this function more than once.
+ *
+ * @param[in] chan The RPC channel instance.
+ * @param[in] destroy Whether to destroy the channels.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+RpcInStopChannel(RpcChannel *chan,
+ gboolean destroy)
+{
+ gboolean ret = TRUE;
+ BackdoorChannel *bdoor = chan->_private;
+
+ ASSERT(chan->appName != NULL);
+ if (bdoor->out != NULL) {
+ if (!bdoor->outStarted || RpcOut_stop(bdoor->out)) {
+ if (destroy) {
+ RpcOut_Destruct(bdoor->out);
+ bdoor->out = NULL;
+ }
+ bdoor->outStarted = FALSE;
+ } else {
+ ret = FALSE;
+ }
+ } else {
+ ASSERT(!bdoor->outStarted);
+ }
+
+ if (bdoor->in != NULL) {
+ if (!bdoor->inStarted || RpcIn_stop(bdoor->in)) {
+ if (destroy) {
+ RpcIn_Destruct(bdoor->in);
+ bdoor->in = NULL;
+ }
+ bdoor->inStarted = FALSE;
+ } else {
+ ret = FALSE;
+ }
+ } else {
+ ASSERT(!bdoor->inStarted);
+ }
+
+ return ret;
+}
+
+
+/**
+ * Starts the RpcIn loop and the RpcOut channel.
+ *
+ * @param[in] chan The RPC channel instance.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+RpcInStart(RpcChannel *chan)
+{
+ gboolean ret;
+ BackdoorChannel *bdoor = chan->_private;
+
+ ASSERT(chan->appName != NULL);
+ ASSERT(!bdoor->inStarted);
+ ASSERT(!bdoor->outStarted);
+
+ ret = RpcIn_start(bdoor->in, RPCIN_MAX_DELAY, RpcChannel_Error, chan);
+ if (ret) {
+ ret = RpcOut_start(bdoor->out);
+ if (!ret) {
+ RpcIn_stop(bdoor->in);
+ }
+ }
+ bdoor->inStarted = TRUE;
+ bdoor->outStarted = TRUE;
+ return ret;
+}
+
+
+/**
+ * Shuts down the RpcIn channel. Due to the "split brain" nature of the backdoor,
+ * if this function fails, it's possible that while the "out" channel was shut
+ * down the "in" one wasn't, for example, although that's unlikely.
+ *
+ * @param[in] chan The RPC channel instance.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+RpcInShutdown(RpcChannel *chan)
+{
+ return RpcInStopChannel(chan, TRUE);
+}
+
+
+/**
+ * Stops the channel from receiving messages and releases the channel, but
+ * don't clean up the internal channel state. This allows the channel to be
+ * restarted later if needed. The "out" channel is also stopped, so sending
+ * a message on the channel while it's stopped will fail.
+ *
+ * @param[in] chan The RPC channel instance.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+RpcInStop(RpcChannel *chan)
+{
+ return RpcInStopChannel(chan, FALSE);
+}
+
+
+/**
+ * Sends the data using the RpcOut library.
+ *
+ * @param[in] chan The RPC channel instance.
+ * @param[in] data Data to send.
+ * @param[in] dataLen Number of bytes to send.
+ * @param[out] result Response from other side.
+ * @param[out] resultLen Number of bytes in response.
+ *
+ * @return The status from the remote end (TRUE if call was successful).
+ */
+
+static Bool
+RpcInSend(RpcChannel *chan,
+ char *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen)
+{
+ gboolean ret;
+ const char *reply;
+ size_t replyLen;
+ BackdoorChannel *bdoor = chan->_private;
+
+ ASSERT(chan->appName != NULL);
+
+ if (!bdoor->outStarted) {
+ return FALSE;
+ }
+
+ ret = RpcOut_send(bdoor->out, data, dataLen, &reply, &replyLen);
+
+ /*
+ * A lot of this logic is just replicated from rpcout.c:RpcOut_SendOneRaw().
+ * Look there for comments about a few details.
+ */
+ if (result != NULL) {
+ if (reply != NULL) {
+ *result = Util_SafeMalloc(replyLen + 1);
+ memcpy(*result, reply, replyLen);
+ (*result)[replyLen] = '\0';
+ } else {
+ *result = NULL;
+ }
+ }
+
+ if (resultLen != NULL) {
+ *resultLen = replyLen;
+ }
+
+ return ret;
+}
+
+
+/**
+ * Creates a new RpcIn channel.
+ *
+ * @param[in] mainCtx The app's main context.
+ *
+ * @return A new channel instance (never NULL).
+ */
+
+RpcChannel *
+RpcChannel_NewBackdoorChannel(GMainContext *mainCtx)
+{
+ RpcChannel *ret;
+ BackdoorChannel *bdoor;
+
+ ret = g_malloc0(sizeof *ret);
+
+ bdoor = g_malloc(sizeof *bdoor);
+ bdoor->in = RpcIn_Construct(mainCtx, RpcChannel_Dispatch, ret);
+ ASSERT(bdoor->in != NULL);
+
+ bdoor->out = RpcOut_Construct();
+ ASSERT(bdoor->out != NULL);
+
+ bdoor->inStarted = FALSE;
+ bdoor->outStarted = FALSE;
+
+ ret->start = RpcInStart;
+ ret->stop = RpcInStop;
+ ret->send = RpcInSend;
+ ret->shutdown = RpcInShutdown;
+ ret->_private = bdoor;
+
+ return ret;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file rpcChannel.c
+ *
+ * Common functions to all RPC channel implementations.
+ */
+
+#include <string.h>
+#include "dynxdr.h"
+#include "rpcChannelInt.h"
+#include "str.h"
+#include "strutil.h"
+#include "vmxrpc.h"
+#include "xdrutil.h"
+
+/** Max number of times to attempt a channel restart. */
+#define RPCIN_MAX_RESTARTS 60
+
+static Bool
+RpcChannelPing(RpcInData *data);
+
+static RpcChannelCallback gRpcHandlers[] = {
+ { "ping", RpcChannelPing, NULL, NULL, NULL, 0 }
+};
+
+
+/**
+ * Handler for a "ping" message. Does nothing.
+ *
+ * @param[in] data The RPC data.
+ *
+ * @return TRUE.
+ */
+
+static Bool
+RpcChannelPing(RpcInData *data)
+{
+ return RPCIN_SETRETVALS(data, "", TRUE);
+}
+
+
+/**
+ * Callback for restarting the RPC channel.
+ *
+ * @param[in] _chan The RPC channel
+ *
+ * @return FALSE
+ */
+
+static gboolean
+RpcChannelRestart(gpointer _chan)
+{
+ RpcChannel *chan = _chan;
+
+ if (!chan->stop(chan) || !chan->start(chan)) {
+ g_warning("Channel reset failed [%d]\n", chan->rpcErrorCount);
+ if (chan->resetCb != NULL) {
+ chan->resetCb(chan, FALSE, chan->resetData);
+ }
+ } else {
+ chan->rpcError = FALSE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ * Checks and potentially resets the RPC channel. This code is based on the
+ * toolsDaemon.c function "ToolsDaemon_CheckReset".
+ *
+ * @param[in] _chan The RPC channel.
+ *
+ * @return FALSE. The reset callback will schedule a new check when it's called.
+ */
+
+static gboolean
+RpcChannelCheckReset(gpointer _chan)
+{
+ static int channelTimeoutAttempts = RPCIN_MAX_RESTARTS;
+ RpcChannel *chan = _chan;
+
+ /* Check the channel state. */
+ if (chan->rpcError) {
+ GSource *src;
+
+ if (++(chan->rpcErrorCount) > channelTimeoutAttempts) {
+ g_warning("Failed to reset channel after %u attempts\n",
+ chan->rpcErrorCount - 1);
+ if (chan->resetCb != NULL) {
+ chan->resetCb(chan, FALSE, chan->resetData);
+ }
+ goto exit;
+ }
+
+ /* Schedule the channel restart for 1 sec in the future. */
+ g_debug("Resetting channel [%u]\n", chan->rpcErrorCount);
+ src = g_timeout_source_new(1000);
+ g_source_set_callback(src, RpcChannelRestart, chan, NULL);
+ g_source_attach(src, chan->mainCtx);
+ g_source_unref(src);
+ goto exit;
+ }
+
+ /* Reset was successful. */
+ g_debug("Channel was reset successfully.\n");
+ chan->rpcErrorCount = 0;
+
+ if (chan->resetCb != NULL) {
+ chan->resetCb(chan, TRUE, chan->resetData);
+ }
+
+exit:
+ g_source_unref(chan->resetCheck);
+ chan->resetCheck = NULL;
+ return FALSE;
+}
+
+
+/**
+ * Handles an RPC reset. Calls the reset callback of all loaded plugins.
+ *
+ * @param[in] data The RPC data.
+ *
+ * @return TRUE.
+ */
+
+static Bool
+RpcChannelReset(RpcInData *data)
+{
+ gchar *msg;
+ RpcChannel *chan = data->clientData;
+
+ g_assert(chan->resetCheck == NULL);
+ chan->resetCheck = g_idle_source_new();
+ g_source_set_callback(chan->resetCheck, RpcChannelCheckReset, chan, NULL);
+ g_source_attach(chan->resetCheck, chan->mainCtx);
+
+ msg = Str_Asprintf(NULL, "ATR %s", chan->appName);
+ ASSERT_MEM_ALLOC(msg);
+ data->freeResult = TRUE;
+ return RPCIN_SETRETVALS(data, msg, TRUE);
+}
+
+
+/**
+ * A wrapper for standard RPC callback functions which provides automatic
+ * XDR serialization / deserialization if requested by the application.
+ *
+ * @param[in] data RpcIn data.
+ * @param[in] rpc The RPC registration data.
+ *
+ * @return Whether the RPC was handled successfully.
+ */
+
+static Bool
+RpcChannelXdrWrapper(RpcInData *data,
+ RpcChannelCallback *rpc)
+{
+ Bool ret;
+ RpcInData copy;
+ void *xdrData = NULL;
+
+ if (rpc->xdrIn != NULL) {
+ xdrData = malloc(rpc->xdrInSize);
+ if (xdrData == NULL) {
+ ret = RPCIN_SETRETVALS(data, "Out of memory.", FALSE);
+ goto exit;
+ }
+
+ memset(xdrData, 0, rpc->xdrInSize);
+ if (!XdrUtil_Deserialize(data->args + 1, data->argsSize, rpc->xdrIn, xdrData)) {
+ ret = RPCIN_SETRETVALS(data, "XDR deserialization failed.", FALSE);
+ free(xdrData);
+ goto exit;
+ }
+
+ copy.name = data->name;
+ copy.args = xdrData;
+ copy.argsSize = rpc->xdrInSize;
+ copy.result = data->result;
+ copy.resultLen = data->resultLen;
+ copy.freeResult = data->freeResult;
+ copy.appCtx = data->appCtx;
+ copy.clientData = rpc->clientData;
+ } else {
+ memcpy(©, data, sizeof copy);
+ }
+
+ ret = rpc->callback(©);
+
+ if (rpc->xdrIn != NULL) {
+ VMX_XDR_FREE(rpc->xdrIn, xdrData);
+ free(xdrData);
+ copy.args = NULL;
+ data->result = copy.result;
+ data->resultLen = copy.resultLen;
+ data->freeResult = copy.freeResult;
+ }
+
+ if (rpc->xdrOut != NULL && copy.result != NULL) {
+ XDR xdrs;
+ xdrproc_t xdrProc = rpc->xdrOut;
+
+ if (DynXdr_Create(&xdrs) == NULL) {
+ ret = RPCIN_SETRETVALS(data, "Out of memory.", FALSE);
+ goto exit;
+ }
+
+ if (!xdrProc(&xdrs, copy.result)) {
+ ret = RPCIN_SETRETVALS(data, "XDR serialization failed.", FALSE);
+ DynXdr_Destroy(&xdrs, TRUE);
+ goto exit;
+ }
+
+ if (copy.freeResult) {
+ VMX_XDR_FREE(rpc->xdrOut, copy.result);
+ }
+ data->result = DynXdr_Get(&xdrs);
+ data->resultLen = XDR_GETPOS(&xdrs);
+ data->freeResult = TRUE;
+ DynXdr_Destroy(&xdrs, FALSE);
+ }
+
+exit:
+ if (copy.freeResult && copy.result != NULL) {
+ g_free(copy.result);
+ }
+ return ret;
+}
+
+
+/**
+ * Builds an "rpcout" command to send a XDR struct.
+ *
+ * @param[in] cmd The command name.
+ * @param[in] xdrProc Function to use for serializing the XDR struct.
+ * @param[in] xdrData The XDR struct to serialize.
+ * @param[out] result Where to store the serialized data.
+ * @param[out] resultLen Where to store the serialized data length.
+ *
+ * @return Whether successfully built the command.
+ */
+
+Bool
+RpcChannel_BuildXdrCommand(const char *cmd,
+ void *xdrProc,
+ void *xdrData,
+ char **result,
+ size_t *resultLen)
+{
+ Bool ret = FALSE;
+ xdrproc_t proc = xdrProc;
+ XDR xdrs;
+
+ if (DynXdr_Create(&xdrs) == NULL) {
+ return FALSE;
+ }
+
+ if (!DynXdr_AppendRaw(&xdrs, cmd, strlen(cmd))) {
+ goto exit;
+ }
+
+ if (!DynXdr_AppendRaw(&xdrs, " ", 1)) {
+ goto exit;
+ }
+
+ if (!proc(&xdrs, xdrData)) {
+ goto exit;
+ }
+
+ *result = DynXdr_Get(&xdrs);
+ *resultLen = xdr_getpos(&xdrs);
+
+ ret = TRUE;
+
+exit:
+ DynXdr_Destroy(&xdrs, !ret);
+ return ret;
+}
+
+
+/**
+ * Dispatches the given RPC to the registered handler. This mimics the behavior
+ * of the RpcIn library (but is not tied to that particular implementation of
+ * an RPC channel).
+ *
+ * @param[in,out] data The RPC data.
+ *
+ * @return Whether the RPC was handled successfully.
+ */
+
+Bool
+RpcChannel_Dispatch(RpcInData *data)
+{
+ char *name = NULL;
+ unsigned int index = 0;
+ size_t nameLen;
+ Bool status;
+ RpcChannelCallback *rpc = NULL;
+ RpcChannel *chan = data->clientData;
+
+ name = StrUtil_GetNextToken(&index, data->args, " ");
+ if (name == NULL) {
+ status = RPCIN_SETRETVALS(data, "Bad command", FALSE);
+ goto exit;
+ }
+
+ if (chan->rpcs != NULL) {
+ rpc = g_hash_table_lookup(chan->rpcs, name);
+ }
+
+ if (rpc == NULL) {
+ status = RPCIN_SETRETVALS(data, "Unknown Command", FALSE);
+ goto exit;
+ }
+
+ /* Adjust the RPC arguments. */
+ nameLen = strlen(name);
+ data->name = name;
+ data->args = data->args + nameLen;
+ data->argsSize -= nameLen;
+ data->appCtx = chan->appCtx;
+ data->clientData = rpc->clientData;
+
+ if (rpc->xdrIn != NULL || rpc->xdrOut != NULL) {
+ status = RpcChannelXdrWrapper(data, rpc);
+ } else {
+ status = rpc->callback(data);
+ }
+
+ g_assert(data->result != NULL);
+
+exit:
+ data->name = NULL;
+ free(name);
+ return status;
+}
+
+
+/**
+ * Shuts down an RPC channel and release any held resources.
+ *
+ * @param[in] chan The RPC channel.
+ *
+ * @return Whether the channel was shut down successfully.
+ */
+
+gboolean
+RpcChannel_Destroy(RpcChannel *chan)
+{
+ size_t i;
+
+ if (chan->shutdown != NULL && !chan->shutdown(chan)) {
+ return FALSE;
+ }
+
+ RpcChannel_UnregisterCallback(chan, &chan->resetReg);
+ for (i = 0; i < ARRAYSIZE(gRpcHandlers); i++) {
+ RpcChannel_UnregisterCallback(chan, &gRpcHandlers[i]);
+ }
+
+ if (chan->rpcs != NULL) {
+ g_hash_table_destroy(chan->rpcs);
+ chan->rpcs = NULL;
+ }
+
+ chan->resetCb = NULL;
+ chan->resetData = NULL;
+ chan->appCtx = NULL;
+
+ g_free(chan->appName);
+ chan->appName = NULL;
+
+ g_main_context_unref(chan->mainCtx);
+ chan->mainCtx = NULL;
+
+ if (chan->resetCheck != NULL) {
+ g_source_destroy(chan->resetCheck);
+ chan->resetCheck = NULL;
+ }
+
+ g_free(chan);
+ return TRUE;
+}
+
+
+/**
+ * Error handling function for the RPC channel. Enqueues the "check reset"
+ * function for running later, if it's not yet enqueued.
+ *
+ * @param[in] _chan The RPC channel.
+ * @param[in] status Error description.
+ */
+
+void
+RpcChannel_Error(void *_chan,
+ char const *status)
+{
+ RpcChannel *chan = _chan;
+ chan->rpcError = TRUE;
+ g_warning("Error in the RPC receive loop: %s.\n", status);
+
+ if (chan->resetCheck == NULL) {
+ chan->resetCheck = g_idle_source_new();
+ g_source_set_callback(chan->resetCheck, RpcChannelCheckReset, chan, NULL);
+ g_source_attach(chan->resetCheck, chan->mainCtx);
+ }
+}
+
+
+/**
+ * Initializes the RPC channel for use. This function must be called before
+ * starting the channel.
+ *
+ * @param[in] chan The RPC channel.
+ * @param[in] appName TCLO application name.
+ * @param[in] mainCtx Application event context.
+ * @param[in] appCtx Application context.
+ * @param[in] resetCb Callback for when a reset occurs.
+ * @param[in] resetData Client data for the reset callback.
+ */
+
+void
+RpcChannel_Setup(RpcChannel *chan,
+ const gchar *appName,
+ GMainContext *mainCtx,
+ gpointer appCtx,
+ RpcChannelResetCb resetCb,
+ gpointer resetData)
+{
+ size_t i;
+
+ chan->appName = g_strdup(appName);
+ chan->appCtx = appCtx;
+ chan->mainCtx = g_main_context_ref(mainCtx);
+ chan->resetCb = resetCb;
+ chan->resetData = resetData;
+
+ chan->resetReg.name = "reset";
+ chan->resetReg.callback = RpcChannelReset;
+ chan->resetReg.clientData = chan;
+
+ /* Register the callbacks handled by the rpcChannel library. */
+ RpcChannel_RegisterCallback(chan, &chan->resetReg);
+
+ for (i = 0; i < ARRAYSIZE(gRpcHandlers); i++) {
+ RpcChannel_RegisterCallback(chan, &gRpcHandlers[i]);
+ }
+}
+
+
+/**
+ * Registers a new RPC handler in the given RPC channel. This function is
+ * not thread-safe.
+ *
+ * @param[in] chan The channel instance.
+ * @param[in] rpc Info about the RPC being registered.
+ */
+
+void
+RpcChannel_RegisterCallback(RpcChannel *chan,
+ RpcChannelCallback *rpc)
+{
+ g_assert(rpc->name != NULL && strlen(rpc->name) > 0);
+ g_assert(rpc->callback);
+ g_assert(rpc->xdrIn == NULL || rpc->xdrInSize > 0);
+ if (chan->rpcs == NULL) {
+ chan->rpcs = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+ if (g_hash_table_lookup(chan->rpcs, rpc->name) != NULL) {
+ g_error("Trying to overwrite existing RPC registration for %s!\n", rpc->name);
+ }
+ g_hash_table_insert(chan->rpcs, (gpointer) rpc->name, rpc);
+}
+
+
+/**
+ * Unregisters a new RPC handler from the given RPC channel. This function is
+ * not thread-safe.
+ *
+ * @param[in] chan The channel instance.
+ * @param[in] rpc Info about the RPC being unregistered.
+ */
+
+void
+RpcChannel_UnregisterCallback(RpcChannel *chan,
+ RpcChannelCallback *rpc)
+{
+ if (chan->rpcs != NULL) {
+ g_hash_table_remove(chan->rpcs, rpc->name);
+ }
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _RPCCHANNELINT_H_
+#define _RPCCHANNELINT_H_
+
+/**
+ * @file rpcChannelInt.h
+ *
+ * Internal definitions for the RPC channel library.
+ */
+
+#include "rpcChannel.h"
+
+void
+RpcChannel_Error(void *_state,
+ char const *status);
+
+#endif /* _RPCCHANNELINT_H_ */
+
libStubs_la_SOURCES += stub-user-msg.c
libStubs_la_SOURCES += stub-user-panic.c
-if ENABLE_CORE_SERVICES
noinst_LTLIBRARIES += libStubsCS.la
libStubsCS_la_SOURCES =
libStubsCS_la_SOURCES += stub-config.c
libStubsCS_la_SOURCES += stub-user-msg.c
libStubsCS_la_SOURCES += stub-user-panic.c
-endif
*/
char *
-System_GetEnv(Bool global, // IN
- char *valueName) // IN: UTF-8
+System_GetEnv(Bool global, // IN
+ const char *valueName) // IN: UTF-8
{
char *result;
int
System_SetEnv(Bool global, // IN
- char *valueName, // IN: UTF-8
- char *value) // IN: UTF-8
+ const char *valueName, // IN: UTF-8
+ const char *value) // IN: UTF-8
{
#if defined(sun)
return(-1);
XSelectInput(up->display, upw->clientWindow, 0);
HashTable_Delete(up->allWindows, GUINT_TO_POINTER(upw->clientWindow));
}
+#if defined(VM_HAVE_X11_SHAPE_EXT)
+ if (up->shapeEventBase) {
+ XShapeSelectInput(up->display, upw->toplevelWindow, 0);
+
+ if (upw->clientWindow) {
+ XShapeSelectInput(up->display, upw->clientWindow, 0);
+ }
+ }
+#endif
/*
* Okay, now we may have two UnityPlatformWindows running around, one each for
#if defined(VM_HAVE_X11_SHAPE_EXT)
if (up->shapeEventBase) {
XShapeSelectInput(up->display, toplevelWindow, ShapeNotifyMask);
+
+ if (upw->clientWindow) {
+ XShapeSelectInput(up->display, upw->clientWindow, ShapeNotifyMask);
+ }
}
#endif
int numQueryArgs;
int i;
int err;
- char *ctmp = NULL;
char **argv;
char *windowQueryString = NULL;
char *execQueryString = NULL;
}
if (argv[0][0] != '/') {
+ char *ctmp = NULL;
if ((ctmp = AppUtil_CanonicalizeAppName(argv[0], cwd))) {
char **newArgv;
newArgv = alloca(argc * sizeof argv[0]);
XFree(rects); rects = NULL;
rectCount = 0;
+ /*
+ * The X Shape Extension operates on unshaped windows by using default bounding
+ * and clipping regions. I.e., XShapeGetRectangles will return a single rectangle
+ * for an unshaped window. Without the following test, we'd end up informing the
+ * Unity client that this window can be described by a single rectangle region,
+ * and it'd expect further region updates when the window's geometry changes.
+ *
+ * This wouldn't be a problem, except we don't receive XShapeEvents on these
+ * windows when they're resized. To work around this, we make sure that the UWT
+ * knows that unshaped windows are exactly that.
+ */
+ {
+ int bShaped;
+ int cShaped;
+ int dummy;
+
+ XShapeQueryExtents(up->display, upw->toplevelWindow,
+ &bShaped, &dummy, &dummy, &dummy, &dummy,
+ &cShaped, &dummy, &dummy, &dummy, &dummy);
+ if (!bShaped && !cShaped) {
+ UnityWindowTracker_ChangeWindowRegion(up->tracker, upw->toplevelWindow, 0);
+ return;
+ }
+ }
+
UnityPlatformResetErrorCount(up);
/*
#else
osFamily = GUEST_OS_FAMILY_LINUX;
#endif
- if (!(GuestInfo_GetOSName(sizeof osNameFull, sizeof osName, osNameFull, osName))) {
+ if (!(Hostinfo_GetOSName(sizeof osNameFull, sizeof osName, osNameFull,
+ osName))) {
osNameFull[0] = 0;
osName[0] = 0;
}
if (version != VERSION_MAGIC) {
Debug("The version of this program is incompatible with your %s.\n"
"For information on updating your VMware Tools please see\n"
- "http://www.vmware.com/support/reference/common/info_tools.html.\n"
+ "http://www.vmware.com/info?id=99\n"
"\n", PRODUCT_LINE_NAME);
return FALSE;
}
WiperIsDiskDevice(MNTINFO *mnt, // IN: file system being considered
struct stat *s) // IN: stat(2) info of fs source
{
- int major;
+ int majorN;
- major = (s->st_rdev >> 8) & 0xFF;
- if (! ( (major == 3) /* First MFM, RLL and IDE hard disk/CD-ROM
+ majorN = major(s->st_rdev);
+ if (! ( (majorN == 3) /* First MFM, RLL and IDE hard disk/CD-ROM
interface. Inside a VM, this is simply the First
IDE hard disk/CD-ROM interface because we don't
support others */
- || (major == 22) /* Second IDE hard disk/CD-ROM interface */
- || (major == 8) /* SCSI disk devices */
- || (major == 43) /* Network block device */)) {
+ || (majorN == 22) /* Second IDE hard disk/CD-ROM interface */
+ || (majorN == 8) /* SCSI disk devices */
+ || (majorN == 43) /* Network block device */
+ || (majorN == 259) /* Disks in 2.6.27 */)) {
return FALSE;
}
return error;
}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetCpuStolenMs --
+ *
+ * Retrieve CPU stolen.
+ *
+ * Results:
+ * VMGuestLibError
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetCpuStolenMs(VMGuestLibHandle handle, // IN
+ uint64 *cpuStolenMs) // OUT
+{
+ VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+ VMGUESTLIB_GETSTAT_V3(handle, error,
+ cpuStolenMs, cpuStolenMs,
+ GUESTLIB_CPU_STOLEN_MS);
+ return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetMemTargetSizeMB --
+ *
+ * Retrieve Memory Target Size.
+ *
+ * Results:
+ * VMGuestLibError
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetMemTargetSizeMB(VMGuestLibHandle handle, // IN
+ uint64 *memTargetSizeMB) // OUT
+{
+ VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+ VMGUESTLIB_GETSTAT_V3(handle, error,
+ memTargetSizeMB, memTargetSizeMB,
+ GUESTLIB_MEM_TARGET_SIZE_MB);
+ return error;
+}
+
+
libvmtools_la_LIBADD += ../lib/file/libFile.la
libvmtools_la_LIBADD += ../lib/guestApp/libGuestApp.la
libvmtools_la_LIBADD += ../lib/guestInfo/libGuestInfoCS.la
+libvmtools_la_LIBADD += ../lib/guestRpc/libGuestRpc.la
libvmtools_la_LIBADD += ../lib/hgfs/libHgfs.la
libvmtools_la_LIBADD += ../lib/message/libMessage.la
libvmtools_la_LIBADD += ../lib/misc/libMisc.la
+libvmtools_la_LIBADD += ../lib/netUtil/libNetUtil.la
libvmtools_la_LIBADD += ../lib/panic/libPanic.la
+libvmtools_la_LIBADD += ../lib/procMgr/libProcMgr.la
+libvmtools_la_LIBADD += ../lib/rpcChannel/libRpcChannel.la
libvmtools_la_LIBADD += ../lib/rpcOut/libRpcOut.la
+libvmtools_la_LIBADD += ../lib/rpcVmx/libRpcVmx.la
libvmtools_la_LIBADD += ../lib/string/libString.la
libvmtools_la_LIBADD += ../lib/sync/libSync.la
+libvmtools_la_LIBADD += ../lib/syncDriver/libSyncDriver.la
libvmtools_la_LIBADD += ../lib/system/libSystem.la
libvmtools_la_LIBADD += ../lib/stubs/libStubsCS.la
libvmtools_la_LIBADD += ../lib/unicode/libUnicode.la
{ CONFNAME_REBOOT, "vmsvc", CONFNAME_REBOOT, CFG_STRING, NULL },
/* HGFS options. */
{ CONFNAME_MOUNT_POINT, "hgfs", CONFNAME_MOUNT_POINT, CFG_STRING, NULL },
+#else
/* Tray options. */
{ CONFNAME_SHOW_WIRELESS_ICON, "vmtray", CONFNAME_SHOW_WIRELESS_ICON, CFG_BOOLEAN, NULL },
#endif
* we detect whether the original message already had a new line, and
* remove it, to avoid having two newlines when printing our log messages.
*/
- if (msgCurr[len - 2] == '\n') {
+ if (msgCurr != NULL && msgCurr[len - 2] == '\n') {
msgCurr[len - 1] = '\0';
}
}
- free(msg);
- return msgCurr;
+ if (msgCurr != NULL) {
+ free(msg);
+ return msgCurr;
+ }
+ return msg;
}
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### VMware-specific macros for use with autoconf.
+###
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+#
+# AC_VMW_CHECK_LIB(library, lvar, pkgname, lconfig, version, header, function,
+# [action-if-found],
+# [action-if-not-found])
+#
+# Checks for the existence of a library using three different methods, in the
+# following order:
+#
+# - user defined CUSTOM_(LIB)_CPPFLAGS and CUSTOM_(LIB)_LIBS variables.
+# - pkg-config
+# - the library's custom "config"
+#
+# If a library is successfully detected, the (LIB)_CPPFLAGS and (LIB)_LIBS
+# variables are set to contain the appropriate flags, and these variables are
+# exported using AC_SUBST. The parameters to the macro are:
+#
+# library ($1): the library name; this is used for testing whether we can link
+# to the library (with AC_CHECK_LIB), and also to modify the user
+# provided CUSTOM_(LIB)_LIBS variable to make sure the library is
+# available in the linker flags.
+# lvar ($2): root name of the variables holding the libraries CPPFLAGS / LIBS;
+# e.g., FOO means that FOO_CPPFLAGS will be set, and CUSTOM_FOO_CPPFLAGS
+# used with AC_CHECK_HEADER.
+# pkgname ($3): pkg-config name of the library.
+# lconfig ($4): library's custom "config" program for figuring out compiler and
+# linker flags (optional).
+# version ($5): minimum version of the library when using pkg-config (optional).
+# header ($6): header file (when not using pkg-config; see AC_CHECK_HEADER; optional).
+# function ($7): function (when not using pkg-config; see AC_CHECK_LIB; optional).
+# action-if-found ($8): what to execute when successfully found the library.
+# action-if-not-found ($9): what to execute when the library was not found.
+#
+AC_DEFUN([AC_VMW_CHECK_LIB],[
+ AC_REQUIRE([AC_CHECK_LIB]) dnl
+ AC_REQUIRE([AC_CHECK_HEADER]) dnl
+
+ if test -z "$1"; then
+ AC_MSG_ERROR(['library' parameter is required.'])
+ fi
+ if test -z "$2"; then
+ AC_MSG_ERROR(['lvar' parameter is required.'])
+ fi
+
+ ac_vmw_have_lib=0
+ ac_vmw_have_lib_func=0
+ ac_vmw_have_lib_header=0
+
+ #
+ # First, try any user-defined CUSTOM_* flags.
+ #
+ if test -n "${CUSTOM_$2_CPPFLAGS}" || test -n "${CUSTOM_$2_LIBS}"; then
+ CUSTOM_$2_LIBS="${CUSTOM_$2_LIBS} -l$1"
+ if test -n "$6"; then
+ ORIGINAL_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="${CUSTOM_$2_CPPFLAGS} $CPPFLAGS"
+
+ AC_CHECK_HEADER([$6],
+ [ac_vmw_have_lib_header=1])
+
+ CPPFLAGS="$ORIGINAL_CPPFLAGS"
+ else
+ ac_vmw_have_lib_header=1
+ fi
+
+ # Check a specific function in the library if requested.
+ # If it hasn't, just pick a random function from libc, just to make
+ # sure the linker can find the library being tested.
+ if test $ac_vmw_have_lib_header -eq 1; then
+ if test -n "$7"; then
+ ac_vmw_function=$7
+ else
+ ac_vmw_function=strlen
+ fi
+ AC_CHECK_LIB(
+ [$1],
+ [$ac_vmw_function],
+ [ac_vmw_have_lib_func=1],
+ [],
+ [${CUSTOM_$2_LIBS}])
+ fi
+
+ if test $ac_vmw_have_lib_func -eq 1 && test $ac_vmw_have_lib_header -eq 1; then
+ $2_CPPFLAGS="${CUSTOM_$2_CPPFLAGS}"
+ $2_LIBS="${CUSTOM_$2_LIBS}"
+ ac_vmw_have_lib=1
+ fi
+ fi
+
+ # If that didn't work, try with pkg-config.
+ if test $ac_vmw_have_lib -eq 0 && test "$HAVE_PKG_CONFIG" = "yes" && test -n "$3"; then
+ if test -n "$5"; then
+ AC_MSG_CHECKING([for $3 >= $5 (via pkg-config)])
+ if pkg-config --exists '$3 >= $5'; then
+ ac_vmw_have_lib=1
+ fi
+ else
+ AC_MSG_CHECKING([for $3 (via pkg-config)])
+ if pkg-config --exists '$3'; then
+ ac_vmw_have_lib=1
+ fi
+ fi
+
+ if test $ac_vmw_have_lib -eq 1; then
+ # Sometimes pkg-config might fail; for example, "pkg-config gtk+-2.0 --cflags"
+ # fails on OpenSolaris B71. So be pessimistic.
+ ac_vmw_cppflags="`pkg-config --cflags $3`"
+ ac_vmw_ret1=$?
+ ac_vmw_libs="`pkg-config --libs $3`"
+ ac_vmw_ret2=$?
+ if test $ac_vmw_ret1 -eq 0 && test $ac_vmw_ret2 -eq 0; then
+ AC_MSG_RESULT([yes])
+ $2_CPPFLAGS="$ac_vmw_cppflags"
+ $2_LIBS="$ac_vmw_libs"
+ else
+ AC_MSG_RESULT([no])
+ fi
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+
+ # If we still haven't found the lib, try with the library's custom "config" script.
+ # Before checking, flush the AC_PATH_PROG cached variable.
+ unset ac_cv_path_ac_vmw_lib_cfg
+ unset ac_vmw_lib_cfg
+ if test $ac_vmw_have_lib -eq 0 && test -n "$4"; then
+ AC_PATH_PROG([ac_vmw_lib_cfg], [$4], [no])
+ if test "$ac_vmw_lib_cfg" != "no"; then
+ # XXX: icu-config does not follow the "--cflags" and "--libs" convention,
+ # so single it out here to avoid having to replicate all the rest of the
+ # logic elsewhere.
+ if test `basename "$ac_vmw_lib_cfg"` = "icu-config"; then
+ $2_CPPFLAGS="`$ac_vmw_lib_cfg --cppflags`"
+ $2_LIBS="`$ac_vmw_lib_cfg --ldflags`"
+ else
+ $2_CPPFLAGS="`$ac_vmw_lib_cfg --cflags`"
+ $2_LIBS="`$ac_vmw_lib_cfg --libs`"
+ fi
+ ac_vmw_have_lib=1
+ fi
+ fi
+
+ # Finish by executing the user provided action. The call to "true" is needed
+ # because the actions are optional, and we need something inside the block.
+ if test $ac_vmw_have_lib -eq 1; then
+ AC_SUBST([$2_CPPFLAGS])
+ AC_SUBST([$2_LIBS])
+ true
+ $8
+ else
+ true
+ $9
+ fi
+])
+
+
+#
+# AC_VMW_CHECK_LIBXX(library, lvar, pkgname, lconfig, version, header, function,
+# [action-if-found],
+# [action-if-not-found])
+#
+# Similar to AC_VMW_CHECK_LIB, but for C++ libraries.
+#
+# XXX: Getting automake to choose between the C linker and the C++ linker
+# depending on whether we're linking any C++ library was a royal pain in the
+# ass. The classic way to do this is to define an optional source file for a
+# program with an extension of .cxx, using nodist_EXTRA_fooprogram_SOURCES. This
+# causes automake's linker detection algorithm to see a C++ source file and
+# automatically set up the C++ linker and link line for us. Unfortunately, said
+# linker detection doesn't obey conditionals, which means that it'd always pick
+# the C++ linker, regardless of whether it's linking to a C++ library or not.
+# Instead, we are forced to manually set the correct linker in fooprogram_LINK.
+# However, since none of our programs actually contain C++ code, automake
+# doesn't make the CXXLINK variable (which contains the linker as well as all
+# link flags) available to us, so we must hard-code the entire link line into
+# fooprogram_LINK. Not exactly a futureproof solution...
+#
+# Additional references on this problem:
+# http://sources.redhat.com/ml/automake/1999-10/msg00101.html
+# http://lists.gnu.org/archive/html/bug-automake/2008-04/msg00010.html
+# http://www.gnu.org/software/automake/manual/automake.html#Libtool-Convenience-Libraries
+# http://www.gnu.org/software/automake/manual/automake.html#C_002b_002b-Support
+#
+AC_DEFUN([AC_VMW_CHECK_LIBXX],[
+ AC_REQUIRE([AC_VMW_CHECK_LIB])
+ AC_LANG_PUSH([C++])
+ AC_VMW_CHECK_LIB([$1], [$2], [$3], [$4], [$5], [$6], [$7], [$8], [$9])
+ AC_LANG_POP([C++])
+])
+
modulesrc = $(top_srcdir)/modules
$(MODULES):
- $(MAKE) VM_UNAME=$(KERNEL_RELEASE) $(EXTRA_ARGS) -C "$(modulesrc)/$(MODULES_OS)/$@"
+ $(MAKE) VM_UNAME=$(KERNEL_RELEASE) MV=mv RM=rm $(EXTRA_ARGS) \
+ -C "$(modulesrc)/$(MODULES_OS)/$@"
if LINUX
export pvscsidir := $(MODULES_DIR)/drivers/scsi
endif WITH_ROOT_PRIVILEGES
endif LINUX
-if FREEBSD
-export vmblockdir := $(MODULES_DIR)
-export vmhgfsdir := $(MODULES_DIR)
-export vmmemctldir := $(MODULES_DIR)
-export vmsyncdir := $(MODULES_DIR)
-export vmxnetdir := $(MODULES_DIR)
-endif FREEBSD
-
if SOLARIS
export vmhgfsdir := $(MODULES_DIR)
# Solaris does not have Kbuild-like system so we need to supply
clean-local:
for MOD in $(MODULES); do \
if [ -d "$(modulesrc)/$(MODULES_OS)/$$MOD" ]; then \
- $(MAKE) VM_UNAME=$(KERNEL_RELEASE) \
+ $(MAKE) VM_UNAME=$(KERNEL_RELEASE) MV=mv RM=rm \
-C "$(modulesrc)/$(MODULES_OS)/$$MOD" clean || exit 1; \
fi \
done
- $(RM) -f $(modulesrc)/$(MODULES_OS)/*.o $(modulesrc)/$(MODULES_OS)/*.ko
+ rm -f $(modulesrc)/$(MODULES_OS)/*.o $(modulesrc)/$(MODULES_OS)/*.ko
install-exec-hook:
if SOLARIS
for MOD in $(MODULES); do \
- $(MAKE) VM_UNAME=$(KERNEL_RELEASE) \
+ $(MAKE) VM_UNAME=$(KERNEL_RELEASE) MV=mv RM=rm \
-C "$(modulesrc)/$(MODULES_OS)/$$MOD" install || exit 1; \
done
-else
+endif
+if FREEBSD
+ for MOD in $(MODULES); do \
+ $(INSTALL) -d $(DESTDIR)$(MODULES_DIR); \
+ $(INSTALL) -m644 $(modulesrc)/$(MODULES_OS)/$$MOD.ko \
+ $(DESTDIR)$(MODULES_DIR); \
+ done
+endif
+if LINUX
for MOD in $(MODULES); do \
$(INSTALL) -d $(DESTDIR)`eval echo '$$'$${MOD}dir`; \
$(INSTALL) -m644 $(modulesrc)/$(MODULES_OS)/$$MOD/$$MOD.ko \
uninstall-hook:
for MOD in $(MODULES); do \
- $(RM) -f $(DESTDIR)`eval echo '$$'$${MOD}dir`/$$MOD.ko &> /dev/null;\
+ rm -f $(DESTDIR)`eval echo '$$'$${MOD}dir`/$$MOD.ko &> /dev/null;\
done
eval "$$DEPMOD"
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
#define BDOOR_CMD_ACPI_HOTPLUG_MEMORY 57
#define BDOOR_CMD_ACPI_HOTPLUG_CBRET 58
#define BDOOR_CMD_GET_HOST_VIDEO_MODES 59
-#define BDOOR_CMD_MAX 60
+#define BDOOR_CMD_ACPI_HOTPLUG_CPU 60
+#define BDOOR_CMD_MAX 61
/*
* IMPORTANT NOTE: When modifying the behavior of an existing backdoor command,
#define HGFS_PERM_WRITE 2
#define HGFS_PERM_EXEC 1
+/*
+ * Access mode bits.
+ *
+ * Different operating systems have different set of file access mode.
+ * Here are constants that are rich enough to describe all access modes in an OS
+ * independent way.
+ */
+
+typedef uint32 HgfsAccessMode;
+/*
+ * Generic access rights control coarse grain access for the file.
+ * A particular generic rigth can be expanded into different set of specific rights
+ * on different OS.
+ */
+
+/*
+ * HGFS_MODE_GENERIC_READ means ability to read file data and read various file
+ * attributes and properties.
+ */
+#define HGFS_MODE_GENERIC_READ (1 << 0)
+/*
+ * HGFS_MODE_GENERIC_WRITE means ability to write file data and updaate various file
+ * attributes and properties.
+ */
+#define HGFS_MODE_GENERIC_WRITE (1 << 1)
+/*
+ * HGFS_MODE_GENERIC_EXECUE means ability to execute file. For network redirectors
+ * ability to execute usualy implies ability to read data; for local file systems
+ * HGFS_MODE_GENERIC_EXECUTE does not imply ability to read data.
+ */
+#define HGFS_MODE_GENERIC_EXECUTE (1 << 2)
+
+/* Specific rights define fine grain access modes. */
+#define HGFS_MODE_READ_DATA (1 << 3) // Ability to read file data
+#define HGFS_MODE_WRITE_DATA (1 << 4) // Ability to writge file data
+#define HGFS_MODE_APPEND_DATA (1 << 5) // Appending data to the end of file
+#define HGFS_MODE_DELETE (1 << 6) // Ability to delete the file
+#define HGFS_MODE_TRAVERSE_DIRECTORY (1 << 7) // Ability to access files in a directory
+#define HGFS_MODE_LIST_DIRECTORY (1 << 8) // Ability to list file names
+#define HGFS_MODE_ADD_SUBDIRECTORY (1 << 9) // Ability to create a new subdirectory
+#define HGFS_MODE_ADD_FILE (1 << 10) // Ability to create a new file
+#define HGFS_MODE_DELETE_CHILD (1 << 11) // Ability to delete file/subdirectory
+#define HGFS_MODE_READ_ATTRIBUTES (1 << 12) // Ability to read attributes
+#define HGFS_MODE_WRITE_ATTRIBUTES (1 << 13) // Ability to write attributes
+#define HGFS_MODE_READ_EXTATTRIBUTES (1 << 14) // Ability to read extended attributes
+#define HGFS_MODE_WRITE_EXTATTRIBUTES (1 << 15) // Ability to write extended attributes
+#define HGFS_MODE_READ_SECURITY (1 << 16) // Ability to read permissions/ACLs/owner
+#define HGFS_MODE_WRITE_SECURITY (1 << 17) // Ability to change permissions/ACLs
+#define HGFS_MODE_TAKE_OWNERSHIP (1 << 18) // Ability to change file owner/group
/*
* Server-side locking (oplocks and leases).
* only to determine if the ID is valid.
*/
#define HGFS_ATTR_VALID_NON_STATIC_FILEID (1 << 16)
+/*
+ * File permissions that are in effect for the user which runs HGFS server.
+ * Client needs to know effective permissions in order to implement access(2).
+ * Client can't derive it from group/owner/other permissions because of two resaons:
+ * 1. It does not know user/group id of the user which runs HGFS server
+ * 2. Effective permissions account for additional restrictions that may be imposed
+ * by host file system, for example by ACL.
+ */
+#define HGFS_ATTR_VALID_EFFECTIVE_PERMS (1 << 17)
/*
uint32 groupId; /* group identifier, ignored by Windows */
uint64 hostFileId; /* File Id of the file on host: inode_t on Linux */
uint32 volumeId; /* volume identifier, non-zero is valid. */
- uint32 reserved1; /* Reserved for future use */
+ uint32 effectivePerms; /* Permissions in effect for the user on the host. */
uint64 reserved2; /* Reserved for future use */
}
#include "vmware_pack_end.h"
# endif
# include <stdarg.h>
# include <string.h>
+# elif defined(sun)
+# include "vm_basic_types.h"
+# include <sys/types.h>
+# include <sys/varargs.h>
#endif
/*
* Function Prototypes
*/
-#if defined(linux) || defined(__APPLE__) /* if (linux) || (__APPLE__) { */
+#if defined(linux) || defined(__APPLE__) || defined (sun)
# ifdef linux /* if (linux) { */
char *strdup(const char *source);
# error "This os.c file can only be compiled for the FreeBSD kernel."
#endif
+#include <sys/types.h>
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/lock.h> // for struct mtx
#include <sys/kernel.h>
#include <vm/uma.h> // for uma_zone_t
#include <sys/kthread.h> // for kthread_create()
+#include <vm/vm.h>
+#include <vm/vm_extern.h> // for vnode_pager_setsize
#include "vm_basic_types.h"
#include "os.h"
NOT_IMPLEMENTED();
return OS_ERR;
}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * os_SetSize --
+ *
+ * Notifies memory management system that file size has been changed.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *----------------------------------------------------------------------------
+ */
+
+void
+os_SetSize(struct vnode* vp, // IN: vnode which size has changed
+ off_t newSize) // IN: new file size
+{
+ vnode_pager_setsize(vp, newSize);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * os_FlushRange --
+ *
+ * Flushes dirty pages associated with the file.
+ *
+ * Results:
+ * Always retun 0 (success) for now since it is NOOP.
+ *
+ * Side effects:
+ * None.
+ *----------------------------------------------------------------------------
+ */
+
+int
+os_FlushRange(struct vnode *vp, // IN: vnode which data needs flushing
+ off_t start, // IN: starting offset in the file to flush
+ uint32_t length) // IN: length of data to flush
+{
+ /*
+ * XXX: NOOP for now. This routine is needed to maintain coherence
+ * between memory mapped data and data for read/write operations.
+ * Will need to implement when adding support for memory mapped files to HGFS
+ * for FreeBsd.
+ */
+ return 0;
+}
/*
* os.h --
*
- * Implementation OS X / FreeBSD independent memory allocation and
+ * Wrappers for OS specific functions that are different between OS X and FreeBsd.
+ * 1. Implementation OS X / FreeBSD independent memory allocation and
* thread synchronization routines.
+ * 2. Interaction with memory manager/pager.
*/
#ifndef _OS_H_
uint32 bufOutSize);
extern Bool os_utf8_conversion_needed(void);
+// Memory manager/pager functions
+void os_SetSize(struct vnode *vp, off_t newSize);
+int os_FlushRange(struct vnode *vp, off_t start, uint32_t length);
#endif // ifndef _OS_H_
HgfsFileHashTable *htp,
Bool rootVnode,
Bool createFile,
- int permissions);
+ int permissions,
+ off_t fileSize);
/* Allocation/initialization/free of open file state */
static HgfsFile *HgfsAllocFile(const char *fileName, HgfsFileType fileType,
struct vnode *dvp, HgfsFileHashTable *htp,
- int permissions);
+ int permissions, off_t fileSize);
/* Acquiring/releasing file state */
static HgfsFile *HgfsInsertFile(const char *fileName,
HgfsFileHashTable *htp);
static void HgfsReleaseFile(HgfsFile *fp, HgfsFileHashTable *htp);
static int HgfsInitFile(HgfsFile *fp, struct vnode *dvp, const char *fileName,
- HgfsFileType fileType, int permissions);
+ HgfsFileType fileType, int permissions, off_t fileSize);
static void HgfsFreeFile(HgfsFile *fp);
/* Adding/finding/removing file state from hash table */
HgfsFileType fileType, // IN: Type of file
HgfsFileHashTable *htp, // IN: File hash table
Bool createFile, // IN: Creating a new file or open existing?
- int permissions) // IN: Permissions for the created file
+ int permissions, // IN: Permissions for the created file
+ off_t fileSize) // IN: File size if the vnode is VREG
{
return HgfsVnodeGetInt(vpp, dvp, sip, vfsp, fileName, fileType, htp, FALSE,
- createFile, permissions);
+ createFile, permissions, fileSize);
}
HgfsFileType fileType, // IN: Type of file
HgfsFileHashTable *htp) // IN: File hash table
{
- return HgfsVnodeGetInt(vpp, NULL, sip, vfsp, fileName, fileType, htp, TRUE, FALSE, 0);
+ return HgfsVnodeGetInt(vpp, NULL, sip, vfsp, fileName, fileType, htp, TRUE,
+ FALSE, 0, 0);
}
* Results:
* Returns 0 if the handle is set and had been referenced,
* EACCES if the handle is set but has an incompatible open mode,
- * ENOENT if no hadnle is set for the vnode
+ * ENOENT if no handle is set for the vnode
*
* Side effects:
* None.
int
HgfsCheckAndReferenceHandle(struct vnode *vp, // IN: Vnode to check handle of
+ Bool mmap, // IN: True if it is mmap call
int requestedOpenMode) // IN: Requested open mode
{
HgfsFile *fp;
- Bool ret;
+ int ret;
ASSERT(vp);
ret = fp->handleRefCount ? 0 : ENOENT;
if (ret == 0) {
if (HgfsIsModeCompatible(requestedOpenMode, fp->mode)) {
- fp->handleRefCount++;
+ DEBUG(VM_DEBUG_LOG, "Handle exists, %d %d %d\n",
+ mmap, fp->mmapped, fp->handleRefCount);
+ /*
+ * Do nothing for subsequent mmap requests since OS invokes mnomap only once
+ * for multiple mmap calls.
+ */
+ if (!mmap || !fp->mmapped) {
+ if (fp->implicitlyOpened) {
+ /*
+ * Consider it a regular open from now on.
+ * Handle already had been referenced, no need to increment
+ * count.
+ */
+ fp->implicitlyOpened = FALSE;
+ DEBUG(VM_DEBUG_LOG, "Clear implicitly opened flag\n");
+ } else {
+ fp->handleRefCount++;
+ }
+ fp->mmapped = fp->mmapped || mmap;
+ }
} else {
ret = EACCES;
+ DEBUG(VM_DEBUG_LOG, "Incompatible modes: %d %d\n", requestedOpenMode, fp->mode);
}
}
void
HgfsSetOpenFileHandle(struct vnode *vp, // IN: Vnode to set handle for
HgfsHandle handle, // IN: Value of handle
- HgfsMode openMode) // IN: Mode assosiated with the handle
+ HgfsMode openMode, // IN: Mode assosiated with the handle
+ Bool implicit) // IN: TRUE if not in VNOP_OPEN context
{
HgfsFile *fp;
fp->handle = handle;
fp->mode = openMode;
fp->handleRefCount = 1;
+ fp->implicitlyOpened = implicit;
DEBUG(VM_DEBUG_STATE, "HgfsSetOpenFileHandle: set handle for %s to %d\n",
HGFS_VP_TO_FILENAME(vp), fp->handle);
* Returns new handle reference count.
* When the returned value is 0 returns the file handle which need to be closed
* on the host.
+ * Returns special value -1 if the handle had not been open.
*
* Side effects:
* None.
*/
int
-HgfsReleaseOpenFileHandle(struct vnode *vp, // IN
- HgfsHandle *handleToClose) // OUT
+HgfsReleaseOpenFileHandle(struct vnode *vp, // IN: correspondent vnode
+ Bool mnomap, // IN: True if called from mnomap
+ HgfsHandle *handleToClose) // OUT: Host handle to close
{
- int ret;
+ int ret = -1;
HgfsFile *fp;
ASSERT(vp);
os_rw_lock_lock_exclusive(fp->handleLock);
/* Make sure the reference count is not going negative! */
- ASSERT(fp->handleRefCount > 0);
+ ASSERT(fp->handleRefCount >= 0);
- --fp->handleRefCount;
- ret = fp->handleRefCount;
+ if (fp->handleRefCount > 0) {
+ --fp->handleRefCount;
+ ret = fp->handleRefCount;
+ if (mnomap) {
+ fp->mmapped = FALSE;
+ }
- /* If the reference count has gone to zero, clear the handle. */
- if (ret == 0) {
- DEBUG(VM_DEBUG_LOG, "closing directory handle\n");
- *handleToClose = fp->handle;
- fp->handle = 0;
- } else {
- DEBUG(VM_DEBUG_LOG, "ReleaseOpenFileHandle with a refcount of: %d\n",
- fp->handleRefCount);
+ /* If the reference count has gone to zero, clear the handle. */
+ if (ret == 0) {
+ DEBUG(VM_DEBUG_LOG, "closing directory handle\n");
+ *handleToClose = fp->handle;
+ fp->handle = 0;
+ } else {
+ DEBUG(VM_DEBUG_LOG, "ReleaseOpenFileHandle with a refcount of: %d\n",
+ fp->handleRefCount);
+ }
}
-
os_rw_lock_unlock_exclusive(fp->handleLock);
return ret;
/* First verify if a vnode for the filename is already allocated. */
existingFp = HgfsFindFile(fileName, htp);
if (existingFp != NULL) {
+ DEBUG(VM_DEBUG_LOG, "Found existing vnode for %s\n", fileName);
if (failIfExist) {
err = EEXIST;
} else {
HgfsFileHashTable *htp, // IN: File hash
Bool rootVnode, // IN: Is this a root vnode?
Bool fileCreate, // IN: Is it a new file creation?
- int permissions) // IN: Permissions for new files
+ int permissions, // IN: Permissions for new files
+ off_t fileSize) // IN: Size of the file
{
struct vnode *vp;
int ret;
}
/* We now allocate our private open file structure. */
- fp = (void *)HgfsAllocFile(fileName, fileType, dvp, htp, permissions);
+ fp = (void *)HgfsAllocFile(fileName, fileType, dvp, htp, permissions, fileSize);
if (fp == NULL) {
ret = ENOMEM;
goto destroyOut;
HgfsFileHashTable *htp, // IN
Bool rootVnode, // IN
Bool fileCreate, // IN
- int permissions) // IN
+ int permissions, // IN
+ off_t fileSize) // IN
{
struct vnode *vp;
struct vnode_fsparam params;
}
params.vnfs_mp = vfsp;
- params.vnfs_str = NULL;
- params.vnfs_dvp = NULL;
+ params.vnfs_str = "hgfs";
+ params.vnfs_dvp = dvp;
params.vnfs_fsnode = NULL;
params.vnfs_vops = HgfsVnodeOps;
params.vnfs_marksystem = FALSE;
params.vnfs_rdev = 0;
- params.vnfs_filesize = 0;
+ params.vnfs_filesize = fileSize;
params.vnfs_cnp = NULL;
/* Do not let OS X cache vnodes for us. */
params.vnfs_flags = VNFS_NOCACHE | VNFS_CANTCACHE;
goto out;
}
- fp = HgfsAllocFile(fileName, fileType, dvp, htp, permissions);
+ fp = HgfsAllocFile(fileName, fileType, dvp, htp, permissions, fileSize);
params.vnfs_fsnode = (void *)fp;
if (params.vnfs_fsnode == NULL) {
HgfsFileType fileType, // IN: Type of file
struct vnode *dvp, // IN: Parent directory vnode
HgfsFileHashTable *htp, // IN: Hash table
- int permissions) // IN: permissions for creating new files
+ int permissions, // IN: permissions for creating new files
+ off_t fileSize) // IN: file size
{
HgfsFile *fp;
fp = os_malloc(sizeof *fp, M_ZERO | M_WAITOK);
if (fp != NULL) {
DEBUG(VM_DEBUG_INFO, "HgfsGetFile: allocated HgfsFile for %s.\n", fileName);
- if (HgfsInitFile(fp, dvp, fileName, fileType, permissions) != 0) {
+ if (HgfsInitFile(fp, dvp, fileName, fileType, permissions, fileSize) != 0) {
DEBUG(VM_DEBUG_FAIL, "Failed to initialize HgfsFile");
os_free(fp, sizeof(*fp));
fp = NULL;
static HgfsFile *
HgfsInsertFile(const char *fileName, // IN: Filename to get file for
HgfsFile *fp, // IN: HgfsFile object to insert
- HgfsFileHashTable *htp) // IN: Hash table to look in
+ HgfsFileHashTable *htp) // IN: Hash table to look in
{
HgfsFile *existingFp = NULL;
os_mutex_lock(htp->mutex);
existingFp = HgfsFindFile(fileName, htp);
- if (existingFp) { // HgfsFile with this name alrady exists
+ if (existingFp) { // HgfsFile with this name already exists
int ret = vnode_get(existingFp->vnodep);
if (ret != 0) {
/*
* It is not clear why vnode_get may fail while there is HgfsFile in
* our hash table. Most likely it will never happen.
* However if this ever occur the safest approach is to remove
- * the HgsfFle structure from the hash table but do dont free it.
+ * the HgfsFile structure from the hash table but do dont free it.
* It should be freed later on when the vnode is recycled.
*/
DblLnkLst_Unlink1(&existingFp->listNode);
existingFp = NULL;
}
}
- if (existingFp) {
+ if (existingFp == NULL) {
HgfsAddFile(fp, htp);
}
struct vnode *dvp, // IN: Paretn directory vnode
const char *fileName, // IN: Name of file
HgfsFileType fileType, // IN: Type of file
- int permissions) // IN: Permissions for new files
+ int permissions, // IN: Permissions for new files
+ off_t fileSize) // IN: File size
{
int len;
fp->handleRefCount = 0;
fp->handle = 0;
+ fp->implicitlyOpened = FALSE;
+ fp->mmapped = FALSE;
+ fp->fileSize = fileSize;
fp->handleLock = os_rw_lock_alloc_init("hgfs_rw_handle_lock");
if (!fp->handleLock) {
*/
void
-HgfsFreeFile(HgfsFile *fp)
+HgfsFreeFile(HgfsFile *fp) // IN: HgfsFile structure to free
{
ASSERT(fp);
os_rw_lock_free(fp->handleLock);
os_free(fp, sizeof *fp);
}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsMarkFileMmapped --
+ *
+ * Sets/Clears mmap flag in HgfsFile structure
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsMarkFileMmapped(struct vnode *vp, // vnode which state is being changed
+ Bool mmapped) // New mapping state
+{
+ HgfsFile *fp;
+ ASSERT(vp);
+ fp = HGFS_VP_TO_FP(vp);
+ fp->mmapped = mmapped;
+}
+
/* Adding/finding/removing file state from hash table */
requestedMode == existingMode);
}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSetFileSize --
+ *
+ * Notifies virtual memory system that file size has changed.
+ * Required for memory mapped files to work properly.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsSetFileSize(struct vnode *vp, // IN: vnode which file size has changed
+ off_t newSize) // IN: new value for file size
+{
+ HgfsFile *fp;
+
+ ASSERT(vp);
+ fp = HGFS_VP_TO_FP(vp);
+ if (fp->fileSize != newSize) {
+ fp->fileSize = newSize;
+ os_SetSize(vp, newSize);
+ }
+}
#define HGFS_VP_TO_PERMISSIONS(vp) \
HGFS_VP_TO_FP(vp)->permissions
+#define HGFS_VP_TO_MMAPPED(vp) \
+ HGFS_VP_TO_FP(vp)->mmapped
+
+#define HGFS_VP_TO_FILESIZE(vp) \
+ HGFS_VP_TO_FP(vp)->fileSize
+
/*
* Types
OS_RWLOCK_T *rwFileLock;
#endif
+ /* TRUE indicates that memory mapping has been established for the file. */
+ Bool mmapped;
+ /*
+ * TRUE if the handle has an additional reference which is the
+ * result of reading file before opening which occurs on MAC OS.
+ */
+ Bool implicitlyOpened;
+ /*
+ * File size. HGFS must tell memory management system when file size is changed.
+ * It implies that HGFS has to know if a write request writes data beyond EOF thus
+ * it has to maintain local copy of file size that is kept in sync with the size
+ * reported to memory manager/pager.
+ */
+ off_t fileSize;
} HgfsFile;
/* The hash table for file state. */
int HgfsVnodeGet(struct vnode **vpp, struct vnode *dp, struct HgfsSuperInfo *sip,
struct mount *vfsp, const char *fileName, HgfsFileType fileType,
- HgfsFileHashTable *htp, Bool createFile, int permissions);
+ HgfsFileHashTable *htp, Bool createFile, int permissions,
+ off_t fileSize);
int HgfsVnodeGetRoot(struct vnode **vpp, struct HgfsSuperInfo *sip, struct mount *vfsp,
const char *fileName, HgfsFileType fileType, HgfsFileHashTable *htp);
int HgfsReleaseVnodeContext(struct vnode *vp, HgfsFileHashTable *htp);
Bool HgfsFileHashTableIsEmpty(struct HgfsSuperInfo *sip, HgfsFileHashTable *htp);
/* Handle get/set/clear functions */
-void HgfsSetOpenFileHandle(struct vnode *vp, HgfsHandle handle, HgfsMode openMode);
+void HgfsSetOpenFileHandle(struct vnode *vp, HgfsHandle handle,
+ HgfsMode openMode, Bool implicit);
int HgfsGetOpenFileHandle(struct vnode *vp, HgfsHandle *outHandle);
-int HgfsReleaseOpenFileHandle(struct vnode *vp, HgfsHandle *handleToClose);
-int HgfsCheckAndReferenceHandle(struct vnode *vp, int requestedOpenMode);
+int HgfsReleaseOpenFileHandle(struct vnode *vp, Bool mnomap, HgfsHandle *handleToClose);
+int HgfsCheckAndReferenceHandle(struct vnode *vp, Bool mmap, int requestedOpenMode);
int HgfsHandleIncrementRefCount(struct vnode *vp);
+void HgfsSetFileSize(struct vnode *vp, off_t newSize);
#endif /* _STATE_H_ */
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
#error No compiler defined for RDTSC
#endif /* __GNUC__ */
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DEBUGBREAK --
+ *
+ * Does an int3 for MSVC / GCC. This is a macro to make sure int3 is
+ * always inlined.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef _MSC_VER
+#define DEBUGBREAK() __debugbreak()
+#else
+#define DEBUGBREAK() __asm__ (" int $3 ")
+#endif
+
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
struct vnode *vp = ap->a_vp;
int mode = ap->a_mode;
- return HgfsOpenInt(vp, mode);
+ return HgfsOpenInt(vp, mode, FALSE);
}
{
struct vnode *vp = ap->a_vp;
int mode = ap->a_mode;
+ HgfsAccessMode accessMode = 0;
+ Bool isDir = vp->v_type == VDIR;
+ if (mode & VREAD) {
+ accessMode |= isDir ? HGFS_MODE_LIST_DIRECTORY : HGFS_MODE_READ_DATA;
+ accessMode |= HGFS_MODE_READ_ATTRIBUTES;
+ }
+ if (mode & VWRITE) {
+ if (isDir) {
+ accessMode |= HGFS_MODE_ADD_FILE | HGFS_MODE_ADD_SUBDIRECTORY |
+ HGFS_MODE_DELETE | HGFS_MODE_DELETE_CHILD |
+ HGFS_MODE_WRITE_ATTRIBUTES;
+ } else {
+ accessMode |= HGFS_MODE_WRITE_DATA | HGFS_MODE_ADD_SUBDIRECTORY |
+ HGFS_MODE_DELETE | HGFS_MODE_WRITE_ATTRIBUTES;
+ }
+ }
+ if (mode & VAPPEND) {
+ accessMode |= isDir ? HGFS_MODE_ADD_SUBDIRECTORY : HGFS_MODE_APPEND_DATA;
+ }
+ if (mode & VEXEC) {
+ accessMode |= isDir ? HGFS_MODE_TRAVERSE_DIRECTORY : HGFS_MODE_GENERIC_EXECUTE;
+ }
- return HgfsAccessInt(vp, mode);
+ return HgfsAccessInt(vp, accessMode);
}
struct vnode *vp = ap->a_vp;
struct uio *uiop = ap->a_uio;
- return HgfsReadInt(vp, uiop);
+ return HgfsReadInt(vp, uiop, FALSE);
}
struct uio *uiop = ap->a_uio;
int ioflag = ap->a_ioflag;
- return HgfsWriteInt(vp, uiop, ioflag);
+ return HgfsWriteInt(vp, uiop, ioflag, FALSE);
}
HgfsFileType *type, Bool *done);
int HgfsDirOpen(HgfsSuperInfo *sip, struct vnode *vp);
int HgfsFileOpen(HgfsSuperInfo *sip, struct vnode *vp,
- int flag, int permissions);
+ int flag, int permissions, Bool implicit);
int HgfsDirClose(HgfsSuperInfo *sip, struct vnode *vp);
int HgfsFileClose(HgfsSuperInfo *sip, struct vnode *vp, int flag);
int HgfsDoRead(HgfsSuperInfo *sip, HgfsHandle handle, uint64_t offset,
*
* HgfsSetattrInt --
*
- * Maps the Solaris attributes to Hgfs attributes (by calling
+ * Maps the MAC OS/FreeBsd attributes to Hgfs attributes (by calling
* HgfsSetattrCopy()) and sends a set attribute request to the Hgfs server.
*
- * "Sets the attributes for the supplied vnode." (Solaris Internals, p537)
- *
* Results:
* Returns 0 on success and a non-zero error code on error.
*
int
HgfsSetattrInt(struct vnode *vp, // IN : vnode of the file
- HgfsVnodeAttr *vap) // IN : attributes container
+ HgfsVnodeAttr *vap) // IN : attributes container
{
HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
HgfsKReqHandle req;
DEBUG(VM_DEBUG_FAIL, "Error encountered with ret = %d\n", ret);
}
goto destroyOut;
+ } else {
+ if (HGFS_VATTR_SIZE_IS_ACTIVE(vap, HGFS_VA_DATA_SIZE)) {
+ HgfsSetFileSize(vp, vap->HGFS_VA_DATA_SIZE);
+ }
}
destroyOut:
* Composes the full pathname of this file and sends a DELETE_FILE request
* by calling HgfsDelete().
*
- * "Removes the file for the supplied vnode." (Solaris Internals, p537)
- *
* Results:
* Returns 0 on success or a non-zero error code on error.
*
goto out;
}
+ os_FlushRange(vp, 0, HGFS_VP_TO_FILESIZE(vp));
+ os_SetSize(vp, 0);
+
/* We can now send the delete request. */
ret = HgfsDelete(sip, HGFS_VP_TO_FILENAME(vp), HGFS_OP_DELETE_FILE_V3);
int
HgfsOpenInt(struct vnode *vp, // IN: Vnode to open.
- int mode) // IN: Mode of vnode being opened.
+ int mode, // IN: Mode of vnode being opened.
+ Bool implicit) // IN: TRUE if called outside of VNOP_OPEN.
{
HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
DEBUG(VM_DEBUG_LOG, "Enter %s.\n", HGFS_VP_TO_FILENAME(vp));
* are ignored by HgfsFileOpen.
*/
DEBUG(VM_DEBUG_COMM, "opening a file with flag %x\n", mode);
- return HgfsFileOpen(sip, vp, mode, HGFS_VP_TO_PERMISSIONS(vp));
+ return HgfsFileOpen(sip, vp, mode, HGFS_VP_TO_PERMISSIONS(vp), implicit);
}
default:
*vpp = dvp;
return 0;
}
-
+
/*
* Get pointer to the superinfo. If the device is not attached,
* hgfsInstance will not be valid and we immediately return an error.
attrV2.type, // Type of file
&sip->fileHashTable, // File hash table
FALSE, // Not a new file creation
- 0); // No permissions - not a new file
+ 0, // No permissions - not a new file
+ attrV2.size); // File size
if (ret) {
DEBUG(VM_DEBUG_FAIL, "couldn't create vnode for \"%s\".\n", path);
if (ret >= 0) {
/* Create the vnode for this file. */
ret = HgfsVnodeGet(vpp, dvp, sip, HGFS_VP_TO_MP(dvp), fullname,
- HGFS_FILE_TYPE_REGULAR, &sip->fileHashTable, FALSE, mode);
+ HGFS_FILE_TYPE_REGULAR, &sip->fileHashTable, TRUE,
+ mode, 0);
/* HgfsVnodeGet() guarantees this. */
ASSERT(ret != 0 || *vpp);
+ /*
+ * NOTE: This is a temporary workaround.
+ * This condition may occur because we look up vnodes by file name in the
+ * vnode cache.
+ * There is a race condition when file is already deleted but still referenced -
+ * thus vnode still exist. If a new file with the same name is created I
+ * can neither use the vnode of the deleted file nor insert a new vnode with
+ * the same name - thus I fail the request. This behavior is not correct and will
+ * be fixed after further restructuring if the source code.
+ */
+ if (ret == EEXIST) {
+ ret = EIO;
+ }
} else {
DEBUG(VM_DEBUG_FAIL, "couldn't create full path name.\n");
ret = ENAMETOOLONG;
int
HgfsReadInt(struct vnode *vp, // IN : Vnode to read from
- struct uio *uiop) // IN/OUT: Buffer to write data into.
+ struct uio *uiop, // IN/OUT: Buffer to write data into.
+ Bool pagingIo) // IN: True if the read is a result of a page fault
{
HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
HgfsHandle handle;
DEBUG(VM_DEBUG_ENTRY, "entry %s.\n", HGFS_VP_TO_FILENAME(vp));
/* We can't read from directories, that's what readdir() is for. */
- if (HGFS_VP_TO_VTYPE(vp) == VDIR) {
- DEBUG(VM_DEBUG_FAIL, "cannot read directories.\n");
- return EISDIR;
+ if (HGFS_VP_TO_VTYPE(vp) != VREG) {
+ DEBUG(VM_DEBUG_FAIL, "Can only read regular files.\n");
+ return (HGFS_VP_TO_VTYPE(vp) == VDIR) ? EISDIR : EPERM;
}
/* off_t is a signed quantity */
*/
ret = HgfsGetOpenFileHandle(vp, &handle);
if (ret) {
- DEBUG(VM_DEBUG_FAIL, "could not get handle.\n");
+ DEBUG(VM_DEBUG_FAIL, "could not get handle.\n");
+ return EINVAL;
+ }
+
+ /* Flush mmaped data to maintain data coherence between mmap and read. */
+ if (!pagingIo) {
+ ret = os_FlushRange(vp, offset, HGFS_UIOP_TO_RESID(uiop));
+ if (ret) {
+ DEBUG(VM_DEBUG_FAIL, "could not flush data.\n");
return EINVAL;
}
+ }
/*
* Here we loop around HgfsDoRead with requests less than or equal to
handle, HGFS_VP_TO_FILENAME(vp));
/* Request at most HGFS_IO_MAX bytes */
- size = (HGFS_UIOP_TO_RESID(uiop) > HGFS_IO_MAX) ? HGFS_IO_MAX : HGFS_UIOP_TO_RESID(uiop);
+ size = (HGFS_UIOP_TO_RESID(uiop) > HGFS_IO_MAX) ? HGFS_IO_MAX :
+ HGFS_UIOP_TO_RESID(uiop);
/* Send one read request. */
ret = HgfsDoRead(sip, handle, offset, size, uiop);
* We call HgfsDoWrite() once with requests less than or equal to
* HGFS_IO_MAX bytes until the user's write request has completed.
*
- * "Writes the range supplied for the given vnode. The write system call
- * typically maps the requested range of a file into kernel memory and then
- * uses vop_putpage() to do the real work." (Solaris Internals, p538)
- *
* Results:
* Returns 0 on success and error code on error.
*
int
HgfsWriteInt(struct vnode *vp, // IN : the vnode of the file
- struct uio *uiop, // IN/OUT: location of data to be written
- int ioflag) // IN : hints & other directives
+ struct uio *uiop, // IN/OUT: location of data to be written
+ int ioflag, // IN : hints & other directives
+ Bool pagingIo) // IN: True if the write is originated by memory manager
{
HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
HgfsHandle handle;
uint64_t offset;
int ret;
+ int error = 0;
DEBUG(VM_DEBUG_ENTRY, "entry. (vp=%p)\n", vp);
return EINVAL;
}
+ /* Flush mmaped data to maintain data coherence between mmap and read. */
+ if (!pagingIo && (ioflag & IO_APPEND) == 0) {
+ ret = os_FlushRange(vp, offset, HGFS_UIOP_TO_RESID(uiop));
+ }
+
/*
* We loop around calls to HgfsDoWrite() until either (1) we have written all
* of our data or (2) an error has occurred. HGFS_UIOP_TO_RESID(uiop) is decremented
* function header of HgfsDoWrite() for a more complete explanation.
*/
DEBUG(VM_DEBUG_INFO, "HgfsDoWrite failed, returning %d\n", -ret);
- return -ret;
+ error = -ret;
+ break;
}
/* Increment the offest by the amount already written. */
} while (HGFS_UIOP_TO_RESID(uiop));
- /* We have completed the user's write request, so return success. */
+ /* Need to notify memory manager if written data extended the file. */
+ if (!pagingIo && (offset > HGFS_VP_TO_FILESIZE(vp))) {
+ if ((ioflag & IO_APPEND) == 0) {
+ os_SetSize(vp, offset);
+ } else {
+ off_t oldSize = HGFS_VP_TO_FILESIZE(vp);
+ off_t writtenData = offset - HGFS_UIOP_TO_OFFSET(uiop);
+ os_SetSize(vp, oldSize + writtenData);
+ }
+ }
+ /* We have completed the user's write request, so return. */
DEBUG(VM_DEBUG_LOG, "Exit %s.\n", HGFS_VP_TO_FILENAME(vp));
- return 0;
+ return error;
}
}
ret = HgfsVnodeGet(vpp, dvp, sip, HGFS_VP_TO_MP(dvp), fullName,
- HGFS_FILE_TYPE_DIRECTORY, &sip->fileHashTable, TRUE, mode);
+ HGFS_FILE_TYPE_DIRECTORY, &sip->fileHashTable, TRUE,
+ mode, 0);
if (ret) {
ret = EIO;
goto destroyOut;
* There is no different open modes for directories thus the handle is compatible.
*/
os_rw_lock_lock_exclusive(fp->handleLock);
- ret = HgfsCheckAndReferenceHandle(vp, 0);
+ ret = HgfsCheckAndReferenceHandle(vp, FALSE, 0);
if (ret == ENOENT) { // Handle is not set, need to get one from the host
if (HGFS_IS_ROOT_VNODE(sip, vp)) {
* We successfully received a reply, so we need to save the handle in
* this file's HgfsOpenFile and return success.
*/
- HgfsSetOpenFileHandle(vp, handle, 0);
+ HgfsSetOpenFileHandle(vp, handle, HGFS_OPEN_MODE_READ_ONLY, FALSE);
}
}
os_rw_lock_unlock_exclusive(fp->handleLock);
HgfsFileOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
struct vnode *vp, // IN: Vnode of file to open
int flag, // IN: Flags of open
- int permissions) // IN: Permissions of open (only when creating)
+ int permissions, // IN: Permissions of open (only when creating)
+ Bool implicit) // IN: TRUE if called outside of HgfsOpenInt
{
char *fullPath = NULL;
uint32 fullPathLen;
* If it is true then add reference to vnode and grant the access, otherwise
* deny the access.
*/
- ret = HgfsCheckAndReferenceHandle(vp, openMode);
+ ret = HgfsCheckAndReferenceHandle(vp, FALSE, openMode);
if (ret == ENOENT) { // Handle is not set, need to get one from the host
int requestedMode = HGFS_OPEN_MODE_READ_WRITE;
* Try exact open mode now.
*/
DEBUG(VM_DEBUG_FAIL, "RW mode failed, re-submitting original mode = %d.\n",
- ret);
+ openMode);
requestedMode = openMode;
ret = HgfsSendOpenRequest(sip, requestedMode, openFlags,
permissions, fullPath, fullPathLen, &handle);
* this file's HgfsOpenFile and return success.
*/
if (ret == 0) {
- HgfsSetOpenFileHandle(vp, handle, requestedMode);
+ HgfsSetOpenFileHandle(vp, handle, requestedMode, implicit);
}
}
os_rw_lock_unlock_exclusive(fp->handleLock);
out:
- DEBUG(VM_DEBUG_LOG, "Exit %s.\n", HGFS_VP_TO_FILENAME(vp));
+ DEBUG(VM_DEBUG_LOG, "Exit (%d) %s.\n", ret, HGFS_VP_TO_FILENAME(vp));
return ret;
}
* Check to see if we should close the file handle on the host ( which happen when
* the reference count of the current handle become 0.
*/
- if (HgfsReleaseOpenFileHandle(vp, &handleToClose) == 0) {
+ if (HgfsReleaseOpenFileHandle(vp, FALSE, &handleToClose) == 0) {
ret = HgfsCloseServerDirHandle(sip, handleToClose);
}
DEBUG(VM_DEBUG_LOG, "Exit %s.\n", HGFS_VP_TO_FILENAME(vp));
* Check to see if we should close the file handle on the host ( which happen when
* the reference count of the current handle become 0.
*/
- if (HgfsReleaseOpenFileHandle(vp, &handleToClose) == 0) {
+ if (HgfsReleaseOpenFileHandle(vp, FALSE, &handleToClose) == 0) {
ret = HgfsCloseServerFileHandle(sip, handleToClose);
}
DEBUG(VM_DEBUG_LOG, "Exit %s.\n", HGFS_VP_TO_FILENAME(vp));
ret = HgfsGetStatus(req, repSize);
if (ret == 0) {
ret = HgfsVnodeGet(vpp, dvp, sip, HGFS_VP_TO_MP(dvp), fullName,
- HGFS_FILE_TYPE_SYMLINK, &sip->fileHashTable, TRUE, 0);
+ HGFS_FILE_TYPE_SYMLINK, &sip->fileHashTable, TRUE, 0, 0);
if (ret) {
ret = EIO;
}
return ret;
}
+
/*
*----------------------------------------------------------------------------
*
/*
*----------------------------------------------------------------------------
*
- * HgfsAccessInt --
+ * IsModeCompatible --
*
- * Check to ensure the user has the specified type of access to the file.
+ * Checks if the requested mode is compatible with permissions.
*
* Results:
- * Returns 0 if access is allowed and a non-zero error code otherwise.
+ * Returns TRUE if the mode is compatible, FALSE otherwise.
*
* Side effects:
* None.
*----------------------------------------------------------------------------
*/
-int
-HgfsAccessInt(struct vnode *vp, // IN: Vnode to check access for
- int mode) // IN: Access mdoe requested.
+static Bool
+IsModeCompatible(HgfsAccessMode mode, // IN: Requested open mode
+ uint32 permissions) // IN: Effective user permissions
{
- HgfsVnodeAttr va;
- int ret = 0;
+ if ((permissions & HGFS_PERM_READ) == 0) {
+ if ((mode & (HGFS_MODE_GENERIC_READ |
+ HGFS_MODE_READ_DATA |
+ HGFS_MODE_LIST_DIRECTORY |
+ HGFS_MODE_READ_ATTRIBUTES |
+ HGFS_MODE_READ_EXTATTRIBUTES |
+ HGFS_MODE_READ_SECURITY)) != 0) {
+ return FALSE;
+ }
+ }
- DEBUG(VM_DEBUG_LOG, "Enter %s.\n", HGFS_VP_TO_FILENAME(vp));
+ if ((permissions & HGFS_PERM_WRITE) == 0) {
+ if ((mode & (HGFS_MODE_GENERIC_WRITE |
+ HGFS_MODE_WRITE_DATA |
+ HGFS_MODE_APPEND_DATA |
+ HGFS_MODE_DELETE |
+ HGFS_MODE_ADD_SUBDIRECTORY |
+ HGFS_MODE_DELETE_CHILD |
+ HGFS_MODE_WRITE_ATTRIBUTES |
+ HGFS_MODE_WRITE_EXTATTRIBUTES |
+ HGFS_MODE_WRITE_SECURITY |
+ HGFS_MODE_TAKE_OWNERSHIP |
+ HGFS_MODE_ADD_FILE)) != 0) {
+ return FALSE;
+ }
+ }
- /* Get the attributes for this file from the Hgfs server. */
- ret = HgfsGetattrInt(vp, &va);
- if (ret) {
- return ret;
+ if ((permissions & HGFS_PERM_EXEC) == 0) {
+ if ((mode & (HGFS_MODE_GENERIC_EXECUTE |
+ HGFS_MODE_TRAVERSE_DIRECTORY)) != 0) {
+ return FALSE;
+ }
}
+ return TRUE;
+}
- DEBUG(VM_DEBUG_INFO, "vp's mode: %o\n", va.va_mode);
- if ((mode & S_ISUID) && !(va.va_mode & S_ISUID)) {
- DEBUG(VM_DEBUG_FAIL, "Special: user id not set on execution (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsAccessInt --
+ *
+ * Check to ensure the user has the specified type of access to the file.
+ *
+ * Results:
+ * Returns 0 if access is allowed and a non-zero error code otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
- if ((mode & S_ISGID) && !(va.va_mode & S_ISGID)) {
- DEBUG(VM_DEBUG_FAIL, "Special: group id not set on execution(%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
+int
+HgfsAccessInt(struct vnode *vp, // IN: Vnode to check access for
+ HgfsAccessMode mode) // IN: Access mode requested.
+{
+ int ret = 0;
+ HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
+ HgfsAttrV2 hgfsAttrV2;
- if ((mode & S_ISVTX) && !(va.va_mode & S_ISVTX)) {
- DEBUG(VM_DEBUG_FAIL, "Special: sticky bit not set (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
+ DEBUG(VM_DEBUG_FAIL, "HgfsAccessInt is called\n");
- if ((mode & S_IRUSR) && !(va.va_mode & S_IRUSR)) {
- DEBUG(VM_DEBUG_FAIL, "Owner: read access not allowed (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
+ ret = HgfsDoGetattrByName(HGFS_VP_TO_FILENAME(vp), sip, &hgfsAttrV2);
+ if (ret == 0) {
+ uint32 effectivePermissions;
+ if (hgfsAttrV2.mask & HGFS_ATTR_VALID_EFFECTIVE_PERMS) {
+ effectivePermissions = hgfsAttrV2.effectivePerms;
+ } else {
+ /*
+ * If the server did not return actual effective permissions then
+ * need to calculate ourselves. However we should avoid unnecessary denial of
+ * access so perform optimistic permissions calculation.
+ * It is safe since host enforces necessary restrictions regardless of
+ * the client's decisions.
+ */
+ effectivePermissions =
+ hgfsAttrV2.ownerPerms | hgfsAttrV2.groupPerms | hgfsAttrV2.otherPerms;
+ }
+ if (!IsModeCompatible(mode, effectivePermissions)) {
+ ret = EPERM;
+ DEBUG(VM_DEBUG_FAIL, "HgfsAccessInt denied access: %s (%d, %d)\n",
+ HGFS_VP_TO_FILENAME(vp), mode, effectivePermissions);
+ }
+ } else {
+ DEBUG(VM_DEBUG_FAIL, "HgfsAccessInt failed getting attrib: %s (%d)\n",
+ HGFS_VP_TO_FILENAME(vp), ret);
}
+ return ret;
+}
- if ((mode & S_IWUSR) && !(va.va_mode & S_IWUSR)) {
- DEBUG(VM_DEBUG_FAIL, "Owner: write access not allowed (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
- if ((mode & S_IXUSR) && !(va.va_mode & S_IXUSR)) {
- DEBUG(VM_DEBUG_FAIL, "Owner: execute access not allowed (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsMmapInt --
+ *
+ * HgfsMmapInt is invoked invoked from HgfsVnopMmap to verify parameters
+ * and mark vnode as mmapped if necessary.
+ *
+ * Results:
+ * Zero on success or non-zero error code otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
- if ((mode & S_IRGRP) && !(va.va_mode & S_IRGRP)) {
- DEBUG(VM_DEBUG_FAIL, "Group: read access not allowed (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
+int
+HgfsMmapInt(struct vnode *vp,
+ int accessMode)
+{
+ ASSERT(vp);
- if ((mode & S_IWGRP) && !(va.va_mode & S_IWGRP)) {
- DEBUG(VM_DEBUG_FAIL, "Group: write access not allowed (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
+ DEBUG(VM_DEBUG_ENTRY, "mmapping \"%s\"\n", HGFS_VP_TO_FILENAME(vp));
- if ((mode & S_IXGRP) && !(va.va_mode & S_IXGRP)) {
- DEBUG(VM_DEBUG_FAIL, "Group: execute access not allowed (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
+ return HgfsCheckAndReferenceHandle(vp, TRUE, accessMode);
+}
- if ((mode & S_IROTH) && !(va.va_mode & S_IROTH)) {
- DEBUG(VM_DEBUG_FAIL, "Other: read access not allowed (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
- if ((mode & S_IWOTH) && !(va.va_mode & S_IWOTH)) {
- DEBUG(VM_DEBUG_FAIL, "Other: write access not allowed (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsMnomapInt --
+ *
+ * HgfsMnomapInt is invoked invoked from HgfsVnopNomap to tear down memory
+ * mapping and dereference file handle.
+ *
+ * Results:
+ * Zero on success or non-zero error code otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
- if ((mode & S_IXOTH) && !(va.va_mode & S_IXOTH)) {
- DEBUG(VM_DEBUG_FAIL, "Other: execute access not allowed (%s).\n",
- HGFS_VP_TO_FILENAME(vp));
- return EPERM;
- }
+int
+HgfsMnomapInt(struct vnode *vp)
+{
+ int error = 0;
+ HgfsHandle handleToClose;
+ HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
- return 0;
+ ASSERT(vp);
+ DEBUG(VM_DEBUG_ENTRY, "unmmapping \"%s\"\n", HGFS_VP_TO_FILENAME(vp));
+ /*
+ * Check to see if we should close the file handle on the host, which happen when
+ * the reference count of the current handle become 0.
+ */
+ if (HgfsReleaseOpenFileHandle(vp, TRUE, &handleToClose) == 0) {
+ error = HgfsCloseServerFileHandle(sip, handleToClose);
+ }
+ return error;
}
struct componentname *cnp);
int HgfsRemoveInt(struct vnode *vp);
int HgfsCloseInt(struct vnode *vp, int mode);
-int HgfsOpenInt(struct vnode *vp, int fflag);
+int HgfsOpenInt(struct vnode *vp, int fflag, Bool implicit);
int HgfsLookupInt(struct vnode *dvp, struct vnode **vpp,
struct componentname *cnp);
int HgfsCreateInt(struct vnode *dvp, struct vnode **vpp,
struct componentname *cnp, int mode);
-int HgfsReadInt(struct vnode *vp, struct uio *uiop);
+int HgfsReadInt(struct vnode *vp, struct uio *uiop, Bool pagingIo);
int HgfsReadlinkInt(struct vnode *vp, struct uio *uiop);
-int HgfsWriteInt(struct vnode *vp, struct uio *uiop, int ioflag);
+int HgfsWriteInt(struct vnode *vp, struct uio *uiop,
+ int ioflag, Bool pagingIo);
int HgfsMkdirInt(struct vnode *dvp, struct vnode **vpp,
struct componentname *cnp, int mode);
int HgfsRenameInt(struct vnode *fvp,
struct vnode *tdvp, struct vnode *tvp,
struct componentname *tcnp);
-int HgfsAccessInt(struct vnode *vp, int mode);
+int HgfsAccessInt(struct vnode *vp, HgfsAccessMode mode);
int HgfsSymlinkInt(struct vnode *dvp,
struct vnode **vpp,
struct componentname *cnp,
char *targetName);
+int HgfsMmapInt(struct vnode *vp, int accessMode);
+int HgfsMnomapInt(struct vnode *vp);
#endif // _HGFS_VNOPS_COMMON_H_
FLAGDEF( 87, EDX, AMD, 5, 1, STC, NA, IGNORE, 0, FALSE) \
FLAGDEF( 87, EDX, AMD, 6, 1, 100MHZSTEPS, NA, IGNORE, 0, FALSE) \
FLAGDEF( 87, EDX, AMD, 7, 1, HWPSTATE, NA, IGNORE, 0, FALSE) \
-FLAGDEF( 87, EDX, AMD, 8, 1, TSC_INVARIANT, NA, IGNORE, 0, FALSE) \
+FLAGDEF( 87, EDX, COMMON, 8, 1, TSC_INVARIANT, NA, IGNORE, 0, FALSE) \
FIELDDEFA(88, EAX, COMMON, 0, 8, PHYSBITS, NA, IGNORE, 0, FALSE, PHYS_BITS) \
FIELDDEFA(88, EAX, COMMON, 8, 8, VIRTBITS, NA, IGNORE, 0, FALSE, VIRT_BITS) \
FIELDDEFA(88, ECX, AMD, 0, 8, CORE_COUNT, NA, IGNORE, 0, FALSE, AMD_CORE_COUNT) \
#define CPUID_MODEL_PIII_08 8
#define CPUID_MODEL_PIII_0A 10
+/* AMD model information */
+#define CPUID_MODEL_BARCELONA_02 0x02 // Barcelona (both Opteron & Phenom kind)
+
/*
*----------------------------------------------------------------------
*
CPUID_FAMILY_IS_K8MOBILE(_eax);
}
+/*
+ * AMD Barcelona (of either Opteron or Phenom kind).
+ */
+static INLINE Bool
+CPUID_MODEL_IS_BARCELONA(uint32 v) // IN: %eax from CPUID with %eax=1.
+{
+ /* Assumes the CPU manufacturer is AMD. */
+ return CPUID_FAMILY_IS_K8L(v) &&
+ CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_BARCELONA_02;
+}
+
#define CPUID_TYPE_PRIMARY 0
#define CPUID_TYPE_OVERDRIVE 1
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
PACKAGE_NAME=open-vm-tools
-PACKAGE_VERSION=2009.01.21
+PACKAGE_VERSION=2009.02.18
MAKE[0]="make -C pvscsi VM_UNAME=\$kernelver; \
make -C vmblock VM_UNAME=\$kernelver; \
make -C vmhgfs VM_UNAME=\$kernelver; \
#define PVSCSI_LINUX_DRIVER_DESC "VMware PVSCSI driver"
-/* Module definitions */
MODULE_DESCRIPTION(PVSCSI_LINUX_DRIVER_DESC);
MODULE_AUTHOR("VMware, Inc.");
MODULE_LICENSE("GPL v2");
struct scsi_cmnd *cmd;
struct PVSCSISGList *sgl;
struct list_head list;
+ dma_addr_t dataPA;
+ dma_addr_t sensePA;
+ dma_addr_t sglPA;
};
/* Private per-adapter struct */
char log;
spinlock_t hw_lock;
+
RingReqDesc *req_ring;
unsigned req_pages;
unsigned req_depth;
+ dma_addr_t reqRingPA;
RingCmpDesc *cmp_ring;
unsigned cmp_pages;
unsigned cmp_depth;
+ dma_addr_t cmpRingPA;
RingsState *ring_state;
+ dma_addr_t ringStatePA;
struct pci_dev *dev;
struct Scsi_Host *host;
static inline void pvscsi_free_sgls(struct pvscsi_adapter *adapter)
{
- unsigned i, max;
struct pvscsi_ctx *ctx = adapter->cmd_map;
+ unsigned i;
- max = adapter->req_depth;
- for (i = 0; i < max; ++i, ++ctx)
- kfree(ctx->sgl);
+ for (i = 0; i < adapter->req_depth; ++i, ++ctx)
+ pci_free_consistent(adapter->dev, PAGE_SIZE, ctx->sgl,
+ ctx->sglPA);
}
static inline int pvscsi_setup_msix(struct pvscsi_adapter *adapter)
#endif
}
-static inline void pvscsi_shutdown_msi(struct pvscsi_adapter *adapter)
+static inline void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter)
{
+ if (adapter->irq) {
+ free_irq(adapter->irq, adapter);
+ adapter->irq = 0;
+ }
#ifdef CONFIG_PCI_MSI
- if (adapter->use_msi)
+ if (adapter->use_msi) {
pci_disable_msi(adapter->dev);
+ adapter->use_msi = 0;
+ }
if (adapter->use_msix) {
#if 0
free_irq(adapter->irq_vectors[i], adapter);
#endif
pci_disable_msix(adapter->dev);
+ adapter->use_msix = 0;
}
#endif
}
static void pvscsi_release_resources(struct pvscsi_adapter *adapter)
{
- if (adapter->irq)
- free_irq(adapter->irq, adapter);
-
- pvscsi_shutdown_msi(adapter);
+ pvscsi_shutdown_intr(adapter);
if (adapter->iomap)
iounmap((void *)adapter->iomap);
kfree(adapter->cmd_map);
}
- kfree(adapter->ring_state);
+ if (adapter->ring_state)
+ pci_free_consistent(adapter->dev, PAGE_SIZE,
+ adapter->ring_state, adapter->ringStatePA);
if (adapter->req_ring)
- vfree(adapter->req_ring);
+ pci_free_consistent(adapter->dev,
+ adapter->req_pages * PAGE_SIZE,
+ adapter->req_ring, adapter->reqRingPA);
if (adapter->cmp_ring)
- vfree(adapter->cmp_ring);
+ pci_free_consistent(adapter->dev,
+ adapter->cmp_pages * PAGE_SIZE,
+ adapter->cmp_ring, adapter->cmpRingPA);
}
static int __devinit pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
{
- adapter->ring_state = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ adapter->ring_state = pci_alloc_consistent(adapter->dev, PAGE_SIZE,
+ &adapter->ringStatePA);
if (!adapter->ring_state)
return -ENOMEM;
- adapter->req_pages = MIN(PVSCSI_MAX_NUM_PAGES_REQ_RING,
- pvscsi_ring_pages);
- adapter->req_depth = adapter->req_pages *
+ adapter->req_pages = MIN(PVSCSI_MAX_NUM_PAGES_REQ_RING,
+ pvscsi_ring_pages);
+ adapter->req_depth = adapter->req_pages *
PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
- adapter->req_ring = vmalloc(adapter->req_pages * PAGE_SIZE);
+ adapter->req_ring = pci_alloc_consistent(adapter->dev,
+ adapter->req_pages * PAGE_SIZE,
+ &adapter->reqRingPA);
if (!adapter->req_ring)
return -ENOMEM;
pvscsi_ring_pages);
adapter->cmp_depth = adapter->cmp_pages *
PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
- adapter->cmp_ring = vmalloc(adapter->cmp_pages * PAGE_SIZE);
+ adapter->cmp_ring = pci_alloc_consistent(adapter->dev,
+ adapter->cmp_pages * PAGE_SIZE,
+ &adapter->cmpRingPA);
if (!adapter->cmp_ring)
return -ENOMEM;
+ BUG_ON(adapter->ringStatePA & ~PAGE_MASK);
+ BUG_ON(adapter->reqRingPA & ~PAGE_MASK);
+ BUG_ON(adapter->cmpRingPA & ~PAGE_MASK);
return 0;
}
static int __devinit pvscsi_allocate_sg(struct pvscsi_adapter *adapter)
{
struct pvscsi_ctx *ctx;
- unsigned max;
int i;
ctx = adapter->cmd_map;
- max = adapter->req_depth;
ASSERT_ON_COMPILE(sizeof(struct PVSCSISGList) <= PAGE_SIZE);
- for (i = 0; i < max; ++i, ++ctx) {
- ctx->sgl = kmalloc(PAGE_SIZE, GFP_KERNEL);
- BUG_ON((long)ctx->sgl & ~PAGE_MASK);
+ for (i = 0; i < adapter->req_depth; ++i, ++ctx) {
+ ctx->sgl = pci_alloc_consistent(adapter->dev, PAGE_SIZE,
+ &ctx->sglPA);
+ BUG_ON(ctx->sglPA & ~PAGE_MASK);
if (!ctx->sgl) {
for (; i >= 0; --i, --ctx) {
- kfree(ctx->sgl);
+ pci_free_consistent(adapter->dev, PAGE_SIZE,
+ ctx->sgl, ctx->sglPA);
ctx->sgl = NULL;
+ ctx->sglPA = 0;
}
return -ENOMEM;
}
pci_dev_func = pdev->devfn;
pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
- if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) ||
- pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
- if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) &&
- pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
- printk(KERN_ERR "pvscsi: unable to set usable DMA mask\n");
- goto out_disable_device;
- }
- }
+ if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0 &&
+ pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
+ printk(KERN_INFO "pvscsi: using 64bit dma\n");
+ } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) == 0 &&
+ pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) == 0) {
+ printk(KERN_INFO "pvscsi: using 32bit dma\n");
+ } else {
+ printk(KERN_ERR "pvscsi: failed to set DMA mask\n");
+ goto out_disable_device;
+ }
printk(KERN_NOTICE "pvscsi: found VMware PVSCSI rev %d on "
"bus %d:slot %d:func %d\n", rev, pci_bus,
printk(KERN_ERR "pvscsi: failed to allocate memory.\n");
goto out_reset_adapter;
}
- memset(adapter->cmd_map, 0, adapter->req_depth *
- sizeof(struct pvscsi_ctx));
+ memset(adapter->cmd_map, 0, adapter->req_depth * sizeof(struct pvscsi_ctx));
INIT_LIST_HEAD(&adapter->cmd_pool);
for (i = 0; i < adapter->req_depth; i++) {
}
static struct pvscsi_ctx *
-pvscsi_allocate_context(struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
+pvscsi_acquire_context(struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
{
struct pvscsi_ctx *ctx;
return ctx;
}
-static inline struct scsi_cmnd *
-pvscsi_free_context(struct pvscsi_adapter *adapter, struct pvscsi_ctx *ctx)
+static inline void
+pvscsi_release_context(struct pvscsi_adapter *adapter, struct pvscsi_ctx *ctx)
{
- struct scsi_cmnd *cmd;
-
- cmd = ctx->cmd;
ctx->cmd = NULL;
list_add(&ctx->list, &adapter->cmd_pool);
-
- return cmd;
}
/*
spin_lock_irqsave(&adapter->hw_lock, flags);
- ctx = pvscsi_allocate_context(adapter, cmd);
+ ctx = pvscsi_acquire_context(adapter, cmd);
if (!ctx || pvscsi_queue_ring(adapter, ctx, cmd) != 0) {
if (ctx)
- pvscsi_free_context(adapter, ctx);
+ pvscsi_release_context(adapter, ctx);
spin_unlock_irqrestore(&adapter->hw_lock, flags);
return SCSI_MLQUEUE_HOST_BUSY;
}
}
static inline void
-pvscsi_free_sg(const struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
+pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter, struct pvscsi_ctx *ctx)
{
- unsigned count = scsi_sg_count(cmd);
+ struct scsi_cmnd *cmd;
+ unsigned bufflen;
- if (count) {
- struct scatterlist *sg = scsi_sglist(cmd);
- pci_unmap_sg(adapter->dev, sg, count, cmd->sc_data_direction);
- }
+ cmd = ctx->cmd;
+ bufflen = scsi_bufflen(cmd);
+
+ if (bufflen != 0) {
+ unsigned count = scsi_sg_count(cmd);
+
+ if (count != 0) {
+ pci_unmap_sg(adapter->dev, scsi_sglist(cmd), count,
+ cmd->sc_data_direction);
+ } else {
+ pci_unmap_single(adapter->dev, ctx->dataPA, bufflen,
+ cmd->sc_data_direction);
+ }
+ }
+ if (cmd->sense_buffer) {
+ pci_unmap_single(adapter->dev, ctx->sensePA, SCSI_SENSE_BUFFERSIZE,
+ PCI_DMA_FROMDEVICE);
+ }
}
/*
struct scsi_cmnd *cmd = ctx->cmd;
if (cmd) {
printk(KERN_ERR "pvscsi: forced reset on cmd %p\n", cmd);
- pvscsi_free_sg(adapter, cmd);
- pvscsi_free_context(adapter, ctx);
+ pvscsi_unmap_buffers(adapter, ctx);
+ pvscsi_release_context(adapter, ctx);
cmd->result = (DID_RESET << 16);
cmd->scsi_done(cmd);
}
return IRQ_RETVAL(handled);
}
-/* Shutdown an entire device, syncinc all outstanding I/O */
+/* Shutdown an entire device, sync'ing all outstanding I/O */
static void __pvscsi_shutdown(struct pvscsi_adapter *adapter)
{
pvscsi_write_intr_mask(adapter, 0);
- if (adapter->irq) {
- free_irq(adapter->irq, adapter);
- adapter->irq = 0;
- }
-#ifdef CONFIG_PCI_MSI
- if (adapter->use_msi) {
- pci_disable_msi(adapter->dev);
- adapter->use_msi = 0;
- }
-#endif
+ pvscsi_shutdown_intr(adapter);
pvscsi_process_request_ring(adapter);
pvscsi_process_completion_ring(adapter);
*
**************************************************************/
-static inline struct PVSCSISGList *
+static void
pvscsi_create_sg(struct pvscsi_ctx *ctx, struct scatterlist *sg, unsigned count)
{
unsigned i;
- struct PVSCSISGList *sgl;
struct PVSCSISGElement *sge;
- sgl = ctx->sgl;
-
BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT);
- sge = &sgl->sge[0];
+ sge = &ctx->sgl->sge[0];
for (i = 0; i < count; i++, sg++) {
- sge[i].addr = sg_dma_address(sg);
+ sge[i].addr = sg_dma_address(sg);
sge[i].length = sg_dma_len(sg);
- sge[i].flags = 0;
+ sge[i].flags = 0;
}
-
- return sgl;
}
+
/*
* Map all data buffers for a command into PCI space and
* setup the scatter/gather list if needed.
if (bufflen == 0)
return;
- count = scsi_sg_count(cmd);
+ count = scsi_sg_count(cmd);
if (count != 0) {
struct scatterlist *sg = scsi_sglist(cmd);
int segs = pci_map_sg(adapter->dev, sg, count,
- cmd->sc_data_direction);
+ cmd->sc_data_direction);
if (segs > 1) {
- struct PVSCSISGList *sgl;
+ pvscsi_create_sg(ctx, sg, segs);
e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
- sgl = pvscsi_create_sg(ctx, sg, segs);
- e->dataAddr = __pa(sgl);
- } else
+ e->dataAddr = ctx->sglPA;
+ } else {
e->dataAddr = sg_dma_address(sg);
+ }
} else {
- e->dataAddr = __pa(scsi_request_buffer(cmd));
+ ctx->dataPA = pci_map_single(adapter->dev,
+ scsi_request_buffer(cmd), bufflen,
+ cmd->sc_data_direction);
+ e->dataAddr = ctx->dataPA;
}
}
{
struct scsi_device *sdev;
sdev = cmd->device;
- e->bus = sdev->channel;
+ e->bus = sdev->channel;
e->target = sdev->id;
memset(e->lun, 0, sizeof(e->lun));
e->lun[1] = sdev->lun;
}
if (cmd->sense_buffer) {
+ ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE,
+ PCI_DMA_FROMDEVICE);
+ e->senseAddr = ctx->sensePA;
e->senseLen = SCSI_SENSE_BUFFERSIZE;
- e->senseAddr = __pa(cmd->sense_buffer);
} else {
- e->senseLen = 0;
+ e->senseLen = 0;
e->senseAddr = 0;
}
- e->cdbLen = cmd->cmd_len;
+ e->cdbLen = cmd->cmd_len;
e->vcpuHint = smp_processor_id();
memcpy(e->cdb, cmd->cmnd, e->cdbLen);
u32 sdstat = e->scsiStatus;
ctx = pvscsi_get_context(adapter, e->context);
- cmd = pvscsi_free_context(adapter, ctx);
+ cmd = ctx->cmd;
+ pvscsi_unmap_buffers(adapter, ctx);
+ pvscsi_release_context(adapter, ctx);
cmd->result = 0;
if (sdstat != SAM_STAT_GOOD &&
LOG(3, "cmd=%p %x ctx=%p result=0x%x status=0x%x,%x\n",
cmd, cmd->cmnd[0], ctx, cmd->result, btstat, sdstat);
- pvscsi_free_sg(adapter, cmd);
-
cmd->scsi_done(cmd);
}
static void pvscsi_setup_rings(struct pvscsi_adapter *adapter)
{
struct CmdDescSetupRings cmd;
- unsigned i, pages;
- void *base;
+ dma_addr_t base;
+ unsigned i;
memset(&cmd, 0, sizeof(cmd));
- cmd.ringsStatePPN = __pa(adapter->ring_state) >> PAGE_SHIFT;
+ cmd.ringsStatePPN = adapter->ringStatePA >> PAGE_SHIFT;
+ cmd.reqRingNumPages = adapter->req_pages;
+ cmd.cmpRingNumPages = adapter->cmp_pages;
- cmd.reqRingNumPages = pages = adapter->req_pages;
- for (i = 0, base = adapter->req_ring; i < pages; i++, base += PAGE_SIZE)
- cmd.reqRingPPNs[i] = page_to_pfn(vmalloc_to_page(base));
+ for (i = 0, base = adapter->reqRingPA; i < adapter->req_pages;
+ i++, base += PAGE_SIZE)
+ cmd.reqRingPPNs[i] = base >> PAGE_SHIFT;
- cmd.cmpRingNumPages = pages = adapter->cmp_pages;
- for (i = 0, base = adapter->cmp_ring; i < pages; i++, base += PAGE_SIZE)
- cmd.cmpRingPPNs[i] = page_to_pfn(vmalloc_to_page(base));
+ for (i = 0, base = adapter->cmpRingPA; i < adapter->cmp_pages;
+ i++, base += PAGE_SIZE)
+ cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT;
memset(adapter->ring_state, 0, PAGE_SIZE);
memset(adapter->req_ring, 0, adapter->req_pages * PAGE_SIZE);
#ifndef _PVSCSI_VERSION_H_
#define _PVSCSI_VERSION_H_
-#define PVSCSI_DRIVER_VERSION 0.0.0.6
-#define PVSCSI_DRIVER_VERSION_COMMAS 0,0,0,6
-#define PVSCSI_DRIVER_VERSION_STRING "0.0.0.6"
+#define PVSCSI_DRIVER_VERSION 0.0.0.7
+#define PVSCSI_DRIVER_VERSION_COMMAS 0,0,0,7
+#define PVSCSI_DRIVER_VERSION_STRING "0.0.0.7"
#endif /* _PVSCSI_VERSION_H_ */
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
#define compat_set_freezable() do {} while (0)
#endif
+/*
+ * Around 2.6.27 kernel stopped sending signals to kernel
+ * threads being frozen, instead threads have to check
+ * freezing() or use wait_event_freezable(). Unfortunately
+ * wait_event_freezable() completely hides the fact that
+ * thread was frozen from calling code and sometimes we do
+ * want to know that.
+ */
+#ifdef PF_FREEZER_NOSIG
+#define compat_wait_check_freezing() freezing(current)
+#else
+#define compat_wait_check_freezing() (0)
+#endif
+
/*
* Since 2.6.27-rc2 kill_proc() is gone... Replacement (GPL-only!)
* API is available since 2.6.19. Use them from 2.6.27-rc1 up.
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
#define compat_set_freezable() do {} while (0)
#endif
+/*
+ * Around 2.6.27 kernel stopped sending signals to kernel
+ * threads being frozen, instead threads have to check
+ * freezing() or use wait_event_freezable(). Unfortunately
+ * wait_event_freezable() completely hides the fact that
+ * thread was frozen from calling code and sometimes we do
+ * want to know that.
+ */
+#ifdef PF_FREEZER_NOSIG
+#define compat_wait_check_freezing() freezing(current)
+#else
+#define compat_wait_check_freezing() (0)
+#endif
+
/*
* Since 2.6.27-rc2 kill_proc() is gone... Replacement (GPL-only!)
* API is available since 2.6.19. Use them from 2.6.27-rc1 up.
# endif
# include <stdarg.h>
# include <string.h>
+# elif defined(sun)
+# include "vm_basic_types.h"
+# include <sys/types.h>
+# include <sys/varargs.h>
#endif
/*
* Function Prototypes
*/
-#if defined(linux) || defined(__APPLE__) /* if (linux) || (__APPLE__) { */
+#if defined(linux) || defined(__APPLE__) || defined (sun)
# ifdef linux /* if (linux) { */
char *strdup(const char *source);
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
AtomicEpilogue(void)
{
#ifdef ATOMIC_USE_FENCE
+#ifdef VMM
+ /* The monitor conditionally patches out the lfence when not needed.*/
+ /* Construct a MonitorPatchTextEntry in the .patchtext section. */
+ asm volatile ("1:\n\t"
+ "lfence\n\t"
+ "2:\n\t"
+ ".pushsection .patchtext\n\t"
+#ifdef VMM32
+ ".long 1b\n\t"
+ ".long 0\n\t"
+ ".long 2b\n\t"
+ ".long 0\n\t"
+#else
+ ".quad 1b\n\t"
+ ".quad 2b\n\t"
+#endif
+ ".popsection\n\t" ::: "memory");
+#else
if (UNLIKELY(AtomicUseFence)) {
asm volatile ("lfence" ::: "memory");
}
#endif
+#endif
}
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
consumeQ->queueHeaderPtr = kmap(attach->consumePages[0]);
consumeQ->page = &attach->consumePages[1];
#else
+ /*
+ * Host queue pair support for earlier kernels temporarily
+ * disabled. See bug 365496.
+ */
+
+ ASSERT_NOT_IMPLEMENTED(FALSE);
+#if 0
produceQ->queueHeaderPtr = kmap(attach->produceIoBuf->maplist[0]);
produceQ->page = &attach->produceIoBuf->maplist[1];
consumeQ->queueHeaderPtr = kmap(attach->consumeIoBuf->maplist[0]);
consumeQ->page = &attach->consumeIoBuf->maplist[1];
+#endif
#endif
return VMCI_SUCCESS;
kunmap(attach->producePages[0]);
kunmap(attach->consumePages[0]);
#else
+ /*
+ * Host queue pair support for earlier kernels temporarily
+ * disabled. See bug 365496.
+ */
+
+ ASSERT_NOT_IMPLEMENTED(FALSE);
+#if 0
kunmap(attach->produceIoBuf->maplist[0]);
kunmap(attach->consumeIoBuf->maplist[0]);
#endif
+#endif
}
int
VMCIHost_GetUserMemory(PageStoreAttachInfo *attach) // IN/OUT
{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
int retval;
int err = VMCI_SUCCESS;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
attach->producePages =
VMCI_AllocKernelMem(attach->numProducePages * sizeof attach->producePages[0],
return err;
#else
+ /*
+ * Host queue pair support for earlier kernels temporarily
+ * disabled. See bug 365496.
+ */
+ ASSERT_NOT_IMPLEMENTED(FALSE);
+#if 0
attach->produceIoBuf = VMCI_AllocKernelMem(sizeof *attach->produceIoBuf,
VMCI_MEMORY_NORMAL);
if (attach->produceIoBuf == NULL) {
}
}
return err;
-
+#else
+ return FALSE;
+#endif
#endif
}
attach->numConsumePages *
sizeof attach->consumePages[0]);
#else
+ /*
+ * Host queue pair support for earlier kernels temporarily
+ * disabled. See bug 365496.
+ */
+
+ ASSERT_NOT_IMPLEMENTED(FALSE);
+#if 0
mark_dirty_kiobuf(attach->produceIoBuf,
attach->numProducePages * PAGE_SIZE);
unmap_kiobuf(attach->produceIoBuf);
VMCI_FreeKernelMem(attach->consumeIoBuf,
sizeof *attach->consumeIoBuf);
#endif
+#endif
}
#endif
*
* Results:
* VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
- * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
+ * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
* (as defined by the queue size).
* Otherwise the number of bytes dequeued is returned.
*
const uint64 consumeQSize, // IN:
void *buf, // IN:
size_t bufSize, // IN:
- VMCIMemcpyFromQueueFunc memcpyFromQueue) // IN:
+ VMCIMemcpyFromQueueFunc memcpyFromQueue, // IN:
+ Bool updateConsumer) // IN:
{
const int64 bufReady = VMCIQueue_BufReady(consumeQueue, produceQueue,
consumeQSize);
memcpyFromQueue(buf, 0, consumeQueue, head, tmp);
memcpyFromQueue(buf, tmp, consumeQueue, 0, written - tmp);
}
- AddPointer(&VMCIQueue_GetHeader(produceQueue)->consumerHead, written, consumeQSize);
+
+ if (updateConsumer) {
+ AddPointer(&VMCIQueue_GetHeader(produceQueue)->consumerHead, written,
+ consumeQSize);
+ }
return written;
}
size_t bufSize) // IN:
{
return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
- buf, bufSize, VMCIMemcpyFromQueue);
+ buf, bufSize, VMCIMemcpyFromQueue, TRUE);
}
size_t iovSize) // IN:
{
return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
- (void *)iov, iovSize, VMCIMemcpyFromQueueV);
+ (void *)iov, iovSize, VMCIMemcpyFromQueueV, TRUE);
+}
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_Peek --
+ *
+ * Reads data (if available) from the given consume queue. Copies data
+ * to the provided user buffer but does not update the consumer counter
+ * of the queue.
+ *
+ * Results:
+ * VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
+ * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
+ * (as defined by the queue size).
+ * Otherwise the number of bytes copied to user buffer is returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE ssize_t
+VMCIQueue_Peek(VMCIQueue *produceQueue, // IN:
+ const VMCIQueue *consumeQueue, // IN:
+ const uint64 consumeQSize, // IN:
+ void *buf, // IN:
+ size_t bufSize) // IN:
+{
+ return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
+ buf, bufSize, VMCIMemcpyFromQueue, FALSE);
+}
+
+
+#if defined(SOLARIS) || (defined(__linux__) && defined(__KERNEL__))
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_PeekV --
+ *
+ * Reads data (if available) from the given consume queue. Copies data
+ * to the provided user iovec but does not update the consumer counter
+ * of the queue.
+ *
+ * Results:
+ * VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
+ * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
+ * (as defined by the queue size).
+ * Otherwise the number of bytes copied to user iovec is returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE ssize_t
+VMCIQueue_PeekV(VMCIQueue *produceQueue, // IN:
+ const VMCIQueue *consumeQueue, // IN:
+ const uint64 consumeQSize, // IN:
+ struct iovec *iov, // IN:
+ size_t iovSize) // IN:
+{
+ return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
+ (void *)iov, iovSize, VMCIMemcpyFromQueueV, FALSE);
}
#endif
#define BDOOR_CMD_ACPI_HOTPLUG_MEMORY 57
#define BDOOR_CMD_ACPI_HOTPLUG_CBRET 58
#define BDOOR_CMD_GET_HOST_VIDEO_MODES 59
-#define BDOOR_CMD_MAX 60
+#define BDOOR_CMD_ACPI_HOTPLUG_CPU 60
+#define BDOOR_CMD_MAX 61
/*
* IMPORTANT NOTE: When modifying the behavior of an existing backdoor command,
wait_event_interruptible(hgfsReqThreadWait,
test_bit(HGFS_REQ_THREAD_SEND,
&hgfsReqThreadFlags) ||
+ compat_wait_check_freezing() ||
compat_kthread_should_stop());
/*
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2002 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_CRED_H__
+# define __COMPAT_CRED_H__
+
+
+/*
+ * Include linux/cred.h via linux/sched.h - it is not nice, but
+ * as cpp does not have #ifexist...
+ */
+#include <linux/sched.h>
+
+#if !defined(current_fsuid) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+#define current_uid() (current->uid)
+#define current_euid() (current->euid)
+#define current_fsuid() (current->fsuid)
+#define current_gid() (current->gid)
+#define current_egid() (current->egid)
+#define current_fsgid() (current->fsgid)
+#endif
+
+
+#endif /* __COMPAT_CRED_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_PAGEMAP_H__
+# define __COMPAT_PAGEMAP_H__
+
+
+#include <linux/pagemap.h>
+
+/*
+ * AOP_FLAG_NOFS was defined in the same changeset that
+ * grab_cache_page_write_begin() was introduced.
+ */
+#ifdef AOP_FLAG_NOFS
+#define compat_grab_cache_page_write_begin(mapping, index, flags) \
+ grab_cache_page_write_begin((mapping), (index), (flags))
+#else
+#define compat_grab_cache_page_write_begin(mapping, index, flags) \
+ __grab_cache_page((mapping), (index));
+#endif
+
+#endif /* __COMPAT_PAGEMAP_H__ */
#define compat_set_freezable() do {} while (0)
#endif
+/*
+ * Around 2.6.27 kernel stopped sending signals to kernel
+ * threads being frozen, instead threads have to check
+ * freezing() or use wait_event_freezable(). Unfortunately
+ * wait_event_freezable() completely hides the fact that
+ * thread was frozen from calling code and sometimes we do
+ * want to know that.
+ */
+#ifdef PF_FREEZER_NOSIG
+#define compat_wait_check_freezing() freezing(current)
+#else
+#define compat_wait_check_freezing() (0)
+#endif
+
/*
* Since 2.6.27-rc2 kill_proc() is gone... Replacement (GPL-only!)
* API is available since 2.6.19. Use them from 2.6.27-rc1 up.
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/signal.h>
+#include "compat_cred.h"
#include "compat_fs.h"
#include "compat_kernel.h"
#include "compat_slab.h"
iparent = dparent->d_inode;
HgfsSetUidGid(iparent, file->f_dentry,
- current->fsuid, current->fsgid);
+ current_fsuid(), current_fsgid());
dput(dparent);
}
#include <linux/module.h>
#include <linux/pagemap.h>
#include "compat_completion.h"
+#include "compat_cred.h"
#include "compat_dcache.h"
#include "compat_fs.h"
#include "compat_kernel.h"
if (si->uidSet) {
si->uid = mountInfo->uid;
} else {
- si->uid = current->uid;
+ si->uid = current_uid();
}
si->gidSet = mountInfo->gidSet;
if (si->gidSet) {
si->gid = mountInfo->gid;
} else {
- si->gid = current->gid;
+ si->gid = current_gid();
}
si->fmask = mountInfo->fmask;
si->dmask = mountInfo->dmask;
#define HGFS_PERM_WRITE 2
#define HGFS_PERM_EXEC 1
+/*
+ * Access mode bits.
+ *
+ * Different operating systems have different set of file access mode.
+ * Here are constants that are rich enough to describe all access modes in an OS
+ * independent way.
+ */
+
+typedef uint32 HgfsAccessMode;
+/*
+ * Generic access rights control coarse grain access for the file.
+ * A particular generic rigth can be expanded into different set of specific rights
+ * on different OS.
+ */
+
+/*
+ * HGFS_MODE_GENERIC_READ means ability to read file data and read various file
+ * attributes and properties.
+ */
+#define HGFS_MODE_GENERIC_READ (1 << 0)
+/*
+ * HGFS_MODE_GENERIC_WRITE means ability to write file data and updaate various file
+ * attributes and properties.
+ */
+#define HGFS_MODE_GENERIC_WRITE (1 << 1)
+/*
+ * HGFS_MODE_GENERIC_EXECUE means ability to execute file. For network redirectors
+ * ability to execute usualy implies ability to read data; for local file systems
+ * HGFS_MODE_GENERIC_EXECUTE does not imply ability to read data.
+ */
+#define HGFS_MODE_GENERIC_EXECUTE (1 << 2)
+
+/* Specific rights define fine grain access modes. */
+#define HGFS_MODE_READ_DATA (1 << 3) // Ability to read file data
+#define HGFS_MODE_WRITE_DATA (1 << 4) // Ability to writge file data
+#define HGFS_MODE_APPEND_DATA (1 << 5) // Appending data to the end of file
+#define HGFS_MODE_DELETE (1 << 6) // Ability to delete the file
+#define HGFS_MODE_TRAVERSE_DIRECTORY (1 << 7) // Ability to access files in a directory
+#define HGFS_MODE_LIST_DIRECTORY (1 << 8) // Ability to list file names
+#define HGFS_MODE_ADD_SUBDIRECTORY (1 << 9) // Ability to create a new subdirectory
+#define HGFS_MODE_ADD_FILE (1 << 10) // Ability to create a new file
+#define HGFS_MODE_DELETE_CHILD (1 << 11) // Ability to delete file/subdirectory
+#define HGFS_MODE_READ_ATTRIBUTES (1 << 12) // Ability to read attributes
+#define HGFS_MODE_WRITE_ATTRIBUTES (1 << 13) // Ability to write attributes
+#define HGFS_MODE_READ_EXTATTRIBUTES (1 << 14) // Ability to read extended attributes
+#define HGFS_MODE_WRITE_EXTATTRIBUTES (1 << 15) // Ability to write extended attributes
+#define HGFS_MODE_READ_SECURITY (1 << 16) // Ability to read permissions/ACLs/owner
+#define HGFS_MODE_WRITE_SECURITY (1 << 17) // Ability to change permissions/ACLs
+#define HGFS_MODE_TAKE_OWNERSHIP (1 << 18) // Ability to change file owner/group
/*
* Server-side locking (oplocks and leases).
* only to determine if the ID is valid.
*/
#define HGFS_ATTR_VALID_NON_STATIC_FILEID (1 << 16)
+/*
+ * File permissions that are in effect for the user which runs HGFS server.
+ * Client needs to know effective permissions in order to implement access(2).
+ * Client can't derive it from group/owner/other permissions because of two resaons:
+ * 1. It does not know user/group id of the user which runs HGFS server
+ * 2. Effective permissions account for additional restrictions that may be imposed
+ * by host file system, for example by ACL.
+ */
+#define HGFS_ATTR_VALID_EFFECTIVE_PERMS (1 << 17)
/*
uint32 groupId; /* group identifier, ignored by Windows */
uint64 hostFileId; /* File Id of the file on host: inode_t on Linux */
uint32 volumeId; /* volume identifier, non-zero is valid. */
- uint32 reserved1; /* Reserved for future use */
+ uint32 effectivePerms; /* Permissions in effect for the user on the host. */
uint64 reserved2; /* Reserved for future use */
}
#include "vmware_pack_end.h"
#include <linux/errno.h>
#include <linux/pagemap.h>
+#include "compat_cred.h"
#include "compat_fs.h"
#include "compat_highmem.h"
#include "compat_kernel.h"
* a Linux machine and as root, but we might as well give it
* a go.
*/
- HgfsSetUidGid(dir, dentry, current->fsuid, current->fsgid);
+ HgfsSetUidGid(dir, dentry, current_fsuid(), current_fsgid());
}
/*
/* Convert target name to CPName-lite format. */
CPNameLite_ConvertTo(targetName, targetNameBytes - 1, '/');
- *targetNameLength = result;
- req->payloadSize += result;
+ *targetNameLength = targetNameBytes - 1;
+ req->payloadSize += targetNameBytes - 1;
return 0;
}
# endif
# include <stdarg.h>
# include <string.h>
+# elif defined(sun)
+# include "vm_basic_types.h"
+# include <sys/types.h>
+# include <sys/varargs.h>
#endif
/*
* Function Prototypes
*/
-#if defined(linux) || defined(__APPLE__) /* if (linux) || (__APPLE__) { */
+#if defined(linux) || defined(__APPLE__) || defined (sun)
# ifdef linux /* if (linux) { */
char *strdup(const char *source);
#include "compat_page-flags.h"
#include "compat_fs.h"
#include "compat_kernel.h"
+#include "compat_pagemap.h"
#ifdef HGFS_ENABLE_WRITEBACK
#include <linux/writeback.h>
#endif
unsigned pageFrom, // IN: Starting page offset
unsigned pageTo) // IN: Ending page offset
{
+#ifndef HGFS_ENABLE_WRITEBACK
ASSERT(page);
-#ifdef HGFS_ENABLE_WRITEBACK
- loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
- loff_t currentFileSize = compat_i_size_read(page->mapping->host);
+#else
+ loff_t offset;
+ loff_t currentFileSize;
+
+ ASSERT(page);
+
+ offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+ currentFileSize = compat_i_size_read(page->mapping->host);
/*
* If we are doing a partial write into a new page (beyond end of
unsigned pageTo = pos + len;
struct page *page;
- page = __grab_cache_page(mapping, index);
+ page = compat_grab_cache_page_write_begin(mapping, index, flags);
if (page == NULL) {
return -ENOMEM;
}
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
#error No compiler defined for RDTSC
#endif /* __GNUC__ */
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DEBUGBREAK --
+ *
+ * Does an int3 for MSVC / GCC. This is a macro to make sure int3 is
+ * always inlined.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef _MSC_VER
+#define DEBUGBREAK() __debugbreak()
+#else
+#define DEBUGBREAK() __asm__ (" int $3 ")
+#endif
+
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
FLAGDEF( 87, EDX, AMD, 5, 1, STC, NA, IGNORE, 0, FALSE) \
FLAGDEF( 87, EDX, AMD, 6, 1, 100MHZSTEPS, NA, IGNORE, 0, FALSE) \
FLAGDEF( 87, EDX, AMD, 7, 1, HWPSTATE, NA, IGNORE, 0, FALSE) \
-FLAGDEF( 87, EDX, AMD, 8, 1, TSC_INVARIANT, NA, IGNORE, 0, FALSE) \
+FLAGDEF( 87, EDX, COMMON, 8, 1, TSC_INVARIANT, NA, IGNORE, 0, FALSE) \
FIELDDEFA(88, EAX, COMMON, 0, 8, PHYSBITS, NA, IGNORE, 0, FALSE, PHYS_BITS) \
FIELDDEFA(88, EAX, COMMON, 8, 8, VIRTBITS, NA, IGNORE, 0, FALSE, VIRT_BITS) \
FIELDDEFA(88, ECX, AMD, 0, 8, CORE_COUNT, NA, IGNORE, 0, FALSE, AMD_CORE_COUNT) \
#define CPUID_MODEL_PIII_08 8
#define CPUID_MODEL_PIII_0A 10
+/* AMD model information */
+#define CPUID_MODEL_BARCELONA_02 0x02 // Barcelona (both Opteron & Phenom kind)
+
/*
*----------------------------------------------------------------------
*
CPUID_FAMILY_IS_K8MOBILE(_eax);
}
+/*
+ * AMD Barcelona (of either Opteron or Phenom kind).
+ */
+static INLINE Bool
+CPUID_MODEL_IS_BARCELONA(uint32 v) // IN: %eax from CPUID with %eax=1.
+{
+ /* Assumes the CPU manufacturer is AMD. */
+ return CPUID_FAMILY_IS_K8L(v) &&
+ CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_BARCELONA_02;
+}
+
#define CPUID_TYPE_PRIMARY 0
#define CPUID_TYPE_OVERDRIVE 1
#define BDOOR_CMD_ACPI_HOTPLUG_MEMORY 57
#define BDOOR_CMD_ACPI_HOTPLUG_CBRET 58
#define BDOOR_CMD_GET_HOST_VIDEO_MODES 59
-#define BDOOR_CMD_MAX 60
+#define BDOOR_CMD_ACPI_HOTPLUG_CPU 60
+#define BDOOR_CMD_MAX 61
/*
* IMPORTANT NOTE: When modifying the behavior of an existing backdoor command,
#define compat_set_freezable() do {} while (0)
#endif
+/*
+ * Around 2.6.27 kernel stopped sending signals to kernel
+ * threads being frozen, instead threads have to check
+ * freezing() or use wait_event_freezable(). Unfortunately
+ * wait_event_freezable() completely hides the fact that
+ * thread was frozen from calling code and sometimes we do
+ * want to know that.
+ */
+#ifdef PF_FREEZER_NOSIG
+#define compat_wait_check_freezing() freezing(current)
+#else
+#define compat_wait_check_freezing() (0)
+#endif
+
/*
* Since 2.6.27-rc2 kill_proc() is gone... Replacement (GPL-only!)
* API is available since 2.6.19. Use them from 2.6.27-rc1 up.
/* main loop */
while (1) {
/* sleep for specified period */
- wait_event_interruptible_timeout(t->delay, compat_kthread_should_stop(),
+ wait_event_interruptible_timeout(t->delay,
+ compat_wait_check_freezing() ||
+ compat_kthread_should_stop(),
t->period);
compat_try_to_freeze();
if (compat_kthread_should_stop()) {
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_PCI_MAPPING_H__
+#define __COMPAT_PCI_MAPPING_H__
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <linux/pci.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,41)
+typedef u32 dma_addr_t;
+
+static __inline__ int
+get_order(unsigned long size)
+{
+ int order;
+
+ size = (size - 1) >> (PAGE_SHIFT - 1);
+ order = -1;
+ do {
+ size >>= 1;
+ order++;
+ } while (size);
+ return order;
+}
+
+static inline void *
+compat_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+{
+ void *ptr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
+ if (ptr) {
+ memset(ptr, 0, size);
+ *dma_handle = virt_to_phys(ptr);
+ }
+ return ptr;
+}
+
+static inline void
+compat_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ free_pages((unsigned long)vaddr, get_order(size));
+}
+
+static inline dma_addr_t
+compat_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
+{
+ return virt_to_phys(ptr);
+}
+
+static inline void
+compat_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+ size_t size, int direction)
+{
+}
+
+#else
+#define compat_pci_alloc_consistent(hwdev, size, dma_handle) \
+ pci_alloc_consistent(hwdev, size, dma_handle)
+#define compat_pci_free_consistent(hwdev, size, vaddr, dma_handle) \
+ pci_free_consistent(hwdev, size, vaddr, dma_handle)
+#define compat_pci_map_single(hwdev, ptr, size, direction) \
+ pci_map_single(hwdev, ptr, size, direction)
+#define compat_pci_unmap_single(hwdev, dma_addr, size, direction) \
+ pci_unmap_single(hwdev, dma_addr, size, direction)
+#endif
+
+#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
#include "compat_slab.h"
#include "compat_spinlock.h"
#include "compat_pci.h"
+#include "compat_pci_mapping.h"
#include "compat_init.h"
#include "compat_timer.h"
#include <asm/dma.h>
#undef VMXNET_DO_ZERO_COPY
#endif
-#if defined(MAX_SKB_FRAGS) && ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18) ) && ( LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 0) )
+#if defined(MAX_SKB_FRAGS) && \
+ ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18) ) && \
+ ( LINUX_VERSION_CODE != KERNEL_VERSION(2, 6, 0) )
#define VMXNET_DO_ZERO_COPY
#endif
+#define VMXNET_GET_LO_ADDR(dma) ((uint32)(dma))
+#define VMXNET_GET_HI_ADDR(dma) ((uint16)(((uint64)(dma)) >> 32))
+#define VMXNET_GET_DMA_ADDR(sge) ((dma_addr_t)((((uint64)(sge).addrHi) << 32) | \
+ (sge).addrLow))
+
+#define VMXNET_FILL_SG(sg, dma, size)\
+do{\
+ (sg).addrLow = VMXNET_GET_LO_ADDR(dma);\
+ (sg).addrHi = VMXNET_GET_HI_ADDR(dma);\
+ (sg).length = size;\
+} while (0)
+
#ifdef VMXNET_DO_ZERO_COPY
#include <net/checksum.h>
#include <linux/ip.h>
#define PKT_OF_IPV4(skb) PKT_OF_PROTO(skb, ETH_TYPE_IP)
-#define VMXNET_GET_LO_ADDR(dma) ((uint32)(dma))
-#define VMXNET_GET_HI_ADDR(dma) ((uint16)(((uint64)(dma)) >> 32))
-#define VMXNET_GET_DMA_ADDR(sge) ((dma_addr_t)((((uint64)(sge).addrHi) << 32) | (sge).addrLow))
-
-#define VMXNET_FILL_SG(sg, dma, size)\
-do{\
- (sg).addrLow = VMXNET_GET_LO_ADDR(dma);\
- (sg).addrHi = VMXNET_GET_HI_ADDR(dma);\
- (sg).length = size;\
-} while (0)
-
#if defined(NETIF_F_TSO)
#define VMXNET_DO_TSO
#endif // VMXNET_DO_ZERO_COPY
+#ifdef VMXNET_DO_TSO
+static int disable_lro = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
+ module_param(disable_lro, int, 0);
+#else
+ MODULE_PARM(disable_lro, "i");
+#endif
+#endif
+
#ifdef VMXNET_DEBUG
#define VMXNET_LOG(msg...) printk(KERN_ERR msg)
#else
Bool morphed = FALSE;
Bool enhanced = FALSE;
int i;
- unsigned int driverDataSize;
i = compat_pci_enable_device(pdev);
if (i) {
}
if ((lp->capabilities & VMNET_CAP_LPD) &&
- (lp->features & VMXNET_FEATURE_LPD)) {
+ (lp->features & VMXNET_FEATURE_LPD) &&
+ !disable_lro) {
lp->lpd = TRUE;
printk(" lpd");
}
numTxBuffers = defNumTxBuffers;
}
- driverDataSize =
- sizeof(Vmxnet2_DriverData) +
- (numRxBuffers + numRxBuffers2) * sizeof(Vmxnet2_RxRingEntry) +
- numTxBuffers * sizeof(Vmxnet2_TxRingEntry);
- VMXNET_LOG("vmxnet: numRxBuffers=((%d+%d)*%d) numTxBuffers=(%d*%d) driverDataSize=%d\n",
+ lp->ddSize = sizeof(Vmxnet2_DriverData) +
+ (numRxBuffers + numRxBuffers2) * sizeof(Vmxnet2_RxRingEntry) +
+ numTxBuffers * sizeof(Vmxnet2_TxRingEntry);
+ VMXNET_LOG("vmxnet: numRxBuffers=((%d+%d)*%d) numTxBuffers=(%d*%d) ddSize=%d\n",
numRxBuffers, numRxBuffers2, (uint32)sizeof(Vmxnet2_RxRingEntry),
numTxBuffers, (uint32)sizeof(Vmxnet2_TxRingEntry),
- driverDataSize);
- lp->ddAllocated = kmalloc(driverDataSize + 15, GFP_DMA | GFP_KERNEL);
-
- if (!lp->ddAllocated) {
+ (int)lp->ddSize);
+ lp->dd = kmalloc(lp->ddSize, GFP_KERNEL | GFP_DMA);
+ if (!lp->dd) {
printk(KERN_ERR "Unable to allocate memory for driver data\n");
goto free_dev;
}
- if ((uintptr_t)virt_to_bus(lp->ddAllocated) > SHARED_MEM_MAX) {
- printk(KERN_ERR
- "Unable to initialize driver data, address outside of shared area (0x%p)\n",
- (void*)virt_to_bus(lp->ddAllocated));
- goto free_dev_dd;
- }
-
- /* Align on paragraph boundary */
- lp->dd = (Vmxnet2_DriverData*)(((unsigned long)lp->ddAllocated + 15) & ~15UL);
- memset(lp->dd, 0, driverDataSize);
+ lp->ddPA = compat_pci_map_single(lp->pdev, lp->dd, lp->ddSize,
+ PCI_DMA_BIDIRECTIONAL);
+ memset(lp->dd, 0, lp->ddSize);
spin_lock_init(&lp->txLock);
lp->numRxBuffers = numRxBuffers;
lp->numRxBuffers2 = numRxBuffers2;
lp->numTxBuffers = numTxBuffers;
/* So that the vmkernel can check it is compatible */
lp->dd->magic = VMXNET2_MAGIC;
- lp->dd->length = driverDataSize;
+ lp->dd->length = lp->ddSize;
lp->name = VMXNET_CHIP_NAME;
/*
lp->dd->txBufferPhysLength = 0;
if (lp->partialHeaderCopyEnabled) {
- unsigned int txBufferSize;
-
- txBufferSize = numTxBuffers * TX_PKT_HEADER_SIZE;
- lp->txBufferStartRaw = kmalloc(txBufferSize + PAGE_SIZE,
- GFP_DMA | GFP_KERNEL);
- if (lp->txBufferStartRaw) {
- lp->txBufferStart = (char*)((unsigned long)(lp->txBufferStartRaw + PAGE_SIZE - 1) &
- (unsigned long)~(PAGE_SIZE - 1));
- lp->dd->txBufferPhysStart = virt_to_phys(lp->txBufferStart);
- lp->dd->txBufferPhysLength = txBufferSize;
+ lp->txBufferSize = numTxBuffers * TX_PKT_HEADER_SIZE;
+ lp->txBufferStart = kmalloc(lp->txBufferSize, GFP_KERNEL | GFP_DMA);
+ if (lp->txBufferStart) {
+ lp->txBufferPA = compat_pci_map_single(lp->pdev, lp->txBufferStart,
+ lp->txBufferSize, PCI_DMA_TODEVICE);
+ lp->dd->txBufferPhysStart = lp->txBufferPA;
+ lp->dd->txBufferPhysLength = lp->txBufferSize;
lp->dd->txPktMaxSize = TX_PKT_HEADER_SIZE;
} else {
lp->partialHeaderCopyEnabled = FALSE;
pci_set_drvdata(pdev, dev);
return 0;
-free_dev_dd:;
- kfree(lp->ddAllocated);
+free_dev_dd:
+#ifdef VMXNET_DO_ZERO_COPY
+ if (lp->partialHeaderCopyEnabled && lp->txBufferStart) {
+ compat_pci_unmap_single(pdev, lp->txBufferPA, lp->txBufferSize,
+ PCI_DMA_TODEVICE);
+ kfree(lp->txBufferStart);
+ }
+#endif
+ compat_pci_unmap_single(lp->pdev, lp->ddPA, lp->ddSize, PCI_DMA_BIDIRECTIONAL);
+ kfree(lp->dd);
free_dev:;
compat_free_netdev(dev);
morph_back:;
}
#ifdef VMXNET_DO_ZERO_COPY
- if (lp->partialHeaderCopyEnabled){
- kfree(lp->txBufferStartRaw);
+ if (lp->partialHeaderCopyEnabled && lp->txBufferStart) {
+ compat_pci_unmap_single(pdev, lp->txBufferPA, lp->txBufferSize,
+ PCI_DMA_TODEVICE);
+ kfree(lp->txBufferStart);
}
#endif
- kfree(lp->ddAllocated);
+ compat_pci_unmap_single(lp->pdev, lp->ddPA, lp->ddSize, PCI_DMA_BIDIRECTIONAL);
+ kfree(lp->dd);
compat_free_netdev(dev);
compat_pci_disable_device(pdev);
}
(uint64)offset, dd->length);
for (i = 0; i < lp->numRxBuffers; i++) {
- lp->rxSkbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
+ lp->rxSkbuff[i] = dev_alloc_skb(PKT_BUF_SZ + COMPAT_NET_IP_ALIGN);
if (lp->rxSkbuff[i] == NULL) {
unsigned int j;
return -ENOMEM;
}
- lp->rxRing[i].paddr = virt_to_bus(compat_skb_tail_pointer(lp->rxSkbuff[i]));
+ skb_reserve(lp->rxSkbuff[i], COMPAT_NET_IP_ALIGN);
+
+ lp->rxRing[i].paddr = compat_pci_map_single(lp->pdev, lp->rxSkbuff[i]->data,
+ PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
lp->rxRing[i].bufferLength = PKT_BUF_SZ;
lp->rxRing[i].actualLength = 0;
lp->rxRing[i].ownership = VMXNET2_OWNERSHIP_NIC;
{
struct Vmxnet_Private *lp = (Vmxnet_Private *)dev->priv;
unsigned int ioaddr = dev->base_addr;
- u32 paddr;
+ uint32 ddPA;
if (dev->irq == 0 || request_irq(dev->irq, &vmxnet_interrupt,
COMPAT_IRQF_SHARED, lp->name, (void *)dev)) {
}
if (vmxnet_debug > 1) {
- printk(KERN_DEBUG "%s: vmxnet_open() irq %d lp %#x.\n",
- dev->name, dev->irq,
- (u32) virt_to_bus(lp));
+ printk(KERN_DEBUG "%s: vmxnet_open() irq %d lp %p.\n",
+ dev->name, dev->irq, lp);
}
if (vmxnet_init_ring(dev)) {
return -ENOMEM;
}
- paddr = virt_to_bus(lp->dd);
-
- outl(paddr, ioaddr + VMXNET_INIT_ADDR);
+ ddPA = VMXNET_GET_LO_ADDR(lp->ddPA); // lp->dd was allocated out of ZONE_DMA32
+ outl(ddPA, ioaddr + VMXNET_INIT_ADDR);
outl(lp->dd->length, ioaddr + VMXNET_INIT_LENGTH);
#ifdef VMXNET_DO_ZERO_COPY
break;
}
#ifdef VMXNET_DO_ZERO_COPY
- if (lp->zeroCopyTx){
+ if (lp->zeroCopyTx) {
VMXNET_LOG("unmap txRing[%u]\n", dd->txDriverCur);
vmxnet_unmap_buf(skb, &lp->txBufInfo[dd->txDriverCur], xre, lp->pdev);
- }
+ } else
#endif
-
+ {
+ compat_pci_unmap_single(lp->pdev, xre->sg.sg[0].addrLow,
+ xre->sg.sg[0].length,
+ PCI_DMA_TODEVICE);
+ }
if (lp->txBufInfo[dd->txDriverCur].eop) {
compat_dev_kfree_skb_irq(skb, FREE_WRITE);
}
return VMXNET_DEFER_TRANSMIT;
}
}
- if (UNLIKELY(*(uint16*)(skb->data + ETH_FRAME_TYPE_LOCATION) == ETH_TYPE_VLAN_TAG)) {
+ if (UNLIKELY(*(uint16*)(skb->data + ETH_FRAME_TYPE_LOCATION) ==
+ ETH_TYPE_VLAN_TAG)) {
headerSize += VLAN_TAG_LENGTH;
if (UNLIKELY(skb_headlen(skb) < headerSize)) {
return VMXNET_DEFER_TRANSMIT;
}
- xre->sg.sg[0].addrLow = (uint32)dd->txBufferPhysStart + pos;
+ xre->sg.sg[0].addrLow = dd->txBufferPhysStart + pos;
xre->sg.sg[0].addrHi = 0;
xre->sg.sg[0].length = headerSize;
vmxnet_map_pkt(skb, headerSize, lp, 1);
#endif
{
struct Vmxnet2_TxBuf *tb;
+ dma_addr_t dmaAddr;
spin_lock_irqsave(&lp->txLock, flags);
lp->numTxPending ++;
- xre->sg.sg[0].addrLow = virt_to_bus(skb->data);
- xre->sg.sg[0].addrHi = 0;
- xre->sg.sg[0].length = skb->len;
+ dmaAddr = compat_pci_map_single(lp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+ VMXNET_FILL_SG(xre->sg.sg[0], dmaAddr, skb->len);
xre->sg.length = 1;
xre->flags = 0;
skb = lp->rxSkbuff[dd->rxDriverNext];
/* refill the rx ring */
- newSkb = dev_alloc_skb(PKT_BUF_SZ);
+ newSkb = dev_alloc_skb(PKT_BUF_SZ + COMPAT_NET_IP_ALIGN);
if (UNLIKELY(newSkb == NULL)) {
printk(KERN_DEBUG "%s: Memory squeeze, dropping packet.\n", dev->name);
#ifdef VMXNET_DO_ZERO_COPY
lp->stats.rx_errors++;
goto next_pkt;
}
+ skb_reserve(newSkb, COMPAT_NET_IP_ALIGN);
+
+ compat_pci_unmap_single(lp->pdev, rre->paddr, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+ skb_put(skb, rre->actualLength);
lp->rxSkbuff[dd->rxDriverNext] = newSkb;
- rre->paddr = virt_to_bus(newSkb->data);
+ rre->paddr = compat_pci_map_single(lp->pdev, newSkb->data,
+ PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
rre->bufferLength = PKT_BUF_SZ;
- skb_put(skb, rre->actualLength);
#ifdef VMXNET_DO_ZERO_COPY
if (rre->flags & VMXNET2_RX_WITH_FRAG) {
for (i = 0; i < lp->numRxBuffers; i++) {
if (lp->rxSkbuff[i] != NULL) {
+ compat_pci_unmap_single(lp->pdev, lp->rxRing[i].paddr,
+ PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
compat_dev_kfree_skb(lp->rxSkbuff[i], FREE_WRITE);
lp->rxSkbuff[i] = NULL;
}
if (lp->jumboFrame || lp->lpd) {
for (i = 0; i < lp->numRxBuffers2; i++) {
if (lp->rxPages[i] != NULL) {
- pci_unmap_page(lp->pdev, lp->rxRing2[i].paddr, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ pci_unmap_page(lp->pdev, lp->rxRing2[i].paddr, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
put_page(lp->rxPages[i]);
lp->rxPages[i] = NULL;
}
#define VMXNET_MIN_MTU (ETH_MIN_FRAME_LEN - 14)
#define VMXNET_MAX_MTU (16 * 1024 - 18)
-/* Largest address able to be shared between the driver and the device */
-#define SHARED_MEM_MAX 0xFFFFFFFF
-
typedef enum Vmxnet_TxStatus {
VMXNET_CALL_TRANSMIT,
VMXNET_DEFER_TRANSMIT,
*/
typedef struct Vmxnet_Private {
Vmxnet2_DriverData *dd;
+ dma_addr_t ddPA;
+ size_t ddSize;
const char *name;
struct net_device_stats stats;
struct sk_buff *rxSkbuff[ENHANCED_VMXNET2_MAX_NUM_RX_BUFFERS];
Bool lpd;
Bool morphed; // Indicates whether adapter is morphed
- void *ddAllocated;
- char *txBufferStartRaw;
+ size_t txBufferSize;
char *txBufferStart;
+ dma_addr_t txBufferPA;
struct pci_dev *pdev;
struct timer_list linkCheckTimer;
} Vmxnet_Private;
#ifndef _VMXNET_VERSION_H_
#define _VMXNET_VERSION_H_
-#define VMXNET_DRIVER_VERSION 2.0.1.1
-#define VMXNET_DRIVER_VERSION_COMMAS 2,0,1,1
-#define VMXNET_DRIVER_VERSION_STRING "2.0.1.1"
+#define VMXNET_DRIVER_VERSION 2.0.2.1
+#define VMXNET_DRIVER_VERSION_COMMAS 2,0,2,1
+#define VMXNET_DRIVER_VERSION_STRING "2.0.2.1"
#endif /* _VMXNET_VERSION_H_ */
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
#endif
#include "compat_module.h"
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
+//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
#include <linux/moduleparam.h>
-#endif
+//#endif
#include "compat_slab.h"
#include "compat_spinlock.h"
#endif
};
+static int disable_lro = 0;
/*
*----------------------------------------------------------------------------
printk(" tsoIPv6");
#endif
- adapter->lro = TRUE;
- printk(" lro");
+ if (!disable_lro) {
+ adapter->lro = TRUE;
+ printk(" lro");
+ }
if (dma64) {
netdev->features |= NETIF_F_HIGHDMA;
* by default (i.e., neither mkinitrd nor modprobe will accept it).
*/
MODULE_INFO(supported, "external");
-
+module_param(disable_lro, int, 0);
#ifndef _VMXNET3_VERSION_H_
#define _VMXNET3_VERSION_H_
-#define VMXNET3_DRIVER_VERSION 0.0.0.31
-#define VMXNET3_DRIVER_VERSION_COMMAS 0,0,0,31
-#define VMXNET3_DRIVER_VERSION_STRING "0.0.0.31"
+#define VMXNET3_DRIVER_VERSION 1.0.0.32
+#define VMXNET3_DRIVER_VERSION_COMMAS 1,0,0,32
+#define VMXNET3_DRIVER_VERSION_STRING "1.0.0.32"
-#define VMXNET3_DRIVER_VERSION_NUM 31
+/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
+#define VMXNET3_DRIVER_VERSION_NUM 0x01000020
#endif /* _VMXNET3_VERSION_H_ */
#define compat_set_freezable() do {} while (0)
#endif
+/*
+ * Around 2.6.27 kernel stopped sending signals to kernel
+ * threads being frozen, instead threads have to check
+ * freezing() or use wait_event_freezable(). Unfortunately
+ * wait_event_freezable() completely hides the fact that
+ * thread was frozen from calling code and sometimes we do
+ * want to know that.
+ */
+#ifdef PF_FREEZER_NOSIG
+#define compat_wait_check_freezing() freezing(current)
+#else
+#define compat_wait_check_freezing() (0)
+#endif
+
/*
* Since 2.6.27-rc2 kill_proc() is gone... Replacement (GPL-only!)
* API is available since 2.6.19. Use them from 2.6.27-rc1 up.
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
AtomicEpilogue(void)
{
#ifdef ATOMIC_USE_FENCE
+#ifdef VMM
+ /* The monitor conditionally patches out the lfence when not needed.*/
+ /* Construct a MonitorPatchTextEntry in the .patchtext section. */
+ asm volatile ("1:\n\t"
+ "lfence\n\t"
+ "2:\n\t"
+ ".pushsection .patchtext\n\t"
+#ifdef VMM32
+ ".long 1b\n\t"
+ ".long 0\n\t"
+ ".long 2b\n\t"
+ ".long 0\n\t"
+#else
+ ".quad 1b\n\t"
+ ".quad 2b\n\t"
+#endif
+ ".popsection\n\t" ::: "memory");
+#else
if (UNLIKELY(AtomicUseFence)) {
asm volatile ("lfence" ::: "memory");
}
#endif
+#endif
}
#error No compiler defined for RDTSC
#endif /* __GNUC__ */
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DEBUGBREAK --
+ *
+ * Does an int3 for MSVC / GCC. This is a macro to make sure int3 is
+ * always inlined.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef _MSC_VER
+#define DEBUGBREAK() __debugbreak()
+#else
+#define DEBUGBREAK() __asm__ (" int $3 ")
+#endif
+
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
#define VMCI_MINOR_VERSION(v) ((v) & 0xffff)
#include "vmci_defs.h"
-#ifdef VMKERNEL
+#if defined(VMKERNEL)
#include "vm_atomic.h"
#include "return_status.h"
#include "util_copy_dist.h"
#endif
-#include "vmci_defs.h"
#include "vmci_call_defs.h"
-
-#ifdef VMKERNEL
+#if (defined(__linux__) || defined(_WIN32)) && !defined(VMKERNEL)
+#include "vmci_queue_pair.h"
#endif
typedef void (*VMCI_EventCB)(VMCIId subID, VMCI_EventData *ed,
void *clientData);
-int VMCIEvent_Subscribe(VMCI_Event event, VMCI_EventCB callback,
+int VMCIEvent_Subscribe(VMCI_Event event, VMCI_EventCB callback,
void *callbackData, VMCIId *subID);
int VMCIEvent_Unsubscribe(VMCIId subID);
-/*
- * Since QP API for non-VMKernel hosts is defined in vmci_queue_pair.h, here
- * declarations are included only for VMKERNEL
+/*
+ * Queue pair operations for manipulating the content of a queue
+ * pair are defined in vmci_queue_pair.h for non-vmkernel hosts.
+ * Here we define the API for allocating and detaching from queue
+ * pairs for all hosts, and content manipulation functions for
+ * VMKERNEL.
*/
-#ifdef VMKERNEL
+
+#if defined(VMKERNEL)
/*
* For guest kernels, the VMCIQueue is directly mapped onto the
struct QueuePairEntry *entry; // Endpoint state for the queue pair
} VMCIQueue;
-
/* VMCI Queuepair API */
void VMCIQueue_Init(const VMCIHandle handle, VMCIQueue *queue);
void VMCIQueue_GetPointers(const VMCIQueue *produceQ, const VMCIQueue *consumeQ,
uint64 *producerTail, uint64 *consumerHead);
-int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
- uint64 produceSize, VMCIQueue **consumeQ,
- uint64 consumeSize, VMCIId peer, uint32 flags);
-int VMCIQueuePair_Detach(VMCIHandle handle);
int64 VMCIQueue_FreeSpace(const VMCIQueue *produceQueue,
const VMCIQueue *consumeQueue,
const uint64 produceQSize);
size_t bufSize, Util_BufferType bufType);
#endif /* VMKERNEL */
+#if defined(VMKERNEL) || defined(__linux__) || defined(_WIN32)
+int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
+ uint64 produceSize, VMCIQueue **consumeQ,
+ uint64 consumeSize, VMCIId peer, uint32 flags);
+int VMCIQueuePair_Detach(VMCIHandle handle);
+#endif
+
#endif /* !__VMCI_HOSTKERNELAPI_H__ */
*
* Results:
* VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
- * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
+ * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
* (as defined by the queue size).
* Otherwise the number of bytes dequeued is returned.
*
const uint64 consumeQSize, // IN:
void *buf, // IN:
size_t bufSize, // IN:
- VMCIMemcpyFromQueueFunc memcpyFromQueue) // IN:
+ VMCIMemcpyFromQueueFunc memcpyFromQueue, // IN:
+ Bool updateConsumer) // IN:
{
const int64 bufReady = VMCIQueue_BufReady(consumeQueue, produceQueue,
consumeQSize);
memcpyFromQueue(buf, 0, consumeQueue, head, tmp);
memcpyFromQueue(buf, tmp, consumeQueue, 0, written - tmp);
}
- AddPointer(&VMCIQueue_GetHeader(produceQueue)->consumerHead, written, consumeQSize);
+
+ if (updateConsumer) {
+ AddPointer(&VMCIQueue_GetHeader(produceQueue)->consumerHead, written,
+ consumeQSize);
+ }
return written;
}
size_t bufSize) // IN:
{
return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
- buf, bufSize, VMCIMemcpyFromQueue);
+ buf, bufSize, VMCIMemcpyFromQueue, TRUE);
}
size_t iovSize) // IN:
{
return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
- (void *)iov, iovSize, VMCIMemcpyFromQueueV);
+ (void *)iov, iovSize, VMCIMemcpyFromQueueV, TRUE);
+}
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_Peek --
+ *
+ * Reads data (if available) from the given consume queue. Copies data
+ * to the provided user buffer but does not update the consumer counter
+ * of the queue.
+ *
+ * Results:
+ * VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
+ * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
+ * (as defined by the queue size).
+ * Otherwise the number of bytes copied to user buffer is returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE ssize_t
+VMCIQueue_Peek(VMCIQueue *produceQueue, // IN:
+ const VMCIQueue *consumeQueue, // IN:
+ const uint64 consumeQSize, // IN:
+ void *buf, // IN:
+ size_t bufSize) // IN:
+{
+ return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
+ buf, bufSize, VMCIMemcpyFromQueue, FALSE);
+}
+
+
+#if defined(SOLARIS) || (defined(__linux__) && defined(__KERNEL__))
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_PeekV --
+ *
+ * Reads data (if available) from the given consume queue. Copies data
+ * to the provided user iovec but does not update the consumer counter
+ * of the queue.
+ *
+ * Results:
+ * VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
+ * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
+ * (as defined by the queue size).
+ * Otherwise the number of bytes copied to user iovec is returned.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE ssize_t
+VMCIQueue_PeekV(VMCIQueue *produceQueue, // IN:
+ const VMCIQueue *consumeQueue, // IN:
+ const uint64 consumeQSize, // IN:
+ struct iovec *iov, // IN:
+ size_t iovSize) // IN:
+{
+ return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
+ (void *)iov, iovSize, VMCIMemcpyFromQueueV, FALSE);
}
#endif
FLAGDEF( 87, EDX, AMD, 5, 1, STC, NA, IGNORE, 0, FALSE) \
FLAGDEF( 87, EDX, AMD, 6, 1, 100MHZSTEPS, NA, IGNORE, 0, FALSE) \
FLAGDEF( 87, EDX, AMD, 7, 1, HWPSTATE, NA, IGNORE, 0, FALSE) \
-FLAGDEF( 87, EDX, AMD, 8, 1, TSC_INVARIANT, NA, IGNORE, 0, FALSE) \
+FLAGDEF( 87, EDX, COMMON, 8, 1, TSC_INVARIANT, NA, IGNORE, 0, FALSE) \
FIELDDEFA(88, EAX, COMMON, 0, 8, PHYSBITS, NA, IGNORE, 0, FALSE, PHYS_BITS) \
FIELDDEFA(88, EAX, COMMON, 8, 8, VIRTBITS, NA, IGNORE, 0, FALSE, VIRT_BITS) \
FIELDDEFA(88, ECX, AMD, 0, 8, CORE_COUNT, NA, IGNORE, 0, FALSE, AMD_CORE_COUNT) \
#define CPUID_MODEL_PIII_08 8
#define CPUID_MODEL_PIII_0A 10
+/* AMD model information */
+#define CPUID_MODEL_BARCELONA_02 0x02 // Barcelona (both Opteron & Phenom kind)
+
/*
*----------------------------------------------------------------------
*
CPUID_FAMILY_IS_K8MOBILE(_eax);
}
+/*
+ * AMD Barcelona (of either Opteron or Phenom kind).
+ */
+static INLINE Bool
+CPUID_MODEL_IS_BARCELONA(uint32 v) // IN: %eax from CPUID with %eax=1.
+{
+ /* Assumes the CPU manufacturer is AMD. */
+ return CPUID_FAMILY_IS_K8L(v) &&
+ CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_BARCELONA_02;
+}
+
#define CPUID_TYPE_PRIMARY 0
#define CPUID_TYPE_OVERDRIVE 1
#include "compat_workqueue.h"
#include "compat_list.h"
#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL)
-# include "compat_semaphore.h"
+# include "compat_semaphore.h"
#endif
#include "vmware.h"
#include "vsockPacket.h"
#include "vsockVmci.h"
-#include "vmci_defs.h"
-#include "vmci_call_defs.h"
#include "vmci_iocontrols.h"
-#ifdef VMX86_TOOLS
-# include "vmciGuestKernelAPI.h"
-#else
-# include "vmciHostKernelAPI.h"
-#endif
#include "af_vsock.h"
#include "util.h"
/* Internal functions. */
static int VSockVmciGetAFValue(void);
static int VSockVmciRecvDgramCB(void *data, VMCIDatagram *dg);
-#ifdef VMX86_TOOLS
static int VSockVmciRecvStreamCB(void *data, VMCIDatagram *dg);
static void VSockVmciPeerAttachCB(VMCIId subId,
VMCI_EventData *ed, void *clientData);
static int VSockVmciRecvConnectingClientNegotiate(struct sock *sk,
VSockPacket *pkt);
static int VSockVmciRecvConnected(struct sock *sk, VSockPacket *pkt);
-#endif
static int __VSockVmciBind(struct sock *sk, struct sockaddr_vm *addr);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
static struct sock *__VSockVmciCreate(struct socket *sock, unsigned int priority,
struct socket *sock, gfp_t priority,
unsigned short type);
#endif
-static inline void VSockVmciTestUnregister(void);
+static void VSockVmciTestUnregister(void);
static int VSockVmciRegisterAddressFamily(void);
static void VSockVmciUnregisterAddressFamily(void);
struct sockaddr *addr, int addrLen);
static int VSockVmciDgramConnect(struct socket *sock,
struct sockaddr *addr, int addrLen, int flags);
-#ifdef VMX86_TOOLS
static int VSockVmciStreamConnect(struct socket *sock,
struct sockaddr *addr, int addrLen, int flags);
static int VSockVmciAccept(struct socket *sock, struct socket *newsock, int flags);
-#endif
static int VSockVmciGetname(struct socket *sock,
struct sockaddr *addr, int *addrLen, int peer);
static unsigned int VSockVmciPoll(struct file *file,
struct socket *sock, poll_table *wait);
-#ifdef VMX86_TOOLS
static int VSockVmciListen(struct socket *sock, int backlog);
-#endif
static int VSockVmciShutdown(struct socket *sock, int mode);
-#ifdef VMX86_TOOLS
static int VSockVmciStreamSetsockopt(struct socket *sock, int level, int optname,
char __user *optval, int optlen);
static int VSockVmciStreamGetsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user * optlen);
-#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
static int VSockVmciDgramSendmsg(struct socket *sock, struct msghdr *msg,
int len, struct scm_cookie *scm);
static int VSockVmciDgramRecvmsg(struct socket *sock, struct msghdr *msg,
int len, int flags, struct scm_cookie *scm);
-# ifdef VMX86_TOOLS
static int VSockVmciStreamSendmsg(struct socket *sock, struct msghdr *msg,
int len, struct scm_cookie *scm);
static int VSockVmciStreamRecvmsg(struct socket *sock, struct msghdr *msg,
int len, int flags, struct scm_cookie *scm);
-# endif
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
static int VSockVmciDgramSendmsg(struct kiocb *kiocb, struct socket *sock,
struct msghdr *msg, int len,
static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock,
struct msghdr *msg, int len,
int flags, struct scm_cookie *scm);
-# ifdef VMX86_TOOLS
static int VSockVmciStreamSendmsg(struct kiocb *kiocb, struct socket *sock,
struct msghdr *msg, int len,
struct scm_cookie *scm);
static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock,
struct msghdr *msg, int len,
int flags, struct scm_cookie *scm);
-# endif
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
static int VSockVmciDgramSendmsg(struct kiocb *kiocb,
struct socket *sock, struct msghdr *msg, int len);
static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock,
struct msghdr *msg, int len, int flags);
-# ifdef VMX86_TOOLS
static int VSockVmciStreamSendmsg(struct kiocb *kiocb,
struct socket *sock, struct msghdr *msg, int len);
static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock,
struct msghdr *msg, int len, int flags);
-# endif
#else
static int VSockVmciDgramSendmsg(struct kiocb *kiocb,
struct socket *sock, struct msghdr *msg, size_t len);
static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock,
struct msghdr *msg, size_t len, int flags);
-# ifdef VMX86_TOOLS
static int VSockVmciStreamSendmsg(struct kiocb *kiocb,
struct socket *sock, struct msghdr *msg, size_t len);
static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock,
struct msghdr *msg, size_t len, int flags);
-# endif
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
#endif
};
-#ifdef VMX86_TOOLS
static struct proto_ops vsockVmciStreamOps = {
.family = VSOCK_INVALID_FAMILY,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69)
.sendpage = sock_no_sendpage,
#endif
};
-#endif
static struct file_operations vsockVmciDeviceOps = {
#ifdef HAVE_UNLOCKED_IOCTL
static int vsockVmciSocketCount = 0;
static int vsockVmciKernClientCount = 0;
#ifdef VMX86_TOOLS
-static VMCIHandle vmciStreamHandle = { VMCI_INVALID_ID, VMCI_INVALID_ID };
static Bool vmciDevicePresent = FALSE;
-static VMCIId qpResumedSubId = VMCI_INVALID_ID;
#endif
+static VMCIHandle vmciStreamHandle = { VMCI_INVALID_ID, VMCI_INVALID_ID };
+static VMCIId qpResumedSubId = VMCI_INVALID_ID;
/* Comment this out to compare with old protocol. */
#define VSOCK_OPTIMIZATION_WAITING_NOTIFY 1
-#if defined(VMX86_TOOLS) && defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
/* Comment this out to remove flow control for "new" protocol */
# define VSOCK_OPTIMIZATION_FLOW_CONTROL 1
#endif
*----------------------------------------------------------------------------
*/
-static inline void
+static void
VSockVmciTestUnregister(void)
{
if (devOpenCount <= 0 && vsockVmciSocketCount <= 0 &&
*----------------------------------------------------------------------------
*/
-static inline void
+static void
VSockVmciUpdateQueueBucketCount(VMCIQueue *mainQueue, // IN
VMCIQueue *otherQueue, // IN
- uint64 mainQueueSize, // IN
+ uint64 mainQueueSize, // IN
uint64 queueLevel[]) // IN
{
uint64 bucket = 0;
uint32 remainder = 0;
uint64 dataReady = VMCIQueue_BufReady(mainQueue,
- otherQueue,
- mainQueueSize);
+ otherQueue,
+ mainQueueSize);
/*
* We can't do 64 / 64 = 64 bit divides on linux because it requires a libgcc
* which is not linked into the kernel module. Since this code is only used by
}
#endif
-
-#ifdef VMX86_TOOLS
/*
*----------------------------------------------------------------------------
*
static Bool
VSockVmciNotifyWaitingWrite(VSockVmciSock *vsk) // IN
{
-#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
Bool retval;
uint64 notifyLimit;
static Bool
VSockVmciNotifyWaitingRead(VSockVmciSock *vsk) // IN
{
-#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
if (!vsk->peerWaitingRead) {
return FALSE;
}
struct sockaddr_vm *dst, // IN: unused
struct sockaddr_vm *src) // IN: unused
{
-#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
VSockVmciSock *vsk;
vsk = vsock_sk(sk);
struct sockaddr_vm *dst, // IN: unused
struct sockaddr_vm *src) // IN: unused
{
-#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
VSockVmciSock *vsk;
vsk = vsock_sk(sk);
struct sockaddr_vm *dst, // IN
struct sockaddr_vm *src) // IN
{
-#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
VSockVmciSock *vsk;
vsk = vsock_sk(sk);
struct sockaddr_vm *dst, // IN
struct sockaddr_vm *src) // IN
{
-#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
VSockVmciSock *vsk;
vsk = vsock_sk(sk);
}
#endif
}
-#endif
/*
}
-#ifdef VMX86_TOOLS
/*
*----------------------------------------------------------------------------
*
*----------------------------------------------------------------------------
*/
-static INLINE void
+static void
VSockVmciHandleDetach(struct sock *sk) // IN
{
VSockVmciSock *vsk;
ASSERT(vsk->produceQ);
ASSERT(vsk->consumeQ);
-#ifdef VMX86_TOOLS
if (sk->compat_sk_type == SOCK_STREAM &&
- sk->compat_sk_state == SS_CONNECTED) {
- compat_sock_set_done(sk);
+ sk->compat_sk_state == SS_CONNECTED) {
+ compat_sock_set_done(sk);
}
-#endif
/* On a detach the peer will not be sending or receiving anymore. */
vsk->peerShutdown = SHUTDOWN_MASK;
return err;
}
-#endif
/*
}
-#ifdef VMX86_TOOLS
/*
*----------------------------------------------------------------------------
*
VSockVmciSendWaitingWrite(struct sock *sk, // IN
uint64 roomNeeded) // IN
{
-#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
VSockVmciSock *vsk;
VSockWaitingInfo waitingInfo;
uint64 tail;
VSockVmciSendWaitingRead(struct sock *sk, // IN
uint64 roomNeeded) // IN
{
-#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
VSockVmciSock *vsk;
VSockWaitingInfo waitingInfo;
uint64 tail;
}
return err;
}
-#endif // VMX86_TOOLS
/*
INIT_LIST_HEAD(&vsk->boundTable);
INIT_LIST_HEAD(&vsk->connectedTable);
vsk->dgHandle = VMCI_INVALID_HANDLE;
-#ifdef VMX86_TOOLS
vsk->qpHandle = VMCI_INVALID_HANDLE;
vsk->produceQ = vsk->consumeQ = NULL;
vsk->produceQGeneration = vsk->consumeQGeneration = 0;
vsk->rejected = FALSE;
vsk->attachSubId = vsk->detachSubId = VMCI_INVALID_ID;
vsk->peerShutdown = 0;
-#endif
if (sock) {
VSockVmciInsertBound(vsockUnboundSockets, sk);
}
/* Clean up any sockets that never were accepted. */
-#ifdef VMX86_TOOLS
while ((pending = VSockVmciDequeueAccept(sk)) != NULL) {
__VSockVmciRelease(pending);
sock_put(pending);
}
-#endif
release_sock(sk);
sock_put(sk);
vsk = vsock_sk(sk);
-#ifdef VMX86_TOOLS
if (vsk->attachSubId != VMCI_INVALID_ID) {
VMCIEvent_Unsubscribe(vsk->attachSubId);
vsk->attachSubId = VMCI_INVALID_ID;
vsk->produceQ = vsk->consumeQ = NULL;
vsk->produceSize = vsk->consumeSize = 0;
}
-#endif
/*
* Each list entry holds a reference on the socket, so we should not even be
*/
ASSERT(!VSockVmciInBoundTable(sk));
ASSERT(!VSockVmciInConnectedTable(sk));
-#ifdef VMX86_TOOLS
ASSERT(!VSockVmciIsPending(sk));
ASSERT(!VSockVmciInAcceptQueue(sk));
-#endif
/*
* When clearing these addresses, there's no need to set the family and
*----------------------------------------------------------------------------
*/
-static INLINE int
+static int
VSockVmciRegisterProto(void)
{
- int err;
-
- err = 0;
+ int err = 0;
/*
* Before 2.6.9, each address family created their own slab (by calling
*----------------------------------------------------------------------------
*/
-static INLINE void
+static void
VSockVmciUnregisterProto(void)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
}
for (index = 0; index < ARRAYSIZE(consumeQueueLevel); index++) {
- consumeQueueLevel[index] = 0;
+ consumeQueueLevel[index] = 0;
}
for (index = 0; index < ARRAYSIZE(produceQueueLevel); index++) {
- produceQueueLevel[index] = 0;
+ produceQueueLevel[index] = 0;
}
}
Log("Could not register VMCI Sockets because VMCI device is not present.\n");
return -1;
}
+#endif
/*
* Create the datagram handle that we will use to send and receive all
qpResumedSubId = VMCI_INVALID_ID;
goto error;
}
-#endif
/*
* Linux will not allocate an address family to code that is not part of the
vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY;
} else {
vsockVmciDgramOps.family = i;
-#ifdef VMX86_TOOLS
vsockVmciStreamOps.family = i;
-#endif
break;
}
}
return vsockVmciFamilyOps.family;
error:
-#ifdef VMX86_TOOLS
if (qpResumedSubId != VMCI_INVALID_ID) {
VMCIEvent_Unsubscribe(qpResumedSubId);
qpResumedSubId = VMCI_INVALID_ID;
}
VMCIDatagram_DestroyHnd(vmciStreamHandle);
-#endif
return err;
}
/* Nothing was registered. */
return;
}
+#endif
if (!VMCI_HANDLE_INVALID(vmciStreamHandle)) {
if (VMCIDatagram_DestroyHnd(vmciStreamHandle) != VMCI_SUCCESS) {
VMCIEvent_Unsubscribe(qpResumedSubId);
qpResumedSubId = VMCI_INVALID_ID;
}
-#endif
if (vsockVmciFamilyOps.family != VSOCK_INVALID_FAMILY) {
sock_unregister(vsockVmciFamilyOps.family);
}
vsockVmciDgramOps.family = vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY;
-#ifdef VMX86_TOOLS
vsockVmciStreamOps.family = vsockVmciFamilyOps.family;
-#endif
}
}
-#ifdef VMX86_TOOLS
/*
*----------------------------------------------------------------------------
*
release_sock(listener);
return err;
}
-#endif
/*
if (!(sk->compat_sk_shutdown & SEND_SHUTDOWN)) {
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
}
-#ifdef VMX86_TOOLS
} else if (sock->type == SOCK_STREAM) {
VSockVmciSock *vsk;
}
release_sock(sk);
-#endif
}
return mask;
}
-#ifdef VMX86_TOOLS
/*
*----------------------------------------------------------------------------
*
release_sock(sk);
return err;
}
-#endif
/*
release_sock(sk);
}
-#ifdef VMX86_TOOLS
if (sk->compat_sk_type == SOCK_STREAM && mode) {
compat_sock_reset_done(sk);
VSOCK_SEND_SHUTDOWN(sk, mode);
}
-#endif
return 0;
}
return err;
}
-#ifdef VMX86_TOOLS
/*
*----------------------------------------------------------------------------
*
return err;
}
-#endif
-#ifdef VMX86_TOOLS
/*
*----------------------------------------------------------------------------
*
}
return 0;
}
-#endif
-#ifdef VMX86_TOOLS
/*
*----------------------------------------------------------------------------
*
ssize_t totalWritten;
long timeout;
int err;
-#if defined(VMX86_TOOLS) && defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
uint64 produceTail;
uint64 consumeHead;
#endif
* size. It is the caller's responsibility to check how many bytes we were
* able to send.
*/
-#if defined(VMX86_TOOLS) && defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
VMCIQueue_GetPointers(vsk->produceQ, vsk->consumeQ,
&produceTail, &consumeHead);
#endif
goto outWait;
}
-#if defined(VMX86_TOOLS) && defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
/*
* Detect a wrap-around to maintain queue generation. Note that this is
* safe since we hold the socket lock across the two queue pair
Warning("unable to send wrote notification to peer for socket %p.\n", sk);
goto outWait;
} else {
-#if defined(VMX86_TOOLS) && defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
vsk->peerWaitingRead = FALSE;
#endif
}
release_sock(sk);
return err;
}
-#endif
/*
}
-#ifdef VMX86_TOOLS
/*
*----------------------------------------------------------------------------
*
ssize_t copied;
Bool sentRead;
unsigned int retries;
-#if defined(VMX86_TOOLS) && defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
uint64 consumeHead;
uint64 produceTail;
#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL
!(vsk->peerShutdown & SEND_SHUTDOWN)) {
if (ready < 0) {
- /*
+ /*
* Invalid queue pair content. XXX This should be changed to
* a connection reset in a later change.
*/
* Now consume up to len bytes from the queue. Note that since we have the
* socket locked we should copy at least ready bytes.
*/
-#if defined(VMX86_TOOLS) && defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
VMCIQueue_GetPointers(vsk->consumeQ, vsk->produceQ,
&produceTail, &consumeHead);
#endif
- copied = VMCIQueue_DequeueV(vsk->produceQ, vsk->consumeQ,
+ if (flags & MSG_PEEK) {
+ copied = VMCIQueue_PeekV(vsk->produceQ, vsk->consumeQ,
vsk->consumeSize, msg->msg_iov, len);
+ } else {
+ copied = VMCIQueue_DequeueV(vsk->produceQ, vsk->consumeQ,
+ vsk->consumeSize, msg->msg_iov, len);
+ }
+
if (copied < 0) {
err = -ENOMEM;
goto outWait;
}
-#if defined(VMX86_TOOLS) && defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
- /*
- * Detect a wrap-around to maintain queue generation. Note that this is
- * safe since we hold the socket lock across the two queue pair
- * operations.
- */
- if (copied >= vsk->consumeSize - consumeHead) {
- vsk->consumeQGeneration++;
- }
-#endif
-
ASSERT(copied >= target);
/*
- * If the other side has shutdown for sending and there is nothing more to
- * read, then set our socket's RCV_SHUTDOWN flag and modify the socket
- * state.
+ * We only do these additional bookkeeping/notification steps if we actually
+ * copied something out of the queue pair instead of just peeking ahead.
*/
- if (vsk->peerShutdown & SEND_SHUTDOWN) {
- if (VMCIQueue_BufReady(vsk->consumeQ,
- vsk->produceQ, vsk->consumeSize) <= 0) {
- sk->compat_sk_shutdown |= RCV_SHUTDOWN;
- sk->compat_sk_state = SS_UNCONNECTED;
- compat_sock_set_done(sk);
- sk->compat_sk_state_change(sk);
+ if (!(flags & MSG_PEEK)) {
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ /*
+ * Detect a wrap-around to maintain queue generation. Note that this is
+ * safe since we hold the socket lock across the two queue pair
+ * operations.
+ */
+ if (copied >= vsk->consumeSize - consumeHead) {
+ vsk->consumeQGeneration++;
}
- }
+#endif
- err = VSockVmciSendReadNotification(sk);
- if (err < 0) {
- goto outWait;
+ /*
+ * If the other side has shutdown for sending and there is nothing more to
+ * read, then set our socket's RCV_SHUTDOWN flag and modify the socket
+ * state.
+ */
+ if (vsk->peerShutdown & SEND_SHUTDOWN) {
+ if (VMCIQueue_BufReady(vsk->consumeQ,
+ vsk->produceQ, vsk->consumeSize) <= 0) {
+ sk->compat_sk_shutdown |= RCV_SHUTDOWN;
+ sk->compat_sk_state = SS_UNCONNECTED;
+ compat_sock_set_done(sk);
+ sk->compat_sk_state_change(sk);
+ }
+ }
+
+ err = VSockVmciSendReadNotification(sk);
+ if (err < 0) {
+ goto outWait;
+ }
}
ASSERT(copied <= INT_MAX);
release_sock(sk);
return err;
}
-#endif
/*
case SOCK_DGRAM:
sock->ops = &vsockVmciDgramOps;
break;
-# ifdef VMX86_TOOLS
- /*
- * Queue pairs are /currently/ only supported within guests, so stream
- * sockets are only supported within guests.
- */
case SOCK_STREAM:
sock->ops = &vsockVmciStreamOps;
break;
-# endif
default:
return -ESOCKTNOSUPPORT;
}
#include "vsockPacket.h"
#include "compat_workqueue.h"
+#if defined(VMX86_TOOLS)
+# include "vmciGuestKernelAPI.h"
+#else
+# include "vmciHostKernelAPI.h"
+#endif
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
# define vsock_sk(__sk) ((VSockVmciSock *)(__sk)->user_data)
# define sk_vsock(__vsk) ((__vsk)->sk)
struct list_head boundTable;
struct list_head connectedTable;
VMCIHandle dgHandle; /* For SOCK_DGRAM only. */
-#ifdef VMX86_TOOLS
/* Rest are SOCK_STREAM only. */
VMCIHandle qpHandle;
VMCIQueue *produceQ;
Bool rejected;
compat_delayed_work dwork;
uint32 peerShutdown;
-#endif
} VSockVmciSock;
#endif /* __AF_VSOCK_H__ */
}
-#ifdef VMX86_TOOLS
/*
*----------------------------------------------------------------------------
*
vsk = vsock_sk(sk);
return !list_empty(&vsk->pendingLinks);
}
-#endif
Bool __VSockVmciInBoundTable(struct sock *sk);
Bool __VSockVmciInConnectedTable(struct sock *sk);
-#ifdef VMX86_TOOLS
struct sock *VSockVmciGetPending(struct sock *listener, VSockPacket *pkt);
void VSockVmciReleasePending(struct sock *pending);
void VSockVmciAddPending(struct sock *listener, struct sock *pending);
Bool VSockVmciInAcceptQueue(struct sock *sk);
Bool VSockVmciIsAcceptQueueEmpty(struct sock *sk);
Bool VSockVmciIsPending(struct sock *sk);
-#endif
static INLINE void VSockVmciInsertBound(struct list_head *list, struct sock *sk);
static INLINE void VSockVmciInsertConnected(struct list_head *list, struct sock *sk);
# define EHOSTUNREACH WSAEHOSTUNREACH
# define __ELOCALSHUTDOWN ESHUTDOWN
# define __EPEERSHUTDOWN ECONNABORTED
+# define __ECONNINPROGRESS EWOULDBLOCK
#else
#if defined(VMKERNEL)
# define EINTR VMK_WAIT_INTERRUPTED
# define EPIPE VMK_BROKEN_PIPE
# define __ELOCALSHUTDOWN EPIPE
# define __EPEERSHUTDOWN EPIPE
+# define __ECONNINPROGRESS EINPROGRESS
#endif // VMKERNEL
#endif // _WIN32
CFLAGS += $(GLOBAL_DEFS)
CFLAGS += $(CC_WARNINGS)
CFLAGS += -DVMX86_TOOLS
-CFLAGS += -D_KERNEL
ifdef VMX86_DEVEL
CFLAGS += -DVMX86_DEVEL
endif
-ifdef VMX86_DEBUG # For assertions
+ifdef VMX86_DEBUG # For assertions
CFLAGS += -DVMX86_DEBUG
endif
-ifdef VMX86_LOG # For debug logging
+ifdef VMX86_LOG # For debug logging
CFLAGS += -DVM_DEBUGGING_ON
endif
##
## Objects needed to build the HGFS kernel module
##
-SOLHGFS_OBJS := debug.o
-SOLHGFS_OBJS += device.o
-SOLHGFS_OBJS += filesystem.o
-SOLHGFS_OBJS += hgfsState.o
-SOLHGFS_OBJS += module.o
-SOLHGFS_OBJS += request.o
-SOLHGFS_OBJS += vnode.o
-SOLHGFS_OBJS += cpName.o
-SOLHGFS_OBJS += cpNameLinux.o
-SOLHGFS_OBJS += dbllnklst.o
-SOLHGFS_OBJS += hgfsEscape.o
-SOLHGFS_OBJS += hgfsUtil.o
-SOLHGFS_OBJS += sha1.o
-
-SOLHGFS_32_OBJS := $(addprefix i386/, $(SOLHGFS_OBJS))
-SOLHGFS_64_OBJS := $(addprefix amd64/, $(SOLHGFS_OBJS))
+SOLHGFS_KRN_OBJS := debug.o
+SOLHGFS_KRN_OBJS += filesystem.o
+SOLHGFS_KRN_OBJS += hgfsBdGlue.o
+SOLHGFS_KRN_OBJS += hgfsState.o
+SOLHGFS_KRN_OBJS += kernelStubsSolaris.o
+SOLHGFS_KRN_OBJS += module.o
+SOLHGFS_KRN_OBJS += request.o
+SOLHGFS_KRN_OBJS += vnode.o
+
+SOLHGFS_32_KRN_OBJS := $(addprefix i386/, $(SOLHGFS_KRN_OBJS))
+SOLHGFS_64_KRN_OBJS := $(addprefix amd64/, $(SOLHGFS_KRN_OBJS))
+
+SOLHGFS_LIB_OBJS := backdoor.o
+SOLHGFS_LIB_OBJS += cpName.o
+SOLHGFS_LIB_OBJS += cpNameLinux.o
+SOLHGFS_LIB_OBJS += dbllnklst.o
+SOLHGFS_LIB_OBJS += hgfsBd.o
+SOLHGFS_LIB_OBJS += hgfsEscape.o
+SOLHGFS_LIB_OBJS += hgfsUtil.o
+SOLHGFS_LIB_OBJS += message.o
+SOLHGFS_LIB_OBJS += messageBackdoor.o
+SOLHGFS_LIB_OBJS += rpcout.o
+SOLHGFS_LIB_OBJS += sha1.o
+
+SOLHGFS_32_LIB_OBJS := $(addprefix i386/, $(SOLHGFS_LIB_OBJS))
+SOLHGFS_32_LIB_OBJS += i386/backdoorGcc32.o
+
+SOLHGFS_64_LIB_OBJS := $(addprefix amd64/, $(SOLHGFS_LIB_OBJS))
+SOLHGFS_64_LIB_OBJS += amd64/backdoorGcc64.o
+
+SOLHGFS_32_OBJS := $(SOLHGFS_32_KRN_OBJS) $(SOLHGFS_32_LIB_OBJS)
+SOLHGFS_64_OBJS := $(SOLHGFS_64_KRN_OBJS) $(SOLHGFS_64_LIB_OBJS)
MODULE_32 := i386/$(MODULE)
MODULE_64 := amd64/$(MODULE)
@echo "Linking $(MODULE_32)"
$(LD) $(LDFLAGS_32) -r -o $(MODULE_32) $(SOLHGFS_32_OBJS)
-$(SOLHGFS_32_OBJS): i386/%.o: %.c
+$(SOLHGFS_32_KRN_OBJS): i386/%.o: %.c
+ @echo "Compiling $(<F)"
+ $(CC) $(CFLAGS_32) -D_KERNEL -c $< -o $@
+
+$(SOLHGFS_32_LIB_OBJS): i386/%.o: %.c
@echo "Compiling $(<F)"
$(CC) $(CFLAGS_32) -c $< -o $@
@echo "Linking $(MODULE_64)"
$(LD) $(LDFLAGS_64) -r -o $(MODULE_64) $(SOLHGFS_64_OBJS)
-$(SOLHGFS_64_OBJS): amd64/%.o: %.c
+$(SOLHGFS_64_KRN_OBJS): amd64/%.o: %.c
+ @echo "Compiling $(<F)"
+ $(CC) $(CFLAGS_64) -D_KERNEL -c $< -o $@
+
+$(SOLHGFS_64_LIB_OBJS): amd64/%.o: %.c
@echo "Compiling $(<F)"
$(CC) $(CFLAGS_64) -c $< -o $@
clean:
@echo "Cleaning directories"
- @rm -f $(MODULE_32) $(SOLHGFS_32_OBJS) i386
- @rm -r $(MODULE_64) $(SOLHGFS_32_OBJS) amd64
+ @rm -rf $(MODULE_32) $(SOLHGFS_32_OBJS) i386
+ @rm -rf $(MODULE_64) $(SOLHGFS_32_OBJS) amd64
install:
@echo "Installing modules"
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1999 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * backdoor.c --
+ *
+ * First layer of the internal communication channel between guest
+ * applications and vmware
+ *
+ * This is the backdoor. By using special ports of the virtual I/O space,
+ * and the virtual CPU registers, a guest application can send a
+ * synchroneous basic request to vmware, and vmware can reply to it.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__KERNEL__) || defined(_KERNEL)
+#else
+# include "debug.h"
+#endif
+
+#include "backdoor_def.h"
+#include "backdoor.h"
+#include "backdoorInt.h"
+
+#if defined(BACKDOOR_DEBUG) && defined(USERLEVEL)
+# include <stdio.h>
+# define BACKDOOR_LOG(args) Debug args
+# define BACKDOOR_LOG_PROTO_STRUCT(x) BackdoorPrintProtoStruct((x))
+# define BACKDOOR_LOG_HB_PROTO_STRUCT(x) BackdoorPrintHbProtoStruct((x))
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * BackdoorPrintProtoStruct --
+ * BackdoorPrintHbProtoStruct --
+ *
+ * Print the contents of the specified backdoor protocol structure via
+ * printf.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Output to stdout.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+BackdoorPrintProtoStruct(Backdoor_proto *myBp)
+{
+ Debug("magic 0x%08x, command %d, size %"FMTSZ"u, port %d\n",
+ myBp->in.ax.word, myBp->in.cx.halfs.low,
+ myBp->in.size, myBp->in.dx.halfs.low);
+
+#ifndef VM_X86_64
+ Debug("ax %#x, "
+ "bx %#x, "
+ "cx %#x, "
+ "dx %#x, "
+ "si %#x, "
+ "di %#x\n",
+ myBp->out.ax.word,
+ myBp->out.bx.word,
+ myBp->out.cx.word,
+ myBp->out.dx.word,
+ myBp->out.si.word,
+ myBp->out.di.word);
+#else
+ Debug("ax %#"FMT64"x, "
+ "bx %#"FMT64"x, "
+ "cx %#"FMT64"x, "
+ "dx %#"FMT64"x, "
+ "si %#"FMT64"x, "
+ "di %#"FMT64"x\n",
+ myBp->out.ax.quad,
+ myBp->out.bx.quad,
+ myBp->out.cx.quad,
+ myBp->out.dx.quad,
+ myBp->out.si.quad,
+ myBp->out.di.quad);
+#endif
+}
+
+
+void
+BackdoorPrintHbProtoStruct(Backdoor_proto_hb *myBp)
+{
+ Debug("magic 0x%08x, command %d, size %"FMTSZ"u, port %d, "
+ "srcAddr %"FMTSZ"u, dstAddr %"FMTSZ"u\n",
+ myBp->in.ax.word, myBp->in.bx.halfs.low, myBp->in.size,
+ myBp->in.dx.halfs.low, myBp->in.srcAddr, myBp->in.dstAddr);
+
+#ifndef VM_X86_64
+ Debug("ax %#x, "
+ "bx %#x, "
+ "cx %#x, "
+ "dx %#x, "
+ "si %#x, "
+ "di %#x, "
+ "bp %#x\n",
+ myBp->out.ax.word,
+ myBp->out.bx.word,
+ myBp->out.cx.word,
+ myBp->out.dx.word,
+ myBp->out.si.word,
+ myBp->out.di.word,
+ myBp->out.bp.word);
+#else
+ Debug("ax %#"FMT64"x, "
+ "bx %#"FMT64"x, "
+ "cx %#"FMT64"x, "
+ "dx %#"FMT64"x, "
+ "si %#"FMT64"x, "
+ "di %#"FMT64"x, "
+ "bp %#"FMT64"x\n",
+ myBp->out.ax.quad,
+ myBp->out.bx.quad,
+ myBp->out.cx.quad,
+ myBp->out.dx.quad,
+ myBp->out.si.quad,
+ myBp->out.di.quad,
+ myBp->out.bp.quad);
+#endif
+}
+
+#else
+# define BACKDOOR_LOG(args)
+# define BACKDOOR_LOG_PROTO_STRUCT(x)
+# define BACKDOOR_LOG_HB_PROTO_STRUCT(x)
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Backdoor --
+ *
+ * Send a low-bandwidth basic request (16 bytes) to vmware, and return its
+ * reply (24 bytes).
+ *
+ * Result:
+ * None
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Backdoor(Backdoor_proto *myBp) // IN/OUT
+{
+ ASSERT(myBp);
+
+ myBp->in.ax.word = BDOOR_MAGIC;
+ myBp->in.dx.halfs.low = BDOOR_PORT;
+
+ BACKDOOR_LOG(("Backdoor: before "));
+ BACKDOOR_LOG_PROTO_STRUCT(myBp);
+
+ Backdoor_InOut(myBp);
+
+ BACKDOOR_LOG(("Backdoor: after "));
+ BACKDOOR_LOG_PROTO_STRUCT(myBp);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Backdoor_HbOut --
+ *
+ * Send a high-bandwidth basic request to vmware, and return its
+ * reply.
+ *
+ * Result:
+ * The host-side response is returned via the IN/OUT parameter.
+ *
+ * Side-effects:
+ * Pokes the high-bandwidth backdoor.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Backdoor_HbOut(Backdoor_proto_hb *myBp) // IN/OUT
+{
+ ASSERT(myBp);
+
+ myBp->in.ax.word = BDOOR_MAGIC;
+ myBp->in.dx.halfs.low = BDOORHB_PORT;
+
+ BACKDOOR_LOG(("Backdoor_HbOut: before "));
+ BACKDOOR_LOG_HB_PROTO_STRUCT(myBp);
+
+ BackdoorHbOut(myBp);
+
+ BACKDOOR_LOG(("Backdoor_HbOut: after "));
+ BACKDOOR_LOG_HB_PROTO_STRUCT(myBp);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Backdoor_HbIn --
+ *
+ * Send a basic request to vmware, and return its high-bandwidth
+ * reply
+ *
+ * Result:
+ * Host-side response returned via the IN/OUT parameter.
+ *
+ * Side-effects:
+ * Pokes the high-bandwidth backdoor.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Backdoor_HbIn(Backdoor_proto_hb *myBp) // IN/OUT
+{
+ ASSERT(myBp);
+
+ myBp->in.ax.word = BDOOR_MAGIC;
+ myBp->in.dx.halfs.low = BDOORHB_PORT;
+
+ BACKDOOR_LOG(("Backdoor_HbIn: before "));
+ BACKDOOR_LOG_HB_PROTO_STRUCT(myBp);
+
+ BackdoorHbIn(myBp);
+
+ BACKDOOR_LOG(("Backdoor_HbIn: after "));
+ BACKDOOR_LOG_HB_PROTO_STRUCT(myBp);
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1999 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * backdoor.h --
+ *
+ * First layer of the internal communication channel between guest
+ * applications and vmware
+ */
+
+#ifndef _BACKDOOR_H_
+#define _BACKDOOR_H_
+
+#include "vm_basic_types.h"
+#include "vm_assert.h"
+
+#include "backdoor_types.h"
+
+void
+Backdoor(Backdoor_proto *bp); // IN/OUT
+
+void
+Backdoor_InOut(Backdoor_proto *bp); // IN/OUT
+
+void
+Backdoor_HbOut(Backdoor_proto_hb *bp); // IN/OUT
+
+void
+Backdoor_HbIn(Backdoor_proto_hb *bp); // IN/OUT
+
+#endif /* _BACKDOOR_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2005 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * backdoorGcc32.c --
+ *
+ * Implements the real work for guest-side backdoor for GCC, 32-bit
+ * target (supports inline ASM, GAS syntax). The asm sections are marked
+ * volatile since vmware can change the registers content without the
+ * compiler knowing it.
+ *
+ * XXX
+ * I tried to write this more cleanly, but:
+ * - There is no way to specify an "ebp" constraint
+ * - "ebp" is ignored when specified as cloberred register
+ * - gas barfs when there is more than 10 operands
+ * - gas 2.7.2.3, depending on the order of the operands, can
+ * mis-assemble without any warning
+ * --hpreg
+ *
+ * Note that the problems with gas noted above might longer be relevant
+ * now that we've upgraded most of our compiler versions.
+ * --rrdharan
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "backdoor.h"
+#include "backdoorInt.h"
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Backdoor_InOut --
+ *
+ * Send a low-bandwidth basic request (16 bytes) to vmware, and return its
+ * reply (24 bytes).
+ *
+ * Results:
+ * Host-side response returned in bp IN/OUT parameter.
+ *
+ * Side effects:
+ * Pokes the backdoor.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+Backdoor_InOut(Backdoor_proto *myBp) // IN/OUT
+{
+ uint32 dummy;
+
+ __asm__ __volatile__(
+#ifdef __PIC__
+ "pushl %%ebx" "\n\t"
+#endif
+ "pushl %%eax" "\n\t"
+ "movl 20(%%eax), %%edi" "\n\t"
+ "movl 16(%%eax), %%esi" "\n\t"
+ "movl 12(%%eax), %%edx" "\n\t"
+ "movl 8(%%eax), %%ecx" "\n\t"
+ "movl 4(%%eax), %%ebx" "\n\t"
+ "movl (%%eax), %%eax" "\n\t"
+ "inl %%dx, %%eax" "\n\t"
+ "xchgl %%eax, (%%esp)" "\n\t"
+ "movl %%edi, 20(%%eax)" "\n\t"
+ "movl %%esi, 16(%%eax)" "\n\t"
+ "movl %%edx, 12(%%eax)" "\n\t"
+ "movl %%ecx, 8(%%eax)" "\n\t"
+ "movl %%ebx, 4(%%eax)" "\n\t"
+ "popl (%%eax)" "\n\t"
+#ifdef __PIC__
+ "popl %%ebx" "\n\t"
+#endif
+ : "=a" (dummy)
+ : "0" (myBp)
+ /*
+ * vmware can modify the whole VM state without the compiler knowing
+ * it. So far it does not modify EFLAGS. --hpreg
+ */
+ :
+#ifndef __PIC__
+ "ebx",
+#endif
+ "ecx", "edx", "esi", "edi", "memory"
+ );
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * BackdoorHbIn --
+ * BackdoorHbOut --
+ *
+ * Send a high-bandwidth basic request to vmware, and return its
+ * reply.
+ *
+ * Results:
+ * Host-side response returned in bp IN/OUT parameter.
+ *
+ * Side-effects:
+ * Pokes the high-bandwidth backdoor port.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+BackdoorHbIn(Backdoor_proto_hb *myBp) // IN/OUT
+{
+ uint32 dummy;
+
+ __asm__ __volatile__(
+#ifdef __PIC__
+ "pushl %%ebx" "\n\t"
+#endif
+ "pushl %%ebp" "\n\t"
+
+ "pushl %%eax" "\n\t"
+ "movl 24(%%eax), %%ebp" "\n\t"
+ "movl 20(%%eax), %%edi" "\n\t"
+ "movl 16(%%eax), %%esi" "\n\t"
+ "movl 12(%%eax), %%edx" "\n\t"
+ "movl 8(%%eax), %%ecx" "\n\t"
+ "movl 4(%%eax), %%ebx" "\n\t"
+ "movl (%%eax), %%eax" "\n\t"
+ "cld" "\n\t"
+ "rep; insb" "\n\t"
+ "xchgl %%eax, (%%esp)" "\n\t"
+ "movl %%ebp, 24(%%eax)" "\n\t"
+ "movl %%edi, 20(%%eax)" "\n\t"
+ "movl %%esi, 16(%%eax)" "\n\t"
+ "movl %%edx, 12(%%eax)" "\n\t"
+ "movl %%ecx, 8(%%eax)" "\n\t"
+ "movl %%ebx, 4(%%eax)" "\n\t"
+ "popl (%%eax)" "\n\t"
+
+ "popl %%ebp" "\n\t"
+#ifdef __PIC__
+ "popl %%ebx" "\n\t"
+#endif
+ : "=a" (dummy)
+ : "0" (myBp)
+ /*
+ * vmware can modify the whole VM state without the compiler knowing
+ * it. --hpreg
+ */
+ :
+#ifndef __PIC__
+ "ebx",
+#endif
+ "ecx", "edx", "esi", "edi", "memory", "cc"
+ );
+}
+
+
+void
+BackdoorHbOut(Backdoor_proto_hb *myBp) // IN/OUT
+{
+ uint32 dummy;
+
+ __asm__ __volatile__(
+#ifdef __PIC__
+ "pushl %%ebx" "\n\t"
+#endif
+ "pushl %%ebp" "\n\t"
+
+ "pushl %%eax" "\n\t"
+ "movl 24(%%eax), %%ebp" "\n\t"
+ "movl 20(%%eax), %%edi" "\n\t"
+ "movl 16(%%eax), %%esi" "\n\t"
+ "movl 12(%%eax), %%edx" "\n\t"
+ "movl 8(%%eax), %%ecx" "\n\t"
+ "movl 4(%%eax), %%ebx" "\n\t"
+ "movl (%%eax), %%eax" "\n\t"
+ "cld" "\n\t"
+ "rep; outsb" "\n\t"
+ "xchgl %%eax, (%%esp)" "\n\t"
+ "movl %%ebp, 24(%%eax)" "\n\t"
+ "movl %%edi, 20(%%eax)" "\n\t"
+ "movl %%esi, 16(%%eax)" "\n\t"
+ "movl %%edx, 12(%%eax)" "\n\t"
+ "movl %%ecx, 8(%%eax)" "\n\t"
+ "movl %%ebx, 4(%%eax)" "\n\t"
+ "popl (%%eax)" "\n\t"
+
+ "popl %%ebp" "\n\t"
+#ifdef __PIC__
+ "popl %%ebx" "\n\t"
+#endif
+ : "=a" (dummy)
+ : "0" (myBp)
+ :
+#ifndef __PIC__
+ "ebx",
+#endif
+ "ecx", "edx", "esi", "edi", "memory", "cc"
+ );
+}
+
+#ifdef __cplusplus
+}
+#endif
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2005 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * backdoorGcc64.c --
+ *
+ * Implements the real work for guest-side backdoor for GCC, 64-bit
+ * target (supports inline ASM, GAS syntax). The asm sections are marked
+ * volatile since vmware can change the registers content without the
+ * compiler knowing it.
+ *
+ * See backdoorGCC32.c (from which this code was mostly copied) for
+ * details on why the ASM is written this way. Also note that it might be
+ * possible to write the asm blocks using the symbolic operand specifiers
+ * in such a way that the same asm would generate correct code for both
+ * 32-bit and 64-bit targets, but I'm too lazy to figure it all out.
+ * --rrdharan
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "backdoor.h"
+#include "backdoorInt.h"
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Backdoor_InOut --
+ *
+ * Send a low-bandwidth basic request (16 bytes) to vmware, and return its
+ * reply (24 bytes).
+ *
+ * Results:
+ * Host-side response returned in bp IN/OUT parameter.
+ *
+ * Side effects:
+ * Pokes the backdoor.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+Backdoor_InOut(Backdoor_proto *myBp) // IN/OUT
+{
+ uint64 dummy;
+
+ __asm__ __volatile__(
+ "pushq %%rax" "\n\t"
+ "movq 40(%%rax), %%rdi" "\n\t"
+ "movq 32(%%rax), %%rsi" "\n\t"
+ "movq 24(%%rax), %%rdx" "\n\t"
+ "movq 16(%%rax), %%rcx" "\n\t"
+ "movq 8(%%rax), %%rbx" "\n\t"
+ "movq (%%rax), %%rax" "\n\t"
+ "inl %%dx, %%eax" "\n\t" /* NB: There is no inq instruction */
+ "xchgq %%rax, (%%rsp)" "\n\t"
+ "movq %%rdi, 40(%%rax)" "\n\t"
+ "movq %%rsi, 32(%%rax)" "\n\t"
+ "movq %%rdx, 24(%%rax)" "\n\t"
+ "movq %%rcx, 16(%%rax)" "\n\t"
+ "movq %%rbx, 8(%%rax)" "\n\t"
+ "popq (%%rax)"
+ : "=a" (dummy)
+ : "0" (myBp)
+ /*
+ * vmware can modify the whole VM state without the compiler knowing
+ * it. So far it does not modify EFLAGS. --hpreg
+ */
+ : "rbx", "rcx", "rdx", "rsi", "rdi", "memory"
+ );
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * BackdoorHbIn --
+ * BackdoorHbOut --
+ *
+ * Send a high-bandwidth basic request to vmware, and return its
+ * reply.
+ *
+ * Results:
+ * Host-side response returned in bp IN/OUT parameter.
+ *
+ * Side-effects:
+ * Pokes the high-bandwidth backdoor port.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+BackdoorHbIn(Backdoor_proto_hb *myBp) // IN/OUT
+{
+ uint32 dummy;
+
+ __asm__ __volatile__(
+ "pushq %%rbp" "\n\t"
+
+ "pushq %%rax" "\n\t"
+ "movq 48(%%rax), %%rbp" "\n\t"
+ "movq 40(%%rax), %%rdi" "\n\t"
+ "movq 32(%%rax), %%rsi" "\n\t"
+ "movq 24(%%rax), %%rdx" "\n\t"
+ "movq 16(%%rax), %%rcx" "\n\t"
+ "movq 8(%%rax), %%rbx" "\n\t"
+ "movq (%%rax), %%rax" "\n\t"
+ "cld" "\n\t"
+ "rep; insb" "\n\t"
+ "xchgq %%rax, (%%rsp)" "\n\t"
+ "movq %%rbp, 48(%%rax)" "\n\t"
+ "movq %%rdi, 40(%%rax)" "\n\t"
+ "movq %%rsi, 32(%%rax)" "\n\t"
+ "movq %%rdx, 24(%%rax)" "\n\t"
+ "movq %%rcx, 16(%%rax)" "\n\t"
+ "movq %%rbx, 8(%%rax)" "\n\t"
+ "popq (%%rax)" "\n\t"
+
+ "popq %%rbp"
+ : "=a" (dummy)
+ : "0" (myBp)
+ /*
+ * vmware can modify the whole VM state without the compiler knowing
+ * it. --hpreg
+ */
+ : "rbx", "rcx", "rdx", "rsi", "rdi", "memory", "cc"
+ );
+}
+
+
+void
+BackdoorHbOut(Backdoor_proto_hb *myBp) // IN/OUT
+{
+ uint64 dummy;
+
+ __asm__ __volatile__(
+ "pushq %%rbp" "\n\t"
+
+ "pushq %%rax" "\n\t"
+ "movq 48(%%rax), %%rbp" "\n\t"
+ "movq 40(%%rax), %%rdi" "\n\t"
+ "movq 32(%%rax), %%rsi" "\n\t"
+ "movq 24(%%rax), %%rdx" "\n\t"
+ "movq 16(%%rax), %%rcx" "\n\t"
+ "movq 8(%%rax), %%rbx" "\n\t"
+ "movq (%%rax), %%rax" "\n\t"
+ "cld" "\n\t"
+ "rep; outsb" "\n\t"
+ "xchgq %%rax, (%%rsp)" "\n\t"
+ "movq %%rbp, 48(%%rax)" "\n\t"
+ "movq %%rdi, 40(%%rax)" "\n\t"
+ "movq %%rsi, 32(%%rax)" "\n\t"
+ "movq %%rdx, 24(%%rax)" "\n\t"
+ "movq %%rcx, 16(%%rax)" "\n\t"
+ "movq %%rbx, 8(%%rax)" "\n\t"
+ "popq (%%rax)" "\n\t"
+
+ "popq %%rbp"
+ : "=a" (dummy)
+ : "0" (myBp)
+ : "rbx", "rcx", "rdx", "rsi", "rdi", "memory", "cc"
+ );
+}
+
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2005 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * backdoorInt.h --
+ *
+ * Internal function prototypes for the real backdoor work.
+ */
+
+void BackdoorHbIn(Backdoor_proto_hb *bp);
+void BackdoorHbOut(Backdoor_proto_hb *bp);
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * backdoor_def.h --
+ *
+ * This contains backdoor defines that can be included from
+ * an assembly language file.
+ */
+
+
+
+#ifndef _BACKDOOR_DEF_H_
+#define _BACKDOOR_DEF_H_
+
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMKERNEL
+#include "includeCheck.h"
+
+/*
+ * If you want to add a new low-level backdoor call for a guest userland
+ * application, please consider using the GuestRpc mechanism instead. --hpreg
+ */
+
+#define BDOOR_MAGIC 0x564D5868
+
+/* Low-bandwidth backdoor port. --hpreg */
+
+#define BDOOR_PORT 0x5658
+
+#define BDOOR_CMD_GETMHZ 1
+/*
+ * BDOOR_CMD_APMFUNCTION is used by:
+ *
+ * o The FrobOS code, which instead should either program the virtual chipset
+ * (like the new BIOS code does, matthias offered to implement that), or not
+ * use any VM-specific code (which requires that we correctly implement
+ * "power off on CLI HLT" for SMP VMs, boris offered to implement that)
+ *
+ * o The old BIOS code, which will soon be jettisoned
+ *
+ * --hpreg
+ */
+#define BDOOR_CMD_APMFUNCTION 2
+#define BDOOR_CMD_GETDISKGEO 3
+#define BDOOR_CMD_GETPTRLOCATION 4
+#define BDOOR_CMD_SETPTRLOCATION 5
+#define BDOOR_CMD_GETSELLENGTH 6
+#define BDOOR_CMD_GETNEXTPIECE 7
+#define BDOOR_CMD_SETSELLENGTH 8
+#define BDOOR_CMD_SETNEXTPIECE 9
+#define BDOOR_CMD_GETVERSION 10
+#define BDOOR_CMD_GETDEVICELISTELEMENT 11
+#define BDOOR_CMD_TOGGLEDEVICE 12
+#define BDOOR_CMD_GETGUIOPTIONS 13
+#define BDOOR_CMD_SETGUIOPTIONS 14
+#define BDOOR_CMD_GETSCREENSIZE 15
+#define BDOOR_CMD_MONITOR_CONTROL 16
+#define BDOOR_CMD_GETHWVERSION 17
+#define BDOOR_CMD_OSNOTFOUND 18
+#define BDOOR_CMD_GETUUID 19
+#define BDOOR_CMD_GETMEMSIZE 20
+#define BDOOR_CMD_HOSTCOPY 21 /* Devel only */
+#define BDOOR_CMD_SERVICE_VM 22 /* prototype only */
+#define BDOOR_CMD_GETTIME 23 /* Deprecated. Use GETTIMEFULL. */
+#define BDOOR_CMD_STOPCATCHUP 24
+#define BDOOR_CMD_PUTCHR 25 /* Devel only */
+#define BDOOR_CMD_ENABLE_MSG 26 /* Devel only */
+#define BDOOR_CMD_GOTO_TCL 27 /* Devel only */
+#define BDOOR_CMD_INITPCIOPROM 28
+#define BDOOR_CMD_INT13 29
+#define BDOOR_CMD_MESSAGE 30
+#define BDOOR_CMD_RSVD0 31
+#define BDOOR_CMD_RSVD1 32
+#define BDOOR_CMD_RSVD2 33
+#define BDOOR_CMD_ISACPIDISABLED 34
+#define BDOOR_CMD_TOE 35 /* Not in use */
+#define BDOOR_CMD_ISMOUSEABSOLUTE 36
+#define BDOOR_CMD_PATCH_SMBIOS_STRUCTS 37
+#define BDOOR_CMD_MAPMEM 38 /* Devel only */
+#define BDOOR_CMD_ABSPOINTER_DATA 39
+#define BDOOR_CMD_ABSPOINTER_STATUS 40
+#define BDOOR_CMD_ABSPOINTER_COMMAND 41
+#define BDOOR_CMD_TIMER_SPONGE 42
+#define BDOOR_CMD_PATCH_ACPI_TABLES 43
+/* Catch-all to allow synchronous tests */
+#define BDOOR_CMD_DEVEL_FAKEHARDWARE 44 /* Debug only - needed in beta */
+#define BDOOR_CMD_GETHZ 45
+#define BDOOR_CMD_GETTIMEFULL 46
+#define BDOOR_CMD_STATELOGGER 47
+#define BDOOR_CMD_CHECKFORCEBIOSSETUP 48
+#define BDOOR_CMD_LAZYTIMEREMULATION 49
+#define BDOOR_CMD_BIOSBBS 50
+#define BDOOR_CMD_VASSERT 51
+#define BDOOR_CMD_ISGOSDARWIN 52
+#define BDOOR_CMD_DEBUGEVENT 53
+#define BDOOR_CMD_OSNOTMACOSXSERVER 54
+#define BDOOR_CMD_GETTIMEFULL_WITH_LAG 55
+#define BDOOR_CMD_ACPI_HOTPLUG_DEVICE 56
+#define BDOOR_CMD_ACPI_HOTPLUG_MEMORY 57
+#define BDOOR_CMD_ACPI_HOTPLUG_CBRET 58
+#define BDOOR_CMD_GET_HOST_VIDEO_MODES 59
+#define BDOOR_CMD_ACPI_HOTPLUG_CPU 60
+#define BDOOR_CMD_MAX 61
+
+/*
+ * IMPORTANT NOTE: When modifying the behavior of an existing backdoor command,
+ * you must adhere to the semantics expected by the oldest Tools who use that
+ * command. Specifically, do not alter the way in which the command modifies
+ * the registers. Otherwise backwards compatibility will suffer.
+ */
+
+/* High-bandwidth backdoor port. --hpreg */
+
+#define BDOORHB_PORT 0x5659
+
+#define BDOORHB_CMD_MESSAGE 0
+#define BDOORHB_CMD_VASSERT 1
+#define BDOORHB_CMD_MAX 2
+
+/*
+ * There is another backdoor which allows access to certain TSC-related
+ * values using otherwise illegal PMC indices when the pseudo_perfctr
+ * control flag is set.
+ */
+
+#define BDOOR_PMC_HW_TSC 0x10000
+#define BDOOR_PMC_REAL_NS 0x10001
+#define BDOOR_PMC_APPARENT_NS 0x10002
+
+#define IS_BDOOR_PMC(index) (((index) | 3) == 0x10003)
+#define BDOOR_CMD(ecx) ((ecx) & 0xffff)
+
+
+#ifdef VMM
+/*
+ *----------------------------------------------------------------------
+ *
+ * Backdoor_CmdRequiresFullyValidVCPU --
+ *
+ * A few backdoor commands require the full VCPU to be valid
+ * (including GDTR, IDTR, TR and LDTR). The rest get read/write
+ * access to GPRs and read access to Segment registers (selectors).
+ *
+ * Result:
+ * True iff VECX contains a command that require the full VCPU to
+ * be valid.
+ *
+ *----------------------------------------------------------------------
+ */
+static INLINE Bool
+Backdoor_CmdRequiresFullyValidVCPU(unsigned cmd)
+{
+ return cmd == BDOOR_CMD_RSVD0 ||
+ cmd == BDOOR_CMD_RSVD1 ||
+ cmd == BDOOR_CMD_RSVD2;
+}
+#endif
+
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1999 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * backdoor_types.h --
+ *
+ * Type definitions for backdoor interaction code.
+ */
+
+#ifndef _BACKDOOR_TYPES_H_
+#define _BACKDOOR_TYPES_H_
+
+#ifndef VM_I386
+#error The backdoor protocol is only supported on x86 architectures.
+#endif
+
+/*
+ * These #defines are intended for defining register structs as part of
+ * existing named unions. If the union should encapsulate the register
+ * (and nothing else), use DECLARE_REG_NAMED_STRUCT defined below.
+ */
+
+#define DECLARE_REG32_STRUCT \
+ struct { \
+ uint16 low; \
+ uint16 high; \
+ } halfs; \
+ uint32 word
+
+#define DECLARE_REG64_STRUCT \
+ DECLARE_REG32_STRUCT; \
+ struct { \
+ uint32 low; \
+ uint32 high; \
+ } words; \
+ uint64 quad
+
+#ifndef VM_X86_64
+#define DECLARE_REG_STRUCT DECLARE_REG32_STRUCT
+#else
+#define DECLARE_REG_STRUCT DECLARE_REG64_STRUCT
+#endif
+
+#define DECLARE_REG_NAMED_STRUCT(_r) \
+ union { DECLARE_REG_STRUCT; } _r
+
+/*
+ * Some of the registers are expressed by semantic name, because if they were
+ * expressed as register structs declared above, we could only address them
+ * by fixed size (half-word, word, quad, etc.) instead of by varying size
+ * (size_t, uintptr_t).
+ *
+ * To be cleaner, these registers are expressed ONLY by semantic name,
+ * rather than by a union of the semantic name and a register struct.
+ */
+typedef union {
+ struct {
+ DECLARE_REG_NAMED_STRUCT(ax);
+ size_t size; /* Register bx. */
+ DECLARE_REG_NAMED_STRUCT(cx);
+ DECLARE_REG_NAMED_STRUCT(dx);
+ DECLARE_REG_NAMED_STRUCT(si);
+ DECLARE_REG_NAMED_STRUCT(di);
+ } in;
+ struct {
+ DECLARE_REG_NAMED_STRUCT(ax);
+ DECLARE_REG_NAMED_STRUCT(bx);
+ DECLARE_REG_NAMED_STRUCT(cx);
+ DECLARE_REG_NAMED_STRUCT(dx);
+ DECLARE_REG_NAMED_STRUCT(si);
+ DECLARE_REG_NAMED_STRUCT(di);
+ } out;
+} Backdoor_proto;
+
+typedef union {
+ struct {
+ DECLARE_REG_NAMED_STRUCT(ax);
+ DECLARE_REG_NAMED_STRUCT(bx);
+ size_t size; /* Register cx. */
+ DECLARE_REG_NAMED_STRUCT(dx);
+ uintptr_t srcAddr; /* Register si. */
+ uintptr_t dstAddr; /* Register di. */
+ DECLARE_REG_NAMED_STRUCT(bp);
+ } in;
+ struct {
+ DECLARE_REG_NAMED_STRUCT(ax);
+ DECLARE_REG_NAMED_STRUCT(bx);
+ DECLARE_REG_NAMED_STRUCT(cx);
+ DECLARE_REG_NAMED_STRUCT(dx);
+ DECLARE_REG_NAMED_STRUCT(si);
+ DECLARE_REG_NAMED_STRUCT(di);
+ DECLARE_REG_NAMED_STRUCT(bp);
+ } out;
+} Backdoor_proto_hb;
+
+MY_ASSERTS(BACKDOOR_STRUCT_SIZES,
+ ASSERT_ON_COMPILE(sizeof(Backdoor_proto) == 6 * sizeof(uintptr_t));
+ ASSERT_ON_COMPILE(sizeof(Backdoor_proto_hb) == 7 * sizeof(uintptr_t));
+)
+
+#undef DECLARE_REG_STRUCT
+
+#endif /* _BACKDOOR_TYPES_H_ */
*/
INLINE void
-HgfsDebugPrintVnode(uint32 level, char *str, struct vnode *vnodep)
+HgfsDebugPrintVnode(uint32 level, char *str,
+ struct vnode *vnodep, Bool printFileName)
{
ASSERT(str);
ASSERT(vnodep);
DEBUG(level, " v_locality : %p\n", vnodep->v_locality);
DEBUG(level, " v_nbllock : %p\n", &vnodep->v_nbllock);
- if (HGFS_VP_TO_OFP(vnodep) && HGFS_VP_TO_FP(vnodep)) {
+ if (printFileName && HGFS_VP_TO_OFP(vnodep) && HGFS_VP_TO_FP(vnodep)) {
DEBUG(level, " filename : %s\n", HGFS_VP_TO_FILENAME(vnodep));
}
}
}
-/*
- * Gotta have Panic. Stolen from vmnix.
- * (Then stolen from hgfs/driver/linux/main.c and tweaked for Solaris)
- */
-
/*
* There is a problem in Solaris 9's header files when using the va_start
* and va_end macros, so we manually do what the preprocessor would have
* argument.
*/
#ifdef SOL9
-# define compat_va_list char *
# define compat_va_start(arg, fmt) arg = ((char *)__builtin_next_arg(fmt))
# define compat_va_end(arg)
#else
-# define compat_va_list va_list
# define compat_va_start(arg, fmt) va_start(arg, fmt)
# define compat_va_end(arg) va_end(arg)
#endif
-void
-Panic(const char *fmt, ...) // IN
+static void
+vLog(const char *fmt,
+ va_list args)
{
- compat_va_list args;
+#ifdef VM_DEBUG_LEV
char buffer[1024];
- volatile char *p = NULL;
- compat_va_start(args, fmt);
- vsprintf(buffer, fmt, args);
- compat_va_end(args);
+ /*
+ * We check this here to avoid unnecessarily manipulating buffer if we
+ * aren't even going to print the log.
+ */
+ if (VM_DEBUG_LOG & VM_DEBUG_LEV) {
+ vsprintf(buffer, fmt, args);
+ cmn_err(HGFS_DEBUG, "%s", buffer);
+ }
+#endif
+}
+
+
+/*
+ * For compatibility with existing code.
+ */
- cmn_err(HGFS_ERROR, "%s", buffer);
+void
+Log(const char *fmt, ...) // IN: format string, etc
+{
+ va_list args;
- /* force segfault */
- buffer[0] = *p;
- while (1) ; // avoid compiler warning
+ compat_va_start(args, fmt);
+ vLog(fmt, args);
+ compat_va_end(args);
}
/*
* For compatibility with existing code.
*/
+
void
-Log(const char *fmt, ...)
+Debug(const char *fmt, ...) // IN: format string, etc.
{
-#ifdef VM_DEBUG_LEV
- compat_va_list args;
- char buffer[1024];
+ va_list args;
- /*
- * We check this here to avoid unnecessarily manipulating buffer if we
- * aren't even going to print the log.
- */
- if (VM_DEBUG_LOG & VM_DEBUG_LEV) {
- compat_va_start(args, fmt);
- vsprintf(buffer, fmt, args);
- compat_va_end(args);
-
- cmn_err(HGFS_DEBUG, "%s", buffer);
- }
-#endif
+ compat_va_start(args, fmt);
+ vLog(fmt, args);
+ compat_va_end(args);
}
+
#undef compat_va_list
#undef compat_va_start
#undef compat_va_end
#ifndef __DEBUG_H_
#define __DEBUG_H_
+#ifdef _KERNEL
+
#include <sys/vnode.h>
#include <sys/vfs.h>
#include "hgfsSolaris.h"
#include "filesystem.h"
+#endif
/*
* Debugging
#define VM_DEBUG_LEV (VM_DEBUG_ALWAYS | VM_DEBUG_FAIL)
#endif
-
#ifdef VM_DEBUG_LEV
#define DEBUG(type, args...) \
((type & VM_DEBUG_LEV) ? (cmn_err(HGFS_DEBUG, args)) : 0)
/*
* Prototypes
*/
+
+#ifdef _KERNEL
+
INLINE void HgfsDebugPrintVfssw(char *str, struct vfssw *vfsswp);
INLINE void HgfsDebugPrintVfs(char *str, struct vfs *vfsp);
-INLINE void HgfsDebugPrintVnode(uint32 level, char *str, struct vnode *vnodep);
+INLINE void HgfsDebugPrintVnode(uint32 level, char *str,
+ struct vnode *vnodep, Bool printFileName);
INLINE void HgfsDebugPrintCred(char *str, struct cred *credp);
INLINE void HgfsDebugPrintMounta(char *str, struct mounta *mntp);
INLINE void HgfsDebugPrintVattr(const struct vattr *vap);
void HgfsDebugPrintReqList(DblLnkLst_Links *listAnchor);
void HgfsDebugPrintReq(const char *str, HgfsReq *req);
void HgfsDebugPrintReqPool(const char *str);
-void Panic(const char *fmt, ...);
-void Log(const char *fmt, ...);
+#endif
+
+void Log(const char *fmt, ...);
+void Debug(const char *fmt, ...);
#endif /* __DEBUG_H_ */
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2004 VMware, Inc. All rights reserved.
- *
- * The contents of this file are subject to the terms of the Common
- * Development and Distribution License (the "License") version 1.0
- * and no later version. You may not use this file except in
- * compliance with the License.
- *
- * You can obtain a copy of the License at
- * http://www.opensource.org/licenses/cddl1.php
- *
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- *********************************************************/
-
-
-/*
- * device.c --
- *
- * HGFS device driver for Solaris.
- *
- * Implements a device driver that creates a device in /dev that can be
- * interacted with through standard file IO syscalls. Implements open(),
- * close(), read(), write(), and poll().
- *
- * read() provides requests from the filesystem to the caller and is
- * synchronized with the HgfsSubmitRequest() function in the filesystem.
- * write() receives replies to those requests and provides them to the
- * filesystem by waking up processes waiting in HgfsSubmitRequest().
- *
- */
-
-#include "hgfsSolaris.h"
-#include "device.h"
-#include "request.h"
-#include "filesystem.h"
-
-/*
- * Local variables
- */
-static Bool hgfsAttached; /* Flag to tell whether device is attached */
-
-/*
- * Function Prototypes
- */
-static int HgfsSendRequestToUser(HgfsReq *req, uio_t *uiop);
-static INLINE int HgfsGetReplyHeaderFromUser(HgfsReplyHeader *reply, uio_t *uiop);
-static int HgfsGetReplyPacketFromUser(HgfsReq *req, ssize_t offset, uio_t *uiop);
-
-/* Local utility functions */
-static INLINE HgfsSuperInfo *HgfsDevToSuperInfo(dev_t dev);
-static INLINE HgfsSuperInfo *HgfsDevinfoToSuperInfo(dev_info_t *dip);
-static INLINE HgfsReq *HgfsReplyToRequest(HgfsReplyHeader *reply);
-
-/*
- * Driver "configuration" functions
- */
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDevGetinfo --
- *
- * The entry point for getinfo(9E). Carries out commands requested by the
- * kernel that either return the device information structure or the
- * instance number.
- *
- * Results:
- * Returns DDI_SUCCESS on success and DDI_FAILURE on failure.
- * When infocmd is DDI_INFO_DEVT2DEVINFO, a pointer to the device's
- * information structure is returned in result.
- * When infocmd is DDI_INFO_DEVT2INSTANCE, the device's instance number is
- * returned in result.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsDevGetinfo(dev_info_t *dip, // IN: Device info for this device
- ddi_info_cmd_t infocmd, // IN: Command to carry out
- void *arg, // IN: Device number (as dev_t) for this device
- void **result) // OUT: Result of command
-{
- minor_t instance; /* getminor() returns minor_t */
- HgfsSuperInfo *sip;
-
- DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevGetinfo().\n");
-
- ASSERT(arg);
- ASSERT(result);
-
- /* These indicate a kernel error */
- if ((!arg) || (!result)) {
- cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevGetinfo().\n");
- return EINVAL;
- }
-
-
- switch (infocmd) {
-
- /* This wants a dev_info_t from the dev_t: get it from the superinfo */
- case DDI_INFO_DEVT2DEVINFO:
- sip = HgfsDevToSuperInfo((dev_t)arg);
- if (!sip) {
- goto error;
- }
-
- *result = sip->dip;
- DEBUG(VM_DEBUG_DEVDONE, "HgfsDevGetinfo() done.\n");
- return DDI_SUCCESS;
-
- /*
- * This wants the instance number, which is the minor number since we set
- * it to be that in HgfsDevAttach()'s call to ddi_create_minor_node().
- */
- case DDI_INFO_DEVT2INSTANCE:
- instance = getminor((dev_t)arg);
- *result = (void *)((uintptr_t)instance);
- DEBUG(VM_DEBUG_DEVDONE, "HgfsDevGetinfo() done.\n");
- return DDI_SUCCESS;
-
- /* Unrecognized command */
- default:
- goto error;
- }
-
-error:
- *result = NULL;
- DEBUG(VM_DEBUG_FAIL, "HgfsDevGetinfo() done (FAIL).\n");
- return DDI_FAILURE;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDevAttach --
- *
- * The entry point for attach(9E) that is invoked when the driver is loaded
- * into the kernel. This allocates and initializes a super info structure
- * and creates the device entry ('minor node') in the file system.
- * XXX: do we need to handle suspend and resume commands also?
- *
- * Results:
- * Returns zero on success, and an appropriate error code on failure.
- *
- * Side effects:
- * The device entry appears in the filesystem (/devices).
- * The hgfsAttaches flag is set.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsDevAttach(dev_info_t *dip, // IN: Device info for this device
- ddi_attach_cmd_t cmd) // IN: Command to carry out
-{
- int instance; /* ddi_get_instance() returns int */
- HgfsSuperInfo *sip;
-
- DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevAttach().\n");
-
- ASSERT(dip);
-
- /* This indicates a kernel error */
- if (!dip) {
- cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevAttach().\n");
- return EINVAL;
- }
-
- if (hgfsAttached) {
- cmn_err(HGFS_ERROR, "Device already attached.\n");
- return EIO;
- }
-
- switch (cmd) {
-
- /* Attach this device */
- case DDI_ATTACH:
- /* hgfsInstance is used by the filesystem side to get superinfo pointer */
- instance = hgfsInstance = ddi_get_instance(dip);
-
- /*
- * Here we allocate state for this instance of the driver (see comment
- * in _init() for more information on Solaris' DDI Soft State interface).
- *
- * Once we have the pointer to the state we just allocated, we'll
- * initialize its fields. In particular:
- * - a pointer to the dev_info_t is stored because HgfsGetInfo() will
- * need it.
- * - clear the flag indicating whether the device is open.
- * - the request list, along with its mutex and condition variable, are
- * initialized.
- */
- if (ddi_soft_state_zalloc(superInfoHead, instance) != DDI_SUCCESS) {
- cmn_err(HGFS_ERROR,
- "could not zalloc state for this instance (%d).\n", instance);
- goto error;
- }
-
- sip = (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, instance);
- if (!sip) {
- goto error_free;
- }
-
- sip->dip = dip;
- sip->devOpen = 0;
-
- HgfsInitRequestList(sip);
-
- /*
- * Create the minor node (the /devices entry)
- */
- if (ddi_create_minor_node(dip, /* device info ptr */
- HGFS_DEV_NAME, /* name of device */
- S_IFCHR, /* type of device (character) */
- instance, /* minor number */
- DDI_PSEUDO, /* pseudo device b/c not backed
- by physical device */
- 0 /* flag: not a clone device */
- ) != DDI_SUCCESS) {
-
- cmn_err(HGFS_ERROR, "could not create minor node (/devices entry).\n");
- goto error_free;
- }
-
- /* Report presence of device to system log (syslog/dmesg) */
- ddi_report_dev(dip);
-
- /*
- * We only want one instance of this driver to ever be running, so set a
- * flag stating the device is attached
- */
- hgfsAttached = TRUE;
-
- DEBUG(VM_DEBUG_DEVDONE, "HgfsDevAttach() done.\n");
- return DDI_SUCCESS;
-
- /* Unsupported commands: DDI_PM_RESUME and DDI_RESUME */
- default:
- goto error;
- }
-
-error_free:
- ddi_soft_state_free(sip, instance);
-error:
- DEBUG(VM_DEBUG_FAIL, "HgfsDevAttach() done (FAIL).\n");
- return DDI_FAILURE;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDevDetach --
- *
- * The detach(9E) entry point that is invoked when the driver is
- * unloaded from the kernel. This cleans up all state allocated in
- * HgfsDevAttach() and removes the device entry ('minor node').
- *
- * Results:
- * Returns zero on success, and an appropriate error code on failure.
- *
- * Side effects:
- * The super info structure for this driver is deallocated.
- * The device entry (/devices) is no longer valid.
- * The hgfsAttached flag is cleared.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsDevDetach(dev_info_t *dip, // IN: Device info for this device
- ddi_detach_cmd_t cmd) // IN: Command to carry out
-{
- int instance;
- HgfsSuperInfo *sip;
-
- DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevDetach().\n");
-
- ASSERT(dip);
-
- /* This indicates a kernel error */
- if (!dip) {
- cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevDetach().\n");
- return EINVAL;
- }
-
- switch(cmd) {
-
- /* Detach this device */
- case DDI_DETACH:
- /*
- * Clean up the state allocated for this instance of the driver:
- * - Get a pointer to the super info structure,
- * - Remove the device entry (minor node) from the system,
- * - Free the super info structure.
- */
- instance = ddi_get_instance(dip);
- sip = (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, instance);
- if (!sip) {
- cmn_err(HGFS_ERROR, "could not find HgfsSuperInfo on detach.\n");
- goto error;
- }
-
- ddi_remove_minor_node(dip, NULL); /* NULL means remove all for this dev_info_t */
- ddi_soft_state_free(superInfoHead, instance);
-
- /* Indicate driver is no longer attached */
- hgfsAttached = 0;
-
- DEBUG(VM_DEBUG_DEVDONE, "HgfsDevDetach() done.\n");
- return DDI_SUCCESS;
-
- /* Unsupported commands: DDI_PM_SUSPEND and DDI_SUSPEND */
- default:
- goto error;
- }
-
-error:
- DEBUG(VM_DEBUG_FAIL, "HgfsDevDetach() done (FAIL).\n");
- return DDI_FAILURE;
-}
-
-
-
-/*
- * Device functions
- */
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDevOpen --
- * The entry point for open(9E) that is invoked when a user process calls
- * open(2) on the device. This checks that the specified device and open
- * type are valid.
- *
- * Results:
- * Returns zero on success, and an appropriate error code on failure.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsDevOpen(dev_t *devp, // IN: Pointer to device number
- int flag, // IN: Indicates open mode
- // (FREAD, FWRITE, FEXCL, FNDELAY)
- int otyp, // IN: Type of open (OTYP_CHR, OTYP_BLK, OTYP_LYR)
- cred_t *credp) // IN: Pointer to credentials of caller
-{
- HgfsSuperInfo *sip;
-
- DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevOpen().\n");
-
- ASSERT(devp);
- ASSERT(credp);
-
- /* These indicate a kernel error */
- if ((!devp) || (!credp)) {
- cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevOpen().\n");
- return EINVAL;
- }
-
- /*
- * Here we do a few checks to ensure that this open is valid. First, our
- * device is a character device so we ensure that the type of open
- * indicates this. Next we ensure that the caller is root. Finally, we
- * make sure that the device number specified is valid by attempting to
- * retrieve its state that was allocated in HgfsDevDetach().
- */
-
- if (otyp != OTYP_CHR) {
- DEBUG(VM_DEBUG_FAIL, "HgfsDevOpen() done (FAIL).\n");
- return EINVAL;
- }
-
- if (!HgfsSuser(credp)) {
- DEBUG(VM_DEBUG_FAIL, "HgfsDevOpen() done (FAIL).\n");
- return EINVAL;
- }
-
- sip = HgfsDevToSuperInfo(*devp);
- if (!sip) {
- DEBUG(VM_DEBUG_FAIL, "HgfsDevOpen() done (FAIL).\n");
- return ENXIO;
- }
-
- /* Make sure device isn't opened more than once */
- if (sip->devOpen) {
- return ENXIO;
- }
-
- sip->devOpen = TRUE;
-
- DEBUG(VM_DEBUG_DEVDONE, "HgfsDevOpen() done.\n");
- return 0;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDevClose --
- * The entry point for close(9E), which is invoked when a user process
- * calls close(2) on the device. This ensures that the specified device
- * number is valid (by trying to find its state structure).
- *
- * Results:
- * Returns zero on success, and an appropriate error code on failure.
- *
- * Side effects:
- * All pending requests are cancelled.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsDevClose(dev_t dev, // IN: Device number
- int flag, // IN: Mode opened with (see HgfsOpen() comment)
- int otyp, // IN: Type of open (see HgfsOpen() comment)
- cred_t *credp) // IN: Pointer to credentials of caller
-{
- HgfsSuperInfo *sip;
-
- DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevClose().\n");
-
- ASSERT(credp);
-
- /* This indicates a kernel error */
- if (!credp) {
- cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevClose().\n");
- return EINVAL;
- }
-
- /*
- * We only allow root to open and close the device.
- */
- if (!HgfsSuser(credp)) {
- return EINVAL;
- }
-
-
- /* Just make sure this instance is valid, state is freed in HgfsDevDetach() */
- sip = HgfsDevToSuperInfo(dev);
- if (!sip) {
- DEBUG(VM_DEBUG_FAIL, "HgfsDevClose() done (FAIL).\n");
- return ENXIO;
- }
-
- /*
- * This will signify to the filesystem that the device half is no longer
- * present.
- */
- sip->devOpen = 0;
-
- /*
- * Each submitted request must be told an error has occurred.
- */
- HgfsCancelAllRequests(sip);
-
-
- DEBUG(VM_DEBUG_DEVDONE, "HgfsDevClose() done.\n");
- return 0;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDevRead --
- *
- * Entry point for read(9E) that is invoked when a user process calls
- * read(2) on the device.
- *
- * This checks the pending request list for any outstanding requests. If
- * the list is empty, this blocks on a condition variable that is signaled
- * each time a request is enqueued. The request is removed from the list
- * and copied to the user's buffer.
- *
- * Results:
- * Returns zero on success, an appropriate error code on failure.
- *
- * Side effects:
- * Blocks if the list is empty.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsDevRead(dev_t dev, // IN: Device number
- uio_t *uiop, // IN: Ptr to structure defining read request
- cred_t *credp) // IN: Ptr to caller's credentials
-{
- int ret;
- HgfsSuperInfo *sip;
- HgfsReq *nextReq = NULL;
-
- DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevRead().\n");
-
- ASSERT(uiop);
- ASSERT(credp);
-
- /* These indicate a kernel error */
- if ((!uiop) || (!credp)) {
- cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevRead().\n");
- return EINVAL;
- }
-
- sip = HgfsDevToSuperInfo(dev);
- if (!sip) {
- DEBUG(VM_DEBUG_FAIL, "HgfsDevRead() done (FAIL).\n");
- return ENXIO;
- }
-
- /*
- * We need to check the request list to see if there is anything to read.
- * If not, wait on the list's condition variable so we will be
- * cv_signal()'ed when a request is placed onto the request list (by the
- * filesystem half). Once a request is there we can remove it from
- * the list and copy it to user space.
- */
- mutex_enter(&sip->reqMutex);
-
- for (;;) {
- /*
- * The cv_wait_sig(9F) man page says the cv_wait*() functions can return
- * prematurely in certain situations, typically when job control or
- * debugging is used, so it is required that we loop around cv_wait_sig().
- */
- while (HgfsListIsEmpty(&sip->reqList)) {
- DEBUG(VM_DEBUG_COMM, "HgfsDevRead: blocking ...\n");
- if (cv_wait_sig(&sip->reqCondVar, &sip->reqMutex) == 0) {
- /*
- * We received a system signal (e.g., SIGKILL) while waiting for the
- * cv_signal(). Release mutex and return appropriate error code.
- */
- mutex_exit(&sip->reqMutex);
- DEBUG(VM_DEBUG_FAIL,
- "cv_wait_sig() interrupted by signal in HgfsDevRead().\n");
- return EINTR;
- }
- }
-
- /*
- * We hold the lock so the next request is guaranteed to be there. If
- * the next request is still in the submitted state then we process it;
- * otherwise the request must be in the abandoned state and we destroy it
- * and wait for the next one.
- */
- nextReq = HgfsDequeueRequest(sip);
- ASSERT(nextReq);
- if (HgfsReqGetState(nextReq) == HGFS_REQ_SUBMITTED) {
- break;
- }
-
- ASSERT(HgfsReqGetState(nextReq) == HGFS_REQ_ABANDONED);
- HgfsDestroyReq(sip, nextReq);
- }
-
- DEBUG(VM_DEBUG_LIST, "HgfsDevRead received request for ID %d", nextReq->id);
- mutex_exit(&sip->reqMutex);
-
- /*
- * Filesystem ensures that requests are small enough to fit in a packet sent
- * through the backdoor.
- */
- ret = HgfsSendRequestToUser(nextReq, uiop);
- /*
- * If we couldn't copy the request to guestd, set the request's state to
- * error and wake up the client. The filesystem will have to clean up.
- */
- if (ret) {
- DEBUG(VM_DEBUG_FAIL, "HgfsDevRead: could not copy request to user (FAIL).\n");
- HgfsReqSetState(nextReq, HGFS_REQ_ERROR);
- HgfsWakeWaitingClient(sip, nextReq);
- }
-
- DEBUG(VM_DEBUG_INFO, "resid=%ld\n", uiop->uio_resid);
- DEBUG(VM_DEBUG_DEVDONE, "HgfsDevRead() done.\n");
- return ret;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDevWrite --
- *
- * Entry point for write(9E), which is invoked when a user process calls
- * write(2) on the device.
- *
- * This copies in a reply header, finds the associated request, then copies
- * the reply packet into the request packet. It handles cleaning up
- * requests that have been abandoned.
- *
- * Results:
- * Returns zero on success, an appropriate error code on failure.
- *
- * Side effects:
- * The state of the request corresponding to this reply is modified.
- * The process waiting for this reply is woken up (if it is still waiting).
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsDevWrite(dev_t dev, // IN: Device number
- uio_t *uiop, // IN: Ptr to structure defining write request
- cred_t *credp) // IN: Ptr to caller's credentials
-{
- int ret;
- uint32_t writeSize;
- HgfsSuperInfo *sip;
- HgfsReq *request;
- HgfsReplyHeader reply;
-
- DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevWrite().\n");
-
- ASSERT(uiop);
- ASSERT(credp);
-
- /* These indicate a kernel error */
- if (!uiop || !credp) {
- cmn_err(HGFS_ERROR, "NULL input from kernel in HgfsDevWrite().\n");
- return EINVAL;
- }
-
- sip = HgfsDevToSuperInfo(dev);
- if (!sip) {
- DEBUG(VM_DEBUG_FAIL, "HgfsDevWrite(): couldn't get superinfo (FAIL)\n");
- return ENXIO;
- }
-
- /* We need at least the reply structure to do anything useful. */
- if (uiop->uio_resid < sizeof reply) {
- DEBUG(VM_DEBUG_FAIL, "HgfsDevWrite(): too little data written (FAIL).\n");
- return ERANGE;
- }
-
- /*
- * If this fails there is a problem with guestd or the filesystem isn't
- * splitting requests properly. This also allows writeSize to be a uint32
- * despite uiop->uio_resid being a ssize_t (which can be a long).
- */
- if (uiop->uio_resid > HGFS_PACKET_MAX) {
- return EINVAL;
- }
-
- /* Needed to set packet size upon successful receipt of packet. */
- writeSize = uiop->uio_resid;
-
- /*
- * Copy in just the reply header that will tell us what request this is
- * for and what the status of the reply is.
- */
- ret = HgfsGetReplyHeaderFromUser(&reply, uiop);
- if (ret) {
- DEBUG(VM_DEBUG_FAIL,
- "HgfsDevWrite(): couldn't copy header from user (FAIL).\n");
- return EIO;
- }
-
- DEBUG(VM_DEBUG_COMM, "HgfsDevWrite: Reply for %d with status %d.\n",
- reply.id, reply.status);
-
- /*
- * Here we need to determine which request this reply is for, then determine
- * if that requester is still waiting. If so we copy the contents of the
- * reply into the request's packet and wake up the client; otherwise we
- * destroy the abandoned request and return an error.
- */
- request = HgfsReplyToRequest(&reply);
- if (!request) {
- DEBUG(VM_DEBUG_FAIL, "HgfsDevWrite(): invalid id in reply (FAIL).\n");
- return EINVAL;
- }
-
- /*
- * Acquiring this mutex makes the checking of whether the request has been
- * ABANDONED and setting the request to COMPLETED or ERROR atomic. It is
- * also acquired in HgfsSubmitRequest().
- */
- mutex_enter(&sip->reqMutex);
-
- if (HgfsReqGetState(request) == HGFS_REQ_ABANDONED) {
- /* The requesting process is gone so we don't need to wake it up */
- HgfsDestroyReq(sip, request);
- mutex_exit(&sip->reqMutex);
- DEBUG(VM_DEBUG_FAIL, "HgfsDevWrite(): request was abandoned (FAIL).\n");
- return EINTR; /* XXX: Does guestd need to know this? */
- }
-
- /*
- * Now that we know which request this reply is for, zero out its packet and
- * copy in the reply header.
- */
- bzero(request->packet, sizeof request->packet);
- memcpy(request->packet, &reply, sizeof reply);
-
- /* Copy rest of reply into request packet after the header */
- ret = HgfsGetReplyPacketFromUser(request, sizeof reply, uiop);
- if (ret < 0) {
- /*
- * If there was an error while copying the reply packet, we set the state
- * to error and return an error code (in case guestd cares).
- */
- HgfsReqSetState(request, HGFS_REQ_ERROR);
- ret = EIO;
- } else {
- /* ... otherwise we set the packet size and set the state to completed. */
- request->packetSize = writeSize - uiop->uio_resid;
- HgfsReqSetState(request, HGFS_REQ_COMPLETED);
- ret = 0;
- }
-
- /*
- * Wake up the client waiting on the request (Note we don't call
- * HgfsWakeWaitingClient() since we already hold the lock.)
- */
- cv_signal(&request->condVar);
- mutex_exit(&sip->reqMutex);
-
- DEBUG(VM_DEBUG_DEVDONE, "HgfsDevWrite() done.\n");
- return ret;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDevChpoll --
- *
- * Entry point for chpoll(9E), which is invoked (potentially more than
- * once) when either poll(2) or select(3C) is called by a user process.
- * This examines the state of the device and returns information indicating
- * which operations are ready to be performed.
- *
- * Results:
- * Returns 0 on success, or an error code if an error occurs.
- * If any of the events polled have occurred, this is specified by filling
- * in reventsp with the appropriate bits.
- * If none of the events polled have occurred, reventsp is cleared. phpp
- * is also set to point to a pollhead structure if no other file
- * descriptors polled have had events.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsDevChpoll(dev_t dev, // IN: Device number
- short int events, // IN: Events that could occur
- // (see man -s 9E chpoll for all
- // events)
- int anyyet, // IN: Flag (set if other fds have events pending)
- short int *reventsp, // OUT: Ptr to bitmask of events satisfied
- struct pollhead **phpp) // OUT: Ptr to a pollhead structure
-{
- short revents;
- HgfsSuperInfo *sip;
-
- DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevChPoll(). (events=%x)\n", events);
-
- ASSERT(reventsp);
- ASSERT(phpp);
-
- /* These indicate a kernel error */
- if ((!reventsp) || (!phpp)) {
- cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevChpoll().\n");
- return EINVAL;
- }
-
- sip = HgfsDevToSuperInfo(dev);
- if (!sip) {
- DEBUG(VM_DEBUG_FAIL, "HgfsDevChPoll() done (FAIL).\n");
- return ENXIO;
- }
-
- /*
- * This comment is for reference, can remove in future:
- *
- * Algorithm to implement (chpoll(9E) and p195 DDK docs):
- *
- * if (events are satisfied now) {
- * *reventsp = (mask of satisfied events);
- * } else {
- * *reventsp = 0;
- * if (!anyyet) {
- * *phpp = &(local pollhead structure);
- * }
- * }
- * return 0;
- *
- * The pollhead structure should not be referenced by the driver.
- */
-
- revents = 0;
- /* Clear flag indicating the need to call pollwakeup() on write() */
- sip->pollwakeupOnWrite = FALSE;
-
- /*
- * Caller asked to read: if the request list is not empty then they can
- * read without blocking.
- */
- if (events & HGFS_POLL_READ) {
- mutex_enter(&sip->reqMutex);
-
- if ( !HgfsListIsEmpty(&sip->reqList) ) {
- /* Set just those bits the caller asked for */
- revents |= (events & HGFS_POLL_READ);
- }
- DEBUG(VM_DEBUG_CHPOLL, "HgfsChpoll(): HGFS_POLL_READ, revents=%d", revents);
-
- mutex_exit(&sip->reqMutex);
- }
-
- /*
- * Caller asked to write: they can always write.
- */
- if (events & HGFS_POLL_WRITE) {
- revents |= (events & HGFS_POLL_WRITE);
- DEBUG(VM_DEBUG_CHPOLL, "HgfsChpoll(): HGFS_POLL_WRITE, revent=%d\n", revents);
- }
-
- /*
- * No events have occurred
- */
- if (revents == 0) {
- DEBUG(VM_DEBUG_CHPOLL, "HgfsChpoll(): no events\n");
- *reventsp = 0;
- if (anyyet == 0) {
- /*
- * No other file descriptors have had events, so we set the pollhead
- * structure and a flag indicating the need to call pollwakeup() on
- * a successful completion of a write().
- */
- *phpp = &sip->hgfsPollhead;
- DEBUG(VM_DEBUG_CHPOLL, "HgfsChpoll(): setting pollwakeupOnWrite.\n");
- sip->pollwakeupOnWrite = TRUE;
- }
- }
-
- *reventsp = revents;
-
- DEBUG(VM_DEBUG_DEVDONE, "HgfsDevChPoll() done. (revents=%x)\n", revents);
- return 0;
-}
-
-
-/*
- * Functions to copy to and from user space.
- */
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsSendRequestToUser --
- *
- * Sends a requst to the user.
- *
- * Results:
- * Returns zero on success, and non-zero on error.
- *
- * Side effects:
- * The uio_resid field of uiop will be decremented by the number of bytes
- * read.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-HgfsSendRequestToUser(HgfsReq *req, // IN: Request to send
- uio_t *uiop) // IN: User's read request
-{
- int ret;
-
- DEBUG(VM_DEBUG_DEVENTRY, "HgfsSendRequestToUser().\n");
-
- ASSERT(req);
- ASSERT(uiop);
-
- /*
- * If the buffer provided by guestd is not large enough to hold the largest
- * packet, then either the filesystem or guestd is doing something wrong.
- * (uio_resid is the number of bytes we can write to the user's buffer.)
- */
- ASSERT(req->packetSize <= HGFS_PACKET_MAX);
- ASSERT(uiop->uio_resid >= req->packetSize);
-
- DEBUG(VM_DEBUG_INFO, "HgfsSendRequestToUser: uiomove(%p, %d, UIO_READ, %p)\n",
- req->packet, req->packetSize, uiop);
-
- /*
- * uiomove(9F) will handle copying of data from kernel buffer to user buffer
- * for us. It understands the format of the uio_t that describes the
- * user's read request and verifies user address is valid. It returns zero
- * on success and an error code otherwise.
- */
- ret = uiomove(req->packet, // Kernel src address
- req->packetSize, // Number of bytes to transfer
- UIO_READ, // rwflag: READ
- uiop); // Pointer to user's read request
-
- DEBUG(VM_DEBUG_DEVDONE,
- "HgfsSendRequestToUser() sent %d bytes in request (ret=%d).\n",
- req->packetSize, ret);
-
- return ret;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsGetReplyHeaderFromUser --
- *
- * Copies the reply header from the user into the provided reply
- *
- * Results:
- * Returns zero on success, non-zero on error.
- *
- * Side effects:
- * uiop's uio_resid is decremented by the number of bytes that were copied.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE int
-HgfsGetReplyHeaderFromUser(HgfsReplyHeader *header, // OUT: Header to copy into
- uio_t *uiop) // IN: User's write request
-{
- ASSERT(header);
- ASSERT(uiop);
-
- DEBUG(VM_DEBUG_COMM,
- "HgfsGetReplyHeaderFromUser(): writing %"FMTSZ"u bytes"
- " into request packet's header.\n", sizeof *header);
-
- /* Only copy in the header, uio_resid decremented for us by uiomove() */
- return uiomove(header, sizeof *header, UIO_WRITE, uiop);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsGetReplyPacketFromUser --
- *
- * Copies the rest of the user's reply into the offset of the request's
- * packet.
- *
- * Results:
- * Returns zero on success, non-zero on error.
- *
- * Side effects:
- * None.
- *
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-HgfsGetReplyPacketFromUser(HgfsReq *req, // IN/OUT: Request to copy into
- ssize_t offset, // IN: Offset in packet to
- // start copying at
- uio_t *uiop) // IN: User's write request
-{
- ASSERT(req);
- ASSERT(uiop);
-
-
- /*
- * If guestd has more to write than the max room left in the packet then it
- * is doing something wrong.
- */
- ASSERT(uiop->uio_resid <= HGFS_PACKET_MAX - offset);
-
- DEBUG(VM_DEBUG_COMM,
- "HgfsGetReplyPacketFromUser(): writing %ld bytes into request packet.\n",
- uiop->uio_resid);
-
- /* Write the reply into the specified buffer */
- return uiomove(req->packet + offset, uiop->uio_resid, UIO_WRITE, uiop);
-}
-
-
-
-/*
- * Utility functions
- */
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDevToSuperInfo --
- *
- * Gets a pointer to the super info structure from a device number (dev_t).
- *
- * Results:
- * Returns a pointer to the super info struct, or NULL if it cannot be
- * found.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE HgfsSuperInfo *
-HgfsDevToSuperInfo(dev_t dev) // IN: Device number
-{
- minor_t instance;
-
- DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevToSuperInfo().\n");
-
- instance = getminor(dev);
-
- DEBUG(VM_DEBUG_RARE,
- "HgfsDevToSuperInfo: getting ptr to instance %d's state.\n", instance);
-
- return (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, (int)instance);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDevinfoToSuperInfo --
- *
- * Gets a pointer to the super info from a device information struct.
- * XXX: currently unused since HgfsDevDetach needs value of instance
- * itself.
- *
- * Results:
- * Returns a pointer to the super info structure, or NULL if it cannot be
- * found.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE HgfsSuperInfo *
-HgfsDevinfoToSuperInfo(dev_info_t *dip) // IN: Device information structure
-{
- int instance;
-
- ASSERT(dip);
-
- instance = ddi_get_instance(dip);
-
- DEBUG(VM_DEBUG_RARE,
- "HgfsDevinfoToSuperInfo: getting ptr to instance %d's state.\n", instance);
-
- return (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, instance);
-}
-
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsReplyToRequest --
- *
- * Determines the request that corresponds with the provided reply.
- *
- * Results:
- * Returns a pointer to the request, or NULL if it cannot be located.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE HgfsReq *
-HgfsReplyToRequest(HgfsReplyHeader *reply) // IN: Reply to find request of
-{
- ASSERT(reply);
-
- if (reply->id > HGFS_MAX_OUTSTANDING_REQS) {
- return NULL;
- }
-
- /*
- * When this function is called, the request should only be in the
- * SUBMITTED, ABANDONED, or ERROR states.
- */
- ASSERT((HgfsReqGetState(&requestPool[reply->id]) == HGFS_REQ_SUBMITTED) ||
- (HgfsReqGetState(&requestPool[reply->id]) == HGFS_REQ_ABANDONED) ||
- (HgfsReqGetState(&requestPool[reply->id]) == HGFS_REQ_ERROR));
-
- DEBUG(VM_DEBUG_INFO, "HgfsRequestToReply: reply for request id %d\n", reply->id);
-
- return &requestPool[reply->id];
-}
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2004 VMware, Inc. All rights reserved.
- *
- * The contents of this file are subject to the terms of the Common
- * Development and Distribution License (the "License") version 1.0
- * and no later version. You may not use this file except in
- * compliance with the License.
- *
- * You can obtain a copy of the License at
- * http://www.opensource.org/licenses/cddl1.php
- *
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- *********************************************************/
-
-
-/*
- * device.h --
- *
- * Definitions and includes for device driver code.
- *
- */
-
-
-#ifndef __DEVICE_H_
-#define __DEVICE_H_
-
-#include <sys/open.h> /* OTYP_CHR */
-#include <sys/stat.h> /* S_IFCHR */
-#include <sys/ddi.h> /* Device Driver Interface */
-#include <sys/sunddi.h> /* Sun DDI defines (DDI_PSEUDO) */
-#include <sys/ksynch.h> /* mutex and condition variables */
-
-#include "debug.h"
-
-/*
- * Macros
- */
-
-/* Flags for chpoll(): we don't distinguish between these priorities of data */
-#define HGFS_POLL_READ (POLLIN | POLLRDNORM | POLLRDBAND)
-#define HGFS_POLL_WRITE (POLLOUT | POLLWRNORM | POLLWRBAND)
-
-
-#endif /* __DEVICE_H_ */
*/
#include <sys/param.h> /* MAXNAMELEN */
+#include <sys/file.h> /* FKIOCTL */
#include "hgfsSolaris.h"
#include "hgfsState.h"
#endif
#endif
+#if HGFS_VFS_VERSION > 2
+static vfsops_t *hgfsVfsOpsP;
+#endif
+
+/*
+ * Fileystem type number given to us upon initialization.
+ */
+static int hgfsType;
+
#if HGFS_VFS_VERSION == 2
/*
int ret;
/* Construct the VFS operations array to give to vfs_setfsops() */
- fs_operation_def_t vfsOpsArr[] = {
+ static fs_operation_def_t vfsOpsArr[] = {
HGFS_VOP(VFSNAME_MOUNT, vfs_mount, HgfsMount),
HGFS_VOP(VFSNAME_UNMOUNT, vfs_unmount, HgfsUnmount),
HGFS_VOP(VFSNAME_ROOT, vfs_root, HgfsRoot),
DEBUG(VM_DEBUG_ENTRY, "HgfsInit: fstype=%d, name=\"%s\"\n", fstype, name);
- /* Set our filesystem type. */
- hgfsType = fstype;
-
/* Assign VFS operations to our filesystem. */
- ret = vfs_setfsops(hgfsType, vfsOpsArr, NULL);
+ ret = vfs_setfsops(fstype, vfsOpsArr, &hgfsVfsOpsP);
if (ret) {
DEBUG(VM_DEBUG_FAIL, "HgfsInit: vfs_setfsops returned %d\n", ret);
return ret;
}
+ ret = HgfsMakeVnodeOps();
+ if (ret) {
+ DEBUG(VM_DEBUG_FAIL, "HgfsInit: could not register HGFS Vnode Ops.\n");
+ vfs_freevfsops_by_type(fstype);
+ ret = EIO;
+ return ret;
+ }
+
+ /* Set our filesystem type. */
+ hgfsType = fstype;
DEBUG(VM_DEBUG_DONE, "HgfsInit: done. (fstype=%d)\n", hgfsType);
return 0;
#endif
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFreeVfsOps --
+ *
+ * Free VFS Ops created when we initialized the filesystem.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Resets hgfsVfsOpsP back to NULL.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+
+void
+HgfsFreeVfsOps(void)
+{
+#if HGFS_VFS_VERSION > 2
+ if (hgfsVfsOpsP) {
+ vfs_freevfsops_by_type(hgfsType);
+ }
+#endif
+}
+
/*
* VFS Entry Points
DEBUG(VM_DEBUG_ENTRY, "HgfsMount().\n");
//HgfsDebugPrintVfs("HgfsMount", vfsp);
- //HgfsDebugPrintVnode(VM_DEBUG_STRUCT, "HgfsMount", vnodep);
+ //HgfsDebugPrintVnode(VM_DEBUG_STRUCT, "HgfsMount", vnodep, FALSE);
//HgfsDebugPrintMounta("HgfsMount", mntp);
//HgfsDebugPrintCred("HgfsMount", credp);
- /*
- * Initial sanity checks to ensure that:
- * - device side has allocated our superinfo struct (see HgfsDevAttach())
- * - the device has been sucecssfully opened
- * - caller is root
- * - data provided by caller is the expected size
- *
- * Note that this is the one place in the filesystem that we call
- * ddi_get_soft_state() directly to get the superinfo pointer. All other
- * places use the HgfsGetSuperInfo() wrapper which only returns the
- * superinfo if the filesystem is in fact mounted.
- */
- sip = (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, hgfsInstance);
- if (!sip) {
- DEBUG(VM_DEBUG_FAIL, "HgfsMount: superinfo has not been allocated/set\n");
- return ENXIO;
- }
-
- if (!sip->devOpen) {
- DEBUG(VM_DEBUG_FAIL, "HgfsMount: device has not been opened\n");
- return ENXIO;
- }
-
if (!HgfsSuser(credp)) {
return EPERM;
}
if (mntp->datalen != sizeof *mountData) {
+ DEBUG(VM_DEBUG_FAIL, "HgfsMount: bad data size (%lu vs %lu).\n",
+ (unsigned long) mntp->datalen,
+ (unsigned long) sizeof *mountData);
return EINVAL;
}
- /*
- * If mount data is in kernel space, just cast pointer; otherwise we need
- * to safely copy it from user space.
- */
- if (mntp->flags & MS_SYSSPACE) {
- mountData = (HgfsMountData *)mntp->dataptr;
- DEBUG(VM_DEBUG_LOAD, "HgfsMount(): mount data was in kernel space.\n");
- } else {
- mountData = (HgfsMountData *)kmem_zalloc(sizeof *mountData, HGFS_ALLOC_FLAG);
-# if HGFS_ALLOC_FLAG != KM_SLEEP
- /* This check is not needed if HGFS_ALLOC_FLAG == KM_SLEEP */
- if (!mountData) {
- return ENOMEM;
- }
-# endif
-
- if (ddi_copyin(mntp->dataptr, mountData,
- sizeof *mountData, HGFS_COPYIN_FLAGS) == -1) {
- DEBUG(VM_DEBUG_FAIL, "HgfsMount: couldn't copy in mount data.\n");
- ret = EFAULT;
- goto out;
- }
+ mountData = kmem_zalloc(sizeof *mountData, HGFS_ALLOC_FLAG);
+ if (!mountData) {
+ return ENOMEM;
+ }
+
+ if (ddi_copyin(mntp->dataptr, mountData, sizeof *mountData,
+ mntp->flags & MS_SYSSPACE ? FKIOCTL : 0) == -1) {
+ DEBUG(VM_DEBUG_FAIL, "HgfsMount: couldn't copy mount data.\n");
+ ret = EFAULT;
+ goto out;
}
/*
- * Make sure mount data matches what guestd will send us.
+ * Make sure mount data matches what mount program will send us.
*/
if (mountData->magic != HGFS_MAGIC) {
- DEBUG(VM_DEBUG_FAIL, "HgfsMount: received invalid magic value: %x\n",
- mountData->magic);
- ret = EINVAL;
- goto out;
+ DEBUG(VM_DEBUG_FAIL, "HgfsMount: received invalid magic value: %x\n",
+ mountData->magic);
+ ret = EINVAL;
+ goto out;
+ }
+
+ /* We support only one instance of hgfs, at least for now */
+ if (HgfsGetSuperInfo()) {
+ DEBUG(VM_DEBUG_FAIL, "HgfsMount: HGFS is already mounted somewhere\n");
+ ret = EBUSY;
+ goto out;
}
/*
* construct the filesystem id.
*/
if ((dev = getudev()) == -1) {
- DEBUG(VM_DEBUG_FAIL, "HgfsMount(): getudev() failed.\n");
- ret = ENXIO;
- goto out;
+ DEBUG(VM_DEBUG_FAIL, "HgfsMount(): getudev() failed.\n");
+ ret = ENXIO;
+ goto out;
}
DEBUG(VM_DEBUG_LOAD, "HgfsMount: dev=%lu\n", dev);
vnodep->v_vfsmountedhere = vfsp;
# endif
- /* We need to initialize the File hash table before getting our first vnode. */
- ret = HgfsInitFileHashTable(&sip->fileHashTable);
- if (ret) {
- DEBUG(VM_DEBUG_FAIL, "HgfsMount: couldn't initialize hash table.\n");
+ HgfsInitSuperInfo(vfsp);
+
+ sip = HgfsGetSuperInfo();
+ vfsp->vfs_data = (caddr_t)sip;
+
+ if (!sip->transportInit()) {
+ DEBUG(VM_DEBUG_FAIL, "HgfsMount: failed to start transport.\n");
+ HgfsClearSuperInfo();
ret = EIO;
goto out;
}
&sip->fileHashTable); // File hash table
if (ret) {
DEBUG(VM_DEBUG_FAIL, "HgfsMount: couldn't get root vnode.\n");
+ sip->transportCleanup();
+ HgfsClearSuperInfo();
ret = EIO;
goto out;
}
sip->rootVnode->v_flag |= VROOT;
mutex_exit(&sip->rootVnode->v_lock);
- /*
- * Fill in value(s) for the HGFS superinfo structure and link it to this
- * filesystem's VFS structure.
- */
- sip->vfsp = vfsp;
-
- vfsp->vfs_data = (caddr_t)sip;
-
/* XXX do this? */
VN_HOLD(vnodep);
- ret = 0; /* Return success */
-
DEBUG(VM_DEBUG_DONE, "HgfsMount() done.\n");
+ ret = 0; /* Return success */
out:
- if (!(mntp->flags & MS_SYSSPACE)) {
- kmem_free(mountData, sizeof *mountData);
- }
+ kmem_free(mountData, sizeof *mountData);
return ret;
}
struct cred *credp) // IN: Credentials of caller
{
HgfsSuperInfo *sip;
+ int ret;
+
+ DEBUG(VM_DEBUG_ENTRY, "HgfsUnmount().\n");
if (!vfsp || !credp) {
cmn_err(HGFS_ERROR, "HgfsUnmount: NULL input from Kernel.\n");
return EINVAL;
}
- DEBUG(VM_DEBUG_ENTRY, "HgfsUnmount().\n");
- HgfsDebugPrintVnode(VM_DEBUG_STRUCT, "HgfsUnmount", vfsp->vfs_vnodecovered);
-
/*
* Initial check to ensure caller is root.
*/
DEBUG(VM_DEBUG_ALWAYS, "HgfsUnmount: vfsp != sip->vfsp.\n");
}
+ HgfsDebugPrintVnode(VM_DEBUG_STRUCT, "HgfsUnmount",
+ vfsp->vfs_vnodecovered, FALSE);
+
+ /* Take the request lock to prevent submitting new requests */
+ mutex_enter(&sip->reqMutex);
+
/*
* Make sure there are no active files (besides the root vnode which we
* release at the end of the function).
*/
HgfsDebugPrintFileHashTable(&sip->fileHashTable, VM_DEBUG_STATE);
- if (!HgfsFileHashTableIsEmpty(sip, &sip->fileHashTable)) {
- /*
- * If the force flag was specified, we'll cancel all requests and perform
- * the unmount. Otherwise, we'll just return EBUSY.
- */
- if (mflag & MS_FORCE) {
- HgfsCancelAllRequests(sip);
- } else {
- DEBUG(VM_DEBUG_FAIL, "HgfsUnmount: there are still active files.\n");
- return EBUSY;
- }
- }
- /* Send an unclean unmount warning to syslog. */
- if (!sip->devOpen) {
- cmn_err(HGFS_ERROR, "HgfsUnmount: unclean unmount; device was closed.\n");
+ if (!HgfsFileHashTableIsEmpty(sip, &sip->fileHashTable) &&
+ !(mflag & MS_FORCE)) {
+ DEBUG(VM_DEBUG_FAIL, "HgfsUnmount: there are still active files.\n");
+ ret = EBUSY;
+ goto out;
}
+ HgfsCancelAllRequests(sip);
+
/*
* Set unmounted flag in vfs structure.
*/
vfsp->vfs_flag |= VFS_UNMOUNTED;
+ /*
+ * Close transport channel, we should not be gettign any more requests.
+ */
+ sip->transportCleanup();
+
/*
* Clean up fields in vnode structure of mount point and release hold on
* vnodes for mount.
*/
# if HGFS_VFS_VERSION == 2
- (vfsp->vfs_vnodecovered)->v_vfsmountedhere = NULL;
+ vfsp->vfs_vnodecovered->v_vfsmountedhere = NULL;
# endif
VN_RELE(vfsp->vfs_vnodecovered);
- VN_RELE( HGFS_ROOT_VNODE(sip) );
+ VN_RELE(HGFS_ROOT_VNODE(sip));
/*
* Signify to the device half that the filesystem has been unmounted.
*/
- sip->vfsp = NULL;
HGFS_ROOT_VNODE(sip) = NULL;
+ HgfsClearSuperInfo();
- return 0;
+ ret = 0;
+
+out:
+ mutex_exit(&sip->reqMutex);
+
+ DEBUG(VM_DEBUG_DONE, "HgfsUnmount() done.\n");
+ return ret;
}
#define HGFS_FSTYPE HGFS_FS_NAME
/*
- * Struct passed from user (guestd) to kernel (fs module)
+ * Struct passed from mount program to kernel (fs module)
*/
typedef struct HgfsMountData {
uint32_t magic;
/* To abstract Solaris 9 and 10 differences in suser() calls */
int HgfsSuser(struct cred *cr);
+void HgfsFreeVfsOps(void);
/*
* Extern variables
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * guest_msg_def.h --
+ *
+ * Second layer of the internal communication channel between guest
+ * applications and vmware
+ *
+ */
+
+#ifndef _GUEST_MSG_DEF_H_
+#define _GUEST_MSG_DEF_H_
+
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#include "includeCheck.h"
+
+
+/* Basic request types */
+typedef enum {
+ MESSAGE_TYPE_OPEN,
+ MESSAGE_TYPE_SENDSIZE,
+ MESSAGE_TYPE_SENDPAYLOAD,
+ MESSAGE_TYPE_RECVSIZE,
+ MESSAGE_TYPE_RECVPAYLOAD,
+ MESSAGE_TYPE_RECVSTATUS,
+ MESSAGE_TYPE_CLOSE,
+} MessageType;
+
+
+/* Reply statuses */
+/* The basic request succeeded */
+#define MESSAGE_STATUS_SUCCESS 0x0001
+/* vmware has a message available for its party */
+#define MESSAGE_STATUS_DORECV 0x0002
+/* The channel has been closed */
+#define MESSAGE_STATUS_CLOSED 0x0004
+/* vmware removed the message before the party fetched it */
+#define MESSAGE_STATUS_UNSENT 0x0008
+/* A checkpoint occurred */
+#define MESSAGE_STATUS_CPT 0x0010
+/* An underlying device is powering off */
+#define MESSAGE_STATUS_POWEROFF 0x0020
+/* vmware has detected a timeout on the channel */
+#define MESSAGE_STATUS_TIMEOUT 0x0040
+/* vmware supports high-bandwidth for sending and receiving the payload */
+#define MESSAGE_STATUS_HB 0x0080
+
+/*
+ * This mask defines the status bits that the guest is allowed to set;
+ * we use this to mask out all other bits when receiving the status
+ * from the guest. Otherwise, the guest can manipulate VMX state by
+ * setting status bits that are only supposed to be changed by the
+ * VMX. See bug 45385.
+ */
+#define MESSAGE_STATUS_GUEST_MASK MESSAGE_STATUS_SUCCESS
+
+/*
+ * Max number of channels.
+ * Unfortunately this has to be public because the monitor part
+ * of the backdoor needs it for its trivial-case optimization. [greg]
+ */
+#define GUESTMSG_MAX_CHANNEL 8
+
+/* Flags to open a channel. --hpreg */
+#define GUESTMSG_FLAG_COOKIE 0x80000000
+#define GUESTMSG_FLAG_ALL GUESTMSG_FLAG_COOKIE
+
+/*
+ * Maximum size of incoming message. This is to prevent denial of host service
+ * attacks from guest applications.
+ */
+#define GUESTMSG_MAX_IN_SIZE (64 * 1024)
+
+#endif /* _GUEST_MSG_DEF_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * hgfsBd.c --
+ *
+ * Backdoor calls used by hgfs pserver. [bac]
+ */
+
+#if defined(__KERNEL__) || defined(_KERNEL) || defined(KERNEL)
+# include "kernelStubs.h"
+#else
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <errno.h>
+# include "str.h" // for Str_Strcpy
+# include "debug.h"
+#endif
+
+#include "vm_assert.h"
+#include "rpcout.h"
+#include "hgfs.h" // for common HGFS definitions
+#include "hgfsBd.h"
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBdGetBufInt --
+ *
+ * Allocates a buffer to send a hgfs request in. This can be either a
+ * HGFS_PACKET_MAX or HGFS_LARGE_PACKET_MAX size buffer depending on the
+ * external funciton called.
+ *
+ * Results:
+ * Pointer to a buffer that has the correct backdoor command prefix for
+ * sending hgfs requests over the backdoor.
+ * NULL on failure (not enough memory).
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static char *
+HgfsBdGetBufInt(size_t bufSize)
+{
+ /*
+ * Allocate a buffer that is large enough for an HGFS packet and the
+ * synchronous HGFS command, write the command, and return a pointer that
+ * points into the buffer, after the command.
+ */
+ size_t len = bufSize + HGFS_SYNC_REQREP_CLIENT_CMD_LEN;
+ char *buf = (char*) calloc(sizeof(char), len);
+
+ if (!buf) {
+ Debug("HgfsBd_GetBuf: Failed to allocate a bd buffer\n");
+ return NULL;
+ }
+
+ Str_Strcpy(buf, HGFS_SYNC_REQREP_CLIENT_CMD, len);
+
+ return buf + HGFS_SYNC_REQREP_CLIENT_CMD_LEN;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBd_GetBuf --
+ *
+ * Get a buffer of size HGFS_PACKET_MAX to send hgfs requests in.
+ *
+ * Results:
+ * See HgfsBdGetBufInt.
+ *
+ * Side effects:
+ * Allocates memory that must be freed with a call to HgfsBd_PutBuf.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+char *
+HgfsBd_GetBuf(void)
+{
+ return HgfsBdGetBufInt(HGFS_PACKET_MAX);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBd_GetLargeBuf --
+ *
+ * Get a buffer of size HGFS_LARGE_PACKET_MAX to send hgfs requests in.
+ *
+ * Results:
+ * See HgfsBdGetBufInt.
+ *
+ * Side effects:
+ * Allocates memory that must be freed with a call to HgfsBd_PutBuf.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+char *
+HgfsBd_GetLargeBuf(void)
+{
+ return HgfsBdGetBufInt(HGFS_LARGE_PACKET_MAX);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBd_PutBuf --
+ *
+ * Release a buffer obtained with HgfsBd_GetBuf.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsBd_PutBuf(char *buf) // IN
+{
+ ASSERT(buf);
+
+ free(buf - HGFS_SYNC_REQREP_CLIENT_CMD_LEN);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBd_GetChannel --
+ *
+ * Allocate a new RpcOut channel, and try to open the connection.
+ *
+ * Results:
+ * Pointer to the allocated, opened channel on success.
+ * NULL on failure (not enough memory, or failed to open the connection).
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+RpcOut *
+HgfsBd_GetChannel(void)
+{
+ RpcOut *out = RpcOut_Construct();
+ Bool status;
+
+ if (!out) {
+ Debug("HgfsBd_GetChannel: Failed to allocate an RpcOut\n");
+ return NULL;
+ }
+
+ status = RpcOut_start(out);
+ if (status == FALSE) {
+ RpcOut_Destruct(out);
+ return NULL;
+ }
+
+ return out;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBd_CloseChannel --
+ *
+ * Close the channel and free the RpcOut object.
+ *
+ * Results:
+ * TRUE if closing the channel succeeded, FALSE if it failed.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsBd_CloseChannel(RpcOut *out) // IN: Channel to close and free
+{
+ Bool success;
+
+ ASSERT(out);
+
+ success = RpcOut_stop(out);
+ if (success == TRUE) {
+ RpcOut_Destruct(out);
+ }
+
+ return success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBd_Dispatch --
+ *
+ * Get a reply to an hgfs request. We call RpcOut_Sent, which
+ * returns a buffer with the reply in it, and we pass this back to
+ * the caller.
+ *
+ * Results:
+ * On success, returns zero. On failure, returns a negative error.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsBd_Dispatch(RpcOut *out, // IN: Channel to send on
+ char *packetIn, // IN: Buf containing request packet
+ size_t *packetSize, // IN/OUT: Size of packet in/out
+ char const **packetOut) // OUT: Buf containing reply packet
+{
+ Bool success;
+ char const *reply;
+ size_t replyLen;
+
+ ASSERT(out);
+ ASSERT(packetIn);
+ ASSERT(packetSize);
+ ASSERT(packetOut);
+
+ success = RpcOut_send(out, packetIn - HGFS_CLIENT_CMD_LEN,
+ *packetSize + HGFS_CLIENT_CMD_LEN,
+ &reply, &replyLen);
+ if (success == FALSE) {
+ Debug("HgfsBd_Dispatch: RpcOut_send returned failure\n");
+ return -1;
+ }
+
+ ASSERT(replyLen <= HGFS_LARGE_PACKET_MAX);
+ *packetOut = reply;
+ *packetSize = replyLen;
+
+ return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBd_Enabled --
+ *
+ * Test to see if hgfs is enabled on the host.
+ *
+ * Results:
+ * TRUE if hgfs is enabled.
+ * FALSE if hgfs is disabled.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsBd_Enabled(RpcOut *out, // IN: RPCI Channel
+ char *requestPacket) // IN: Buffer (obtained from HgfsBd_GetBuf)
+{
+ char const *replyPacket; // Buffer returned by HgfsBd_Dispatch
+ size_t packetSize;
+ int error;
+
+ /*
+ * Send a bogus (empty) request to the VMX. If hgfs is disabled on
+ * the host side then the request will fail (because the RPCI call
+ * itself will fail). If hgfs is enabled, we will get a packet back
+ * (it will be an error packet because our request was malformed,
+ * but we just discard it anyway).
+ */
+ packetSize = 0;
+ error = HgfsBd_Dispatch(out,
+ requestPacket,
+ &packetSize,
+ &replyPacket);
+ if (error < 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBd_OpenBackdoor --
+ *
+ * Check if the HGFS channel is open, and, if not, open it. This is a
+ * one-stop convenience wrapper around HgfsBd_Enabled, HgfsBd_GetBuf, and
+ * HgfsBd_GetChannel.
+ *
+ * Results:
+ * TRUE if the backdoor is now open, regardless of its previous state.
+ * FALSE if the backdoor could not be opened.
+ *
+ * Side effects:
+ * May open a channel to the host.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsBd_OpenBackdoor(RpcOut **out) // IN/OUT: RPCI Channel
+{
+ char *packetBuffer = NULL;
+ Bool success = FALSE;
+
+ ASSERT(out);
+
+ /* Short-circuit: backdoor is already open. */
+ if (*out != NULL) {
+ return TRUE;
+ }
+
+ /* Open the channel. */
+ *out = HgfsBd_GetChannel();
+ if (*out == NULL) {
+ return FALSE;
+ }
+
+ /* Allocate a buffer for use in pinging the HGFS server. */
+ packetBuffer = HgfsBd_GetBuf();
+ if (packetBuffer == NULL) {
+ goto out;
+ }
+
+ /* Ping the HGFS server. */
+ if (!HgfsBd_Enabled(*out, packetBuffer)) {
+ goto out;
+ }
+ success = TRUE;
+
+ out:
+ if (packetBuffer != NULL) {
+ HgfsBd_PutBuf(packetBuffer);
+ }
+ if (!success && *out != NULL) {
+ HgfsBd_CloseChannel(*out);
+ *out = NULL;
+ }
+ return success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBd_CloseBackdoor --
+ *
+ * Closes the backdoor channel, if it's open.
+ *
+ * Results:
+ * TRUE if the channel is now closed, regardless of its previous state.
+ * FALSE if we could not close the channel.
+ *
+ * Side effects:
+ * May close the channel to the host.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsBd_CloseBackdoor(RpcOut **out) // IN/OUT: RPCI Channel
+{
+ Bool success = TRUE;
+
+ ASSERT(out);
+
+ if (*out != NULL) {
+ if (!HgfsBd_CloseChannel(*out)) {
+ success = FALSE;
+ }
+ *out = NULL;
+ }
+
+ return success;
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+#ifndef _HGFS_BD_H_
+# define _HGFS_BD_H_
+
+/*
+ * hgfsBd.h --
+ *
+ * Backdoor calls used by hgfs clients.
+ */
+
+#include "rpcout.h"
+
+char *HgfsBd_GetBuf(void);
+
+char *HgfsBd_GetLargeBuf(void);
+
+void HgfsBd_PutBuf(char *);
+
+RpcOut *HgfsBd_GetChannel(void);
+
+Bool HgfsBd_CloseChannel(RpcOut *out);
+
+int HgfsBd_Dispatch(RpcOut *out,
+ char *packetIn,
+ size_t *packetSize,
+ char const **packetOut);
+
+Bool HgfsBd_Enabled(RpcOut *out,
+ char *requestPacket);
+
+Bool HgfsBd_OpenBackdoor(RpcOut **out);
+
+Bool HgfsBd_CloseBackdoor(RpcOut **out);
+
+#endif // _HGFS_BD_H_
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * hgfsBdGlue.c --
+ *
+ * Glue to communicate directly with backdoor code instead of offloading
+ * it to guestd
+ */
+
+#include "hgfsSolaris.h"
+#include "request.h"
+#include "hgfsBdGlue.h"
+#include "hgfsBd.h"
+#include "vm_assert.h"
+#include "debug.h"
+
+static RpcOut *hgfsRpcOut;
+static void *packetBuffer;
+
+/*
+ * Public function implementations.
+ */
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBackdoorSendRequest --
+ *
+ * Send one request through backdoor and wait for the result.
+ *
+ * Results:
+ * 0 on success, standard UNIX error code upon failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsBackdoorSendRequest(HgfsReq *req) // IN/OUT: Request to be sent
+{
+ char const *replyPacket;
+ size_t packetSize;
+
+ ASSERT(req->state == HGFS_REQ_SUBMITTED);
+
+ ASSERT(req->packetSize <= HGFS_PACKET_MAX);
+ bcopy(req->packet, packetBuffer, req->packetSize);
+ packetSize = req->packetSize;
+
+ DEBUG(VM_DEBUG_COMM,
+ "HgfsBackdoorSendRequest: Sending packet over backdoor\n");
+
+ /*
+ * We should attempt to reopen the backdoor channel with every request,
+ * because the HGFS server in the host can be enabled or disabled at any
+ * time.
+ */
+ if (!HgfsBd_OpenBackdoor(&hgfsRpcOut)) {
+
+ DEBUG(VM_DEBUG_COMM,
+ "HgfsBackdoorSendRequest: HGFS is disabled in the host\n");
+
+ req->state = HGFS_REQ_ERROR;
+ return ENOSYS;
+
+ } else if (HgfsBd_Dispatch(hgfsRpcOut, packetBuffer,
+ &packetSize, &replyPacket) == 0) {
+
+ DEBUG(VM_DEBUG_COMM,
+ "HgfsBackdoorSendRequest: backdoor reply received\n");
+
+ /* Request was sent successfully. Copy the reply and return to the client. */
+ ASSERT(packetSize <= HGFS_PACKET_MAX);
+
+ bcopy(replyPacket, req->packet, packetSize);
+ req->packetSize = packetSize;
+ req->state = HGFS_REQ_COMPLETED;
+
+ } else {
+
+ DEBUG(VM_DEBUG_COMM,
+ "HgfsBackdoorSendRequest: backdoor error\n");
+
+ /* Pass the error into the request. */
+ req->state = HGFS_REQ_ERROR;
+
+ /*
+ * If the channel was previously open, make sure it's dead and gone
+ * now. We do this because subsequent requests deserve a chance to
+ * reopen it.
+ */
+ HgfsBd_CloseBackdoor(&hgfsRpcOut);
+ }
+
+ return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBackdoorCancelRequest --
+ *
+ * Cancel request stub. Since backdoor is synchronous transport this
+ * function should never be called in practice.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsBackdoorCancelRequest(HgfsReq *req) // IN: Request to be cancelled
+{
+ DEBUG(VM_DEBUG_COMM, "HgfsBackdoorCancelRequest: %p\n", req);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsBackdoorInit --
+ *
+ * This function initializes backdoor transport by allocating transfer
+ * buffer.
+ *
+ * Results:
+ * TRUE if buffer was allocated succsessfully, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Bool
+HgfsBackdoorInit(void)
+{
+ packetBuffer = HgfsBd_GetBuf();
+
+ return packetBuffer != NULL;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsBackdoorCleanup --
+ *
+ * This function closes backdoor channel. It is supposed to be
+ * called when we unmount the filesystem.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+HgfsBackdoorCleanup(void)
+{
+ DEBUG(VM_DEBUG_COMM, "HgfsBackdoorCleanup: Closing backdoor\n");
+
+ HgfsBd_CloseBackdoor(&hgfsRpcOut);
+ HgfsBd_PutBuf(packetBuffer);
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * bdhandler.h --
+ *
+ * Glue for backdoor library.
+ */
+
+#ifndef _HGFS_BD_GLUE_H_
+#define _HGFS_BD_GLUE_H_
+
+int HgfsBackdoorSendRequest(HgfsReq *req);
+void HgfsBackdoorCancelRequest(HgfsReq *req);
+Bool HgfsBackdoorInit(void);
+void HgfsBackdoorCleanup(void);
+
+#endif // _HGFS_DRIVER_BDHANDLER_H_
#define HGFS_PERM_WRITE 2
#define HGFS_PERM_EXEC 1
+/*
+ * Access mode bits.
+ *
+ * Different operating systems have different set of file access mode.
+ * Here are constants that are rich enough to describe all access modes in an OS
+ * independent way.
+ */
+
+typedef uint32 HgfsAccessMode;
+/*
+ * Generic access rights control coarse grain access for the file.
+ * A particular generic rigth can be expanded into different set of specific rights
+ * on different OS.
+ */
+
+/*
+ * HGFS_MODE_GENERIC_READ means ability to read file data and read various file
+ * attributes and properties.
+ */
+#define HGFS_MODE_GENERIC_READ (1 << 0)
+/*
+ * HGFS_MODE_GENERIC_WRITE means ability to write file data and updaate various file
+ * attributes and properties.
+ */
+#define HGFS_MODE_GENERIC_WRITE (1 << 1)
+/*
+ * HGFS_MODE_GENERIC_EXECUE means ability to execute file. For network redirectors
+ * ability to execute usualy implies ability to read data; for local file systems
+ * HGFS_MODE_GENERIC_EXECUTE does not imply ability to read data.
+ */
+#define HGFS_MODE_GENERIC_EXECUTE (1 << 2)
+
+/* Specific rights define fine grain access modes. */
+#define HGFS_MODE_READ_DATA (1 << 3) // Ability to read file data
+#define HGFS_MODE_WRITE_DATA (1 << 4) // Ability to writge file data
+#define HGFS_MODE_APPEND_DATA (1 << 5) // Appending data to the end of file
+#define HGFS_MODE_DELETE (1 << 6) // Ability to delete the file
+#define HGFS_MODE_TRAVERSE_DIRECTORY (1 << 7) // Ability to access files in a directory
+#define HGFS_MODE_LIST_DIRECTORY (1 << 8) // Ability to list file names
+#define HGFS_MODE_ADD_SUBDIRECTORY (1 << 9) // Ability to create a new subdirectory
+#define HGFS_MODE_ADD_FILE (1 << 10) // Ability to create a new file
+#define HGFS_MODE_DELETE_CHILD (1 << 11) // Ability to delete file/subdirectory
+#define HGFS_MODE_READ_ATTRIBUTES (1 << 12) // Ability to read attributes
+#define HGFS_MODE_WRITE_ATTRIBUTES (1 << 13) // Ability to write attributes
+#define HGFS_MODE_READ_EXTATTRIBUTES (1 << 14) // Ability to read extended attributes
+#define HGFS_MODE_WRITE_EXTATTRIBUTES (1 << 15) // Ability to write extended attributes
+#define HGFS_MODE_READ_SECURITY (1 << 16) // Ability to read permissions/ACLs/owner
+#define HGFS_MODE_WRITE_SECURITY (1 << 17) // Ability to change permissions/ACLs
+#define HGFS_MODE_TAKE_OWNERSHIP (1 << 18) // Ability to change file owner/group
/*
* Server-side locking (oplocks and leases).
* only to determine if the ID is valid.
*/
#define HGFS_ATTR_VALID_NON_STATIC_FILEID (1 << 16)
+/*
+ * File permissions that are in effect for the user which runs HGFS server.
+ * Client needs to know effective permissions in order to implement access(2).
+ * Client can't derive it from group/owner/other permissions because of two resaons:
+ * 1. It does not know user/group id of the user which runs HGFS server
+ * 2. Effective permissions account for additional restrictions that may be imposed
+ * by host file system, for example by ACL.
+ */
+#define HGFS_ATTR_VALID_EFFECTIVE_PERMS (1 << 17)
/*
uint32 groupId; /* group identifier, ignored by Windows */
uint64 hostFileId; /* File Id of the file on host: inode_t on Linux */
uint32 volumeId; /* volume identifier, non-zero is valid. */
- uint32 reserved1; /* Reserved for future use */
+ uint32 effectivePerms; /* Permissions in effect for the user on the host. */
uint64 reserved2; /* Reserved for future use */
}
#include "vmware_pack_end.h"
/* Determines size of request pool */
#define HGFS_MAX_OUTSTANDING_REQS 4
-/* For ddi_soft_state_init() call in _init() */
-#define HGFS_EXPECTED_INSTANCES 23
-
/* HGFS cmn_err() levels */
#define HGFS_ERROR (CE_WARN)
#define HGFS_ERR_NODEV (-51)
#define HGFS_ERR_INVAL (-52)
-/* This is what shows up after the ':' in the /devices entry */
-#define HGFS_DEV_NAME "vmware-hgfs"
-
/*
* Don't change this to KM_NOSLEEP without first making sure that we handle
* the possibility of kmem_zalloc() failing: KM_SLEEP guarantees it won't fail
*/
#define HGFS_ALLOC_FLAG (KM_SLEEP)
-/*
- * hgfsInstance is uninitialized when device is not open and hgfsType is
- * uninitialized before the file system initialization routine is called.
- */
-#define HGFS_INSTANCE_UNINITIALIZED (-1)
-#define HGFS_TYPE_UNINITIALIZED (-1)
-
/* Accessing root inode and vnode */
#define HGFS_ROOT_VNODE(sip) (sip->rootVnode)
*/
#ifdef _KERNEL
-/*
- * The global state structure for the entire module. This is allocated in
- * HgfsDevAttach() and deallocated in HgfsDevDetach().
- *
- * Note that reqMutex and reqFreeList are also used for synchronization between
- * the filesystem and driver. See docs/synchronization.txt for details.
- */
-typedef struct HgfsSuperInfo {
- dev_info_t *dip; /* Device information pointer */
- Bool devOpen; /* Flag indicating whether device is open */
- /* Poll */
- struct pollhead hgfsPollhead; /* Needed for chpoll() implementation */
- Bool pollwakeupOnWrite; /* Flag which indicates need to call
- pollwakeup() on write() -- no mutex
- since only modified in chpoll() */
- /* Request list */
- DblLnkLst_Links reqList; /* Anchor for pending request list */
- kmutex_t reqMutex; /* For protection of request list */
- kcondvar_t reqCondVar; /* For waiting on request list */
- /* Free request list */
- DblLnkLst_Links reqFreeList; /* Anchor for free request list */
- kmutex_t reqFreeMutex; /* For protection of reqFreeList */
- kcondvar_t reqFreeCondVar; /* For waiting on free request list */
- /* For filesystem */
- struct vfs *vfsp; /* Our filesystem structure */
- struct vnode *rootVnode; /* Root vnode of the filesystem */
- HgfsFileHashTable fileHashTable; /* File hash table */
-# if HGFS_VFS_VERSION > 2
- /* We keep a pointer to the vnodeops the Kernel created for us in Sol 10 */
- struct vnodeops *vnodeOps; /* Operations on files */
-# endif
-} HgfsSuperInfo;
-
/*
* Each request will traverse through this set of states. See
* docs/request-lifecycle.txt for an explanation of these and the API for
signal presence of reply. Used with
the reqMutex in HgfsSuperInfo. */
HgfsReqState state; /* Indicates state of request */
- kmutex_t stateLock; /* Protects state: only used in
- HgfsReq{S,G}etState() */
-
uint32_t id; /* The unique identifier of this request */
-
uint32_t packetSize; /* Total size of packet */
char packet[HGFS_PACKET_MAX]; /* Contains both requests and replies */
} HgfsReq;
/*
- * Global Variables
+ * The global state structure for the entire module. This is allocated in
+ * HgfsDevAttach() and deallocated in HgfsDevDetach().
+ *
+ * Note that reqMutex and reqFreeList are also used for synchronization between
+ * the filesystem and driver. See docs/synchronization.txt for details.
*/
+typedef struct HgfsSuperInfo {
+ kmutex_t reqMutex; /* Serializes sending of requests */
+
+ /* Free request list */
+ DblLnkLst_Links reqFreeList; /* Anchor for free request list */
+ kmutex_t reqFreeMutex; /* For protection of reqFreeList */
+ kcondvar_t reqFreeCondVar; /* For waiting on free request list */
+
+ /* For filesystem */
+ struct vfs *vfsp; /* Our filesystem structure */
+ struct vnode *rootVnode; /* Root vnode of the filesystem */
+ HgfsFileHashTable fileHashTable; /* File hash table */
+
+ int (*sendRequest)(HgfsReq *req); /* Current transport's sent method */
+ void (*cancelRequest)(HgfsReq *req); /* Current transport's cancel method */
+ Bool (*transportInit)(void);
+ void (*transportCleanup)(void);
+} HgfsSuperInfo;
-/* Pool of request structures */
-HgfsReq requestPool[HGFS_MAX_OUTSTANDING_REQS];
/*
- * Fileystem type number.
- *
- * This needs to be stored here rather than in the Superinfo because the soft
- * state is not guaranteed to have been allocated when HgfsInit() is called.
+ * Global Variables
*/
-int hgfsType;
+
+/* Pool of request structures */
+HgfsReq requestPool[HGFS_MAX_OUTSTANDING_REQS];
/*
* Used to access shared state of driver and filesystem. superInfoHead is
* Now set the vnode operations. This is handled differently on Solaris
* 9 and 10, and we call HgfsSetVnodeOps() to take care of this for us.
*/
- if (HgfsSetVnodeOps(sip, vp) != 0) {
+ if (HgfsSetVnodeOps(vp) != 0) {
goto vnode_error;
}
* Initializes the hash table used to track per-file state.
*
* Results:
- * Returns 0 on success and a non-zero error code on failure.
+ * None.
*
* Side effects:
* None.
*----------------------------------------------------------------------------
*/
-int
+void
HgfsInitFileHashTable(HgfsFileHashTable *htp) // IN: Hash table to initialize
{
int i;
for (i = 0; i < ARRAYSIZE(htp->hashTable); i++) {
DblLnkLst_Init(&htp->hashTable[i]);
}
-
- return 0;
}
HgfsFileHashTable *htp);
void HgfsNodeIdGet(HgfsFileHashTable *ht, const char *fileName,
uint32_t fileNameLength, ino64_t *outNodeId);
-int HgfsInitFileHashTable(HgfsFileHashTable *htp);
+void HgfsInitFileHashTable(HgfsFileHashTable *htp);
Bool HgfsFileHashTableIsEmpty(struct HgfsSuperInfo *sip, HgfsFileHashTable *htp);
/* Handle get/set/clear functions */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2006 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * kernelStubs.h
+ *
+ * KernelStubs implements some userspace library functions in terms
+ * of kernel functions to allow library userspace code to be used in a
+ * kernel.
+ */
+
+#ifndef __KERNELSTUBS_H__
+#define __KERNELSTUBS_H__
+
+#ifdef linux
+# ifndef __KERNEL__
+# error "__KERNEL__ is not defined"
+# endif
+# include "driver-config.h" // Must be included before any other header files
+# include "vm_basic_types.h"
+# include <linux/kernel.h>
+# include <linux/string.h>
+#elif defined(_WIN32)
+# include "vm_basic_types.h"
+# include <ntddk.h> /* kernel memory APIs */
+# include <stdio.h> /* for _vsnprintf, vsprintf */
+# include <stdarg.h> /* for va_start stuff */
+# include <stdlib.h> /* for min macro. */
+# include "vm_assert.h" /* Our assert macros */
+#elif defined(__FreeBSD__)
+# include "vm_basic_types.h"
+# ifndef _KERNEL
+# error "_KERNEL is not defined"
+# endif
+# include <sys/types.h>
+# include <sys/malloc.h>
+# include <sys/param.h>
+# include <sys/kernel.h>
+# include <machine/stdarg.h>
+# include <sys/libkern.h>
+# include "vm_assert.h"
+#elif defined(__APPLE__)
+# include "vm_basic_types.h"
+# ifndef KERNEL
+# error "KERNEL is not defined"
+# endif
+# include <stdarg.h>
+# include <string.h>
+# elif defined(sun)
+# include "vm_basic_types.h"
+# include <sys/types.h>
+# include <sys/varargs.h>
+#endif
+
+/*
+ * Function Prototypes
+ */
+
+#if defined(linux) || defined(__APPLE__) || defined (sun)
+
+# ifdef linux /* if (linux) { */
+char *strdup(const char *source);
+# endif
+
+/* Shared between Linux and Apple kernel stubs. */
+void *malloc(size_t size);
+void free(void *mem);
+void *calloc(size_t num, size_t len);
+void *realloc(void *ptr, size_t newSize);
+
+#elif defined(_WIN32) /* } else if (_WIN32) { */
+
+#if (_WIN32_WINNT == 0x0400)
+/* The following declarations are missing on NT4. */
+typedef unsigned int UINT_PTR;
+typedef unsigned int SIZE_T;
+
+/* No free with tag availaible on NT4 kernel! */
+#define KRNL_STUBS_FREE(P,T) ExFreePool((P))
+
+#else /* _WIN32_WINNT */
+#define KRNL_STUBS_FREE(P,T) ExFreePoolWithTag((P),(T))
+/* Win 2K and later useful kernel function, documented but not declared! */
+NTKERNELAPI VOID ExFreePoolWithTag(IN PVOID P, IN ULONG Tag);
+#endif /* _WIN32_WINNT */
+
+#elif defined(__FreeBSD__) /* } else if (FreeBSD) { */
+
+/* Kernel memory on FreeBSD is tagged for statistics and sanity checking. */
+MALLOC_DECLARE(M_VMWARE_TEMP);
+
+/*
+ * On FreeBSD, the general memory allocator for both userland and the kernel is named
+ * malloc, but the kernel malloc() takes more arguments. The following alias & macros
+ * work around this, to provide the standard malloc() API for userspace code that is
+ * being used in the kernel.
+ */
+
+# undef malloc
+
+static INLINE void *
+__compat_malloc(unsigned long size, struct malloc_type *type, int flags) {
+ return malloc(size, type, flags);
+}
+
+# define malloc(size) __compat_malloc(size, M_VMWARE_TEMP, M_NOWAIT)
+# define calloc(count, size) __compat_malloc((count) * (size), \
+ M_VMWARE_TEMP, M_NOWAIT|M_ZERO)
+# define realloc(buf, size) realloc(buf, size, M_VMWARE_TEMP, M_NOWAIT)
+# define free(buf) free(buf, M_VMWARE_TEMP)
+# define strchr(s,c) index(s,c)
+# define strrchr(s,c) rindex(s,c)
+
+#endif /* } */
+
+/*
+ * Stub functions we provide.
+ */
+
+void Panic(const char *fmt, ...);
+
+char *Str_Strcpy(char *buf, const char *src, size_t maxSize);
+int Str_Vsnprintf(char *str, size_t size, const char *format,
+ va_list arguments);
+char *Str_Vasprintf(size_t *length, const char *format,
+ va_list arguments);
+char *Str_Asprintf(size_t *length, const char *Format, ...);
+
+/*
+ * Functions the driver must implement for the stubs.
+ */
+EXTERN void Debug(const char *fmt, ...);
+
+
+#endif /* __KERNELSTUBS_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * kernelStubsSolaris.c
+ *
+ * This file contains implementations of common userspace functions in terms
+ * that the Solaris kernel can understand.
+ */
+
+#include "kernelStubs.h"
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+#ifdef SOL9
+# define compat_va_start(arg, fmt) arg = ((char *)__builtin_next_arg(fmt))
+# define compat_va_end(arg)
+# define compat_va_copy(arg1, arg2) va_copy(arg1, arg2)
+#else
+# define compat_va_start(arg, fmt) va_start(arg, fmt)
+# define compat_va_end(arg) va_end(arg)
+# define compat_va_copy(arg1, arg2) va_copy(arg1, arg2)
+#endif
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Panic --
+ *
+ * Prints the debug message and stops the system.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Panic(const char *fmt, ...) // IN
+{
+ va_list args;
+ char *result;
+
+ compat_va_start(args, fmt);
+ result = Str_Vasprintf(NULL, fmt, args);
+ compat_va_end(args);
+
+ cmn_err(CE_PANIC, "%s",
+ result ? result : "Unable to format PANIC message");
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Str_Strcpy --
+ *
+ * Wrapper for strcpy that checks for buffer overruns.
+ *
+ * Results:
+ * Same as strcpy.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+Str_Strcpy(char *buf, // OUT
+ const char *src, // IN
+ size_t maxSize) // IN
+{
+ size_t len;
+
+ len = strlen(src);
+ if (len >= maxSize) {
+ Panic("%s:%d Buffer too small %p\n", __FILE__, __LINE__, buf);
+ }
+ bcopy(src, buf, len + 1);
+ return buf;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Str_Vsnprintf --
+ *
+ * Compatability wrapper b/w different libc versions
+ *
+ * Results:
+ * int - number of bytes written (not including NULL terminator),
+ * -1 on overflow (insufficient space for NULL terminator
+ * is considered overflow).
+ *
+ * NB: on overflow the buffer WILL be null terminated.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Str_Vsnprintf(char *str, // OUT
+ size_t size, // IN
+ const char *format, // IN
+ va_list arguments) // IN
+{
+ int retval = vsnprintf(str, size, format, arguments);
+
+ /*
+ * Linux glibc 2.0.x returns -1 and null terminates (which we shouldn't
+ * be linking against), but glibc 2.1.x follows c99 and returns
+ * characters that would have been written.
+ */
+ if (retval >= size) {
+ return -1;
+ }
+ return retval;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Str_Vasprintf --
+ *
+ * Allocate and format a string, using the GNU libc way to specify the
+ * format (i.e. optionally allow the use of positional parameters).
+ *
+ * Results:
+ * The allocated string on success (if 'length' is not NULL, *length
+ * is set to the length of the allocated string), NULL on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+char *
+Str_Vasprintf(size_t *length, // OUT
+ const char *format, // IN
+ va_list arguments) // IN
+{
+ /*
+ * Simple implementation of Str_Vasprintf when userlevel libraries are not
+ * available (e.g. for use in drivers). We just fallback to vsnprintf,
+ * doubling if we didn't have enough space.
+ */
+ unsigned int bufSize;
+ char *buf;
+ int retval;
+
+ bufSize = strlen(format);
+ buf = NULL;
+
+ do {
+ /*
+ * Initial allocation of strlen(format) * 2. Should this be tunable?
+ * XXX Yes, this could overflow and spin forever when you get near 2GB
+ * allocations. I don't care. --rrdharan
+ */
+ va_list args2;
+
+ bufSize *= 2;
+ buf = realloc(buf, bufSize);
+
+ if (!buf) {
+ return NULL;
+ }
+
+ compat_va_copy(args2, arguments);
+ retval = Str_Vsnprintf(buf, bufSize, format, args2);
+ compat_va_end(args2);
+ } while (retval == -1);
+
+ if (length) {
+ *length = retval;
+ }
+
+ /*
+ * Try to trim the buffer here to save memory?
+ */
+ return buf;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Str_Asprintf --
+ *
+ * Same as Str_Vasprintf(), but parameters are passed inline --hpreg
+ *
+ * Results:
+ * Same as Str_Vasprintf()
+ *
+ * Side effects:
+ * Same as Str_Vasprintf()
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+char *
+Str_Asprintf(size_t *length, // OUT
+ const char *format, // IN
+ ...) // IN
+{
+ va_list arguments;
+ char *result;
+
+ compat_va_start(arguments, format);
+ result = Str_Vasprintf(length, format, arguments);
+ compat_va_end(arguments);
+
+ return result;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * malloc --
+ *
+ * Allocate memory using kmalloc. There is no realloc
+ * equivalent, so we roll our own by padding each allocation with
+ * 4 (or 8 for 64 bit guests) extra bytes to store the block length.
+ *
+ * Results:
+ * Pointer to driver heap memory, offset by 4 (or 8)
+ * bytes from the real block pointer.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void *
+malloc(size_t size) // IN
+{
+ size_t *ptr = kmem_alloc(size + sizeof(size), KM_SLEEP);
+
+ if (ptr) {
+ *ptr++ = size;
+ }
+ return ptr;
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * free --
+ *
+ * Free memory allocated by a previous call to malloc, calloc or realloc.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Calls kmem_free to free the real (base) pointer.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+free(void *mem) // IN
+{
+ size_t *dataPtr = mem;
+
+ if (mem) {
+ --dataPtr;
+ kmem_free(dataPtr, *dataPtr + sizeof(*dataPtr));
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * calloc --
+ *
+ * Malloc and zero.
+ *
+ * Results:
+ * Pointer to driver heap memory (see malloc, above).
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void *
+calloc(size_t num, // IN
+ size_t len) // IN
+{
+ size_t size;
+ void *ptr;
+
+ size = num * len;
+ ptr = malloc(size);
+ if (ptr) {
+ memset(ptr, 0, size);
+ }
+ return ptr;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * realloc --
+ *
+ * Since the driver heap has no realloc equivalent, we have to roll our
+ * own. Fortunately, we can retrieve the block size of every block we
+ * hand out since we stashed it at allocation time (see malloc above).
+ *
+ * Results:
+ * Pointer to memory block valid for 'newSize' bytes, or NULL if
+ * allocation failed.
+ *
+ * Side effects:
+ * Could copy memory around.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void *
+realloc(void *ptr, // IN
+ size_t newSize) // IN
+{
+ void *newPtr;
+ size_t *dataPtr;
+ size_t length, lenUsed;
+
+ dataPtr = (size_t *)ptr;
+ length = ptr ? dataPtr[-1] : 0;
+ if (newSize == 0) {
+ if (ptr) {
+ free(ptr);
+ newPtr = NULL;
+ } else {
+ newPtr = malloc(newSize);
+ }
+ } else if (newSize == length) {
+ newPtr = ptr;
+ } else if ((newPtr = malloc(newSize))) {
+ if (length < newSize) {
+ lenUsed = length;
+ } else {
+ lenUsed = newSize;
+ }
+ memcpy(newPtr, ptr, lenUsed);
+ free(ptr);
+ }
+ return newPtr;
+}
+
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1999 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * message.c --
+ *
+ * Second layer of the internal communication channel between guest
+ * applications and vmware
+ *
+ * Build a generic messaging system between guest applications and vmware.
+ *
+ * The protocol is not completely symmetrical, because:
+ * . basic requests can only be sent by guest applications (when vmware
+ * wants to post a message to a guest application, the message will be
+ * really fetched only when the guest application will poll for new
+ * available messages)
+ * . several guest applications can talk to vmware, while the contrary is
+ * not true
+ *
+ * Operations that are not atomic (in terms of number of backdoor calls)
+ * can be aborted by vmware if a checkpoint/restore occurs in the middle of
+ * such an operation. This layer takes care of retrying those operations.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__KERNEL__) || defined(_KERNEL) || defined(KERNEL)
+# include "kernelStubs.h"
+#else
+# include <stdio.h>
+# include <stdlib.h>
+# include "debug.h"
+#endif
+
+#include "backdoor_def.h"
+#include "guest_msg_def.h"
+#include "backdoor.h"
+#include "message.h"
+
+static MessageOpenProcType externalOpenProc = NULL;
+static MessageGetReadEventProcType externalGetReadEventProc = NULL;
+static MessageSendProcType externalSendProc = NULL;
+static MessageReceiveProcType externalReceiveProc = NULL;
+static MessageCloseProcType externalCloseProc = NULL;
+
+/*
+ * Currently, the default implementation is to use the backdoor. Soon,
+ * this will not be the default, as we will explicitly set it when we
+ * decide to use the backdoor.
+ */
+EXTERN Message_Channel *MessageBackdoor_Open(uint32 proto);
+
+EXTERN Bool MessageBackdoor_GetReadEvent(Message_Channel *chan,
+ int64 *event);
+
+EXTERN Bool MessageBackdoor_Send(Message_Channel *chan,
+ const unsigned char *buf,
+ size_t bufSize);
+
+EXTERN Bool MessageBackdoor_Receive(Message_Channel *chan,
+ unsigned char **buf,
+ size_t *bufSize);
+
+EXTERN Bool MessageBackdoor_Close(Message_Channel *chan);
+
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Message_SetTransport --
+ *
+ * This tells the message layer to use an alternate transport
+ * for messages. By default, we use the backdoor, so this function
+ * overrides that default at runtime and switches everything over to
+ * an alternate transport.
+ *
+ * Result:
+ * None
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+Message_SetTransport(MessageOpenProcType openProc, // IN
+ MessageGetReadEventProcType getReadEeventProc, // IN
+ MessageSendProcType sendProc, // IN
+ MessageReceiveProcType receiveProc, // IN
+ MessageCloseProcType closeProc) // IN
+{
+ externalOpenProc = openProc;
+ externalGetReadEventProc = getReadEeventProc;
+ externalSendProc = sendProc;
+ externalReceiveProc = receiveProc;
+ externalCloseProc = closeProc;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Message_Open --
+ *
+ * Open a communication channel
+ *
+ * Result:
+ * An allocated Message_Channel on success
+ * NULL on failure
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Message_Channel *
+Message_Open(uint32 proto) // IN
+{
+ /*
+ * If there is an alterate backdoor implementation, then call that.
+ */
+ if (NULL != externalOpenProc) {
+ return((*externalOpenProc)(proto));
+ }
+
+ /*
+ * Otherwise, we default to the backdoor.
+ */
+ return(MessageBackdoor_Open(proto));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Message_GetReadEvent --
+ *
+ * This allows higher levels of the IPC stack to use an event to detect
+ * when a message has arrived. This allows an asynchronous, event-based-model
+ * rather than continually calling Message_Receive in a busy loop. This may
+ * only be supported by some transports. The backdoor does not, so the IPC
+ * code will still have to poll in those cases.
+ *
+ * Result:
+ * Bool - whether this feature is supported by this transport.
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+Message_GetReadEvent(Message_Channel *chan, // IN
+ int64 *event) // OUT
+{
+ /*
+ * If there is an alterate backdoor implementation, then call that.
+ */
+ if (NULL != externalGetReadEventProc) {
+ return((*externalGetReadEventProc)(chan, event));
+ }
+
+ /*
+ * Otherwise, we default to the backdoor.
+ */
+ return(MessageBackdoor_GetReadEvent(chan, event));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Message_Send --
+ *
+ * Send a message over a communication channel
+ *
+ * Result:
+ * TRUE on success
+ * FALSE on failure (the message is discarded by vmware)
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+Message_Send(Message_Channel *chan, // IN/OUT
+ const unsigned char *buf, // IN
+ size_t bufSize) // IN
+{
+ /*
+ * If there is an alterate backdoor implementation, then call that.
+ */
+ if (NULL != externalSendProc) {
+ return((*externalSendProc)(chan, buf, bufSize));
+ }
+
+ /*
+ * Otherwise, we default to the backdoor.
+ */
+ return(MessageBackdoor_Send(chan, buf, bufSize));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Message_Receive --
+ *
+ * If vmware has posted a message for this channel, retrieve it
+ *
+ * Result:
+ * TRUE on success (bufSize is 0 if there is no message)
+ * FALSE on failure
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+Message_Receive(Message_Channel *chan, // IN/OUT
+ unsigned char **buf, // OUT
+ size_t *bufSize) // OUT
+{
+ /*
+ * If there is an alterate backdoor implementation, then call that.
+ */
+ if (NULL != externalReceiveProc) {
+ return((*externalReceiveProc)(chan, buf, bufSize));
+ }
+
+ /*
+ * Otherwise, we default to the backdoor.
+ */
+ return(MessageBackdoor_Receive(chan, buf, bufSize));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Message_Close --
+ *
+ * Close a communication channel
+ *
+ * Result:
+ * TRUE on success, the channel is destroyed
+ * FALSE on failure
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+Message_Close(Message_Channel *chan) // IN/OUT
+{
+ /*
+ * If there is an alterate backdoor implementation, then call that.
+ */
+ if (NULL != externalCloseProc) {
+ return((*externalCloseProc)(chan));
+ }
+
+ /*
+ * Otherwise, we default to the backdoor.
+ */
+ return(MessageBackdoor_Close(chan));
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1999 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * message.h --
+ *
+ * Second layer of the internal communication channel between guest
+ * applications and vmware
+ */
+
+#ifndef __MESSAGE_H__
+# define __MESSAGE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "vm_basic_types.h"
+
+
+typedef struct Message_Channel Message_Channel;
+
+
+/*
+ * These functions must be implemented by any external Message
+ * transport implementation. Some examples include crossTalk,
+ * a network socket, or a Microsoft Hypervisor backdoor.
+ *
+ * These external functions mirror the same corresponding Message_*
+ * functions below.
+ */
+typedef Message_Channel *(*MessageOpenProcType)(uint32 proto);
+
+typedef Bool (*MessageGetReadEventProcType)(Message_Channel *chan,
+ int64 *readEvent);
+
+typedef Bool (*MessageSendProcType)(Message_Channel *chan,
+ const unsigned char *buf,
+ size_t bufSize);
+typedef Bool (*MessageReceiveProcType)(Message_Channel *chan,
+ unsigned char **buf,
+ size_t *bufSize);
+typedef Bool (*MessageCloseProcType)(Message_Channel *chan);
+
+
+/*
+ * This tells the message layer to use an alternate transport
+ * for messages. By default, we use the backdoor, so this function
+ * overrides that default at runtime and switches everything over to
+ * an alternate transport.
+ */
+void Message_SetTransport(MessageOpenProcType openProc,
+ MessageGetReadEventProcType getReadEeventProc,
+ MessageSendProcType sendProc,
+ MessageReceiveProcType receiveProc,
+ MessageCloseProcType closeProc);
+
+void MessageStub_RegisterTransport(void);
+
+Message_Channel *
+Message_Open(uint32 proto); // IN
+
+/*
+ * This allows higher levels of the IPC stack to use an event to detect
+ * when a message has arrived. This allows an interrupt-model rather than
+ * continually calling Message_Receive in a busy loop. This may only be supported
+ * by some transports. The backdoor does not, so the IPC code will still
+ * have to poll in those cases.
+ */
+Bool
+Message_GetReadEvent(Message_Channel *chan, // IN
+ int64 *event); // OUT
+
+Bool
+Message_Send(Message_Channel *chan, // IN/OUT
+ const unsigned char *buf, // IN
+ size_t bufSize); // IN
+
+Bool
+Message_Receive(Message_Channel *chan, // IN/OUT
+ unsigned char **buf, // OUT
+ size_t *bufSize); // OUT
+
+Bool
+Message_Close(Message_Channel *chan); // IN/OUT
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESSAGE_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1999 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * messageBackdoor.c --
+ *
+ * Second layer of the internal communication channel between guest
+ * applications and vmware
+ *
+ * Build a generic messaging system between guest applications and vmware.
+ *
+ * The protocol is not completely symmetrical, because:
+ * . basic requests can only be sent by guest applications (when vmware
+ * wants to post a message to a guest application, the message will be
+ * really fetched only when the guest application will poll for new
+ * available messages)
+ * . several guest applications can talk to vmware, while the contrary is
+ * not true
+ *
+ * Operations that are not atomic (in terms of number of backdoor calls)
+ * can be aborted by vmware if a checkpoint/restore occurs in the middle of
+ * such an operation. This layer takes care of retrying those operations.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if defined(__KERNEL__) || defined(_KERNEL) || defined(KERNEL)
+# include "kernelStubs.h"
+#else
+# include <stdio.h>
+# include <stdlib.h>
+# include "debug.h"
+#endif
+
+#ifdef MESSAGE_DEBUG
+# define MESSAGE_LOG(args) Debug args
+#else /* MESSAGE_DEBUG */
+# define MESSAGE_LOG(args)
+#endif /* MESSAGE_DEBUG */
+
+
+#include "backdoor_def.h"
+#include "guest_msg_def.h"
+#include "backdoor.h"
+#include "message.h"
+
+
+/* The channel object */
+struct Message_Channel {
+ /* Identifier */
+ uint16 id;
+
+ /* Reception buffer */
+ /* Data */
+ unsigned char *in;
+ /* Allocated size */
+ size_t inAlloc;
+
+ /* The cookie */
+ uint32 cookieHigh;
+ uint32 cookieLow;
+};
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MessageBackdoor_Open --
+ *
+ * Open a communication channel
+ *
+ * Result:
+ * An allocated Message_Channel on success
+ * NULL on failure
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Message_Channel *
+MessageBackdoor_Open(uint32 proto) // IN
+{
+ Message_Channel *chan;
+ uint32 flags;
+ Backdoor_proto bp;
+
+ chan = (Message_Channel *)malloc(sizeof(*chan));
+ if (chan == NULL) {
+ MESSAGE_LOG(("Message: Not enough memory\n"));
+ goto error_quit;
+ }
+
+ flags = GUESTMSG_FLAG_COOKIE;
+retry:
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_OPEN;
+ /* IN: Magic number of the protocol and flags */
+ bp.in.size = proto | flags;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if (flags) {
+ /* Cookies not supported. Fall back to no cookie. --hpreg */
+ flags = 0;
+ goto retry;
+ }
+
+ MESSAGE_LOG(("Message: Unable to open a communication channel\n"));
+ goto error_quit;
+ }
+
+ /* OUT: Id and cookie */
+ chan->id = bp.in.dx.halfs.high;
+ chan->cookieHigh = bp.out.si.word;
+ chan->cookieLow = bp.out.di.word;
+
+ /* Initialize the channel */
+ chan->in = NULL;
+ chan->inAlloc = 0;
+
+ MESSAGE_LOG(("Message: Communication channel %u opened\n", chan->id));
+ return chan;
+
+error_quit:
+ free(chan);
+ chan = NULL;
+ return NULL;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MessageBackdoor_GetReadEvent --
+ *
+ * This allows higher levels of the IPC stack to use an event to detect
+ * when a message has arrived. This allows an interrupt-model rather than
+ * continually calling Message_Receive in a busy loop. This may only be supported
+ * by some transports. The backdoor does not, so the IPC code will still
+ * have to poll in those cases.
+ *
+ * Result:
+ * Bool - whether this feature is supported by this transport.
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+MessageBackdoor_GetReadEvent(Message_Channel *chan, // IN
+ int64 *event) // OUT
+{
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MessageBackdoor_Send --
+ *
+ * Send a message over a communication channel
+ *
+ * Result:
+ * TRUE on success
+ * FALSE on failure (the message is discarded by vmware)
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+MessageBackdoor_Send(Message_Channel *chan, // IN/OUT
+ const unsigned char *buf, // IN
+ size_t bufSize) // IN
+{
+ const unsigned char *myBuf;
+ size_t myBufSize;
+ Backdoor_proto bp;
+
+retry:
+ myBuf = buf;
+ myBufSize = bufSize;
+
+ /*
+ * Send the size.
+ */
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_SENDSIZE;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+ /* IN: Size */
+ bp.in.size = myBufSize;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ MESSAGE_LOG(("Message: Unable to send a message over the communication "
+ "channel %u\n", chan->id));
+ return FALSE;
+ }
+
+ if (bp.in.cx.halfs.high & MESSAGE_STATUS_HB) {
+ /*
+ * High-bandwidth backdoor port supported. Send the message in one
+ * backdoor operation. --hpreg
+ */
+
+ if (myBufSize) {
+ Backdoor_proto_hb bphb;
+
+ bphb.in.bx.halfs.low = BDOORHB_CMD_MESSAGE;
+ bphb.in.bx.halfs.high = MESSAGE_STATUS_SUCCESS;
+ bphb.in.dx.halfs.high = chan->id;
+ bphb.in.bp.word = chan->cookieHigh;
+ bphb.in.dstAddr = chan->cookieLow;
+ bphb.in.size = myBufSize;
+ bphb.in.srcAddr = (uintptr_t) myBuf;
+ Backdoor_HbOut(&bphb);
+ if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
+ /* A checkpoint occurred. Retry the operation. --hpreg */
+ goto retry;
+ }
+
+ MESSAGE_LOG(("Message: Unable to send a message over the "
+ "communication channel %u\n", chan->id));
+ return FALSE;
+ }
+ }
+ } else {
+ /*
+ * High-bandwidth backdoor port not supported. Send the message, 4 bytes
+ * at a time. --hpreg
+ */
+
+ for (;;) {
+ if (myBufSize == 0) {
+ /* We are done */
+ break;
+ }
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_SENDPAYLOAD;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+ /* IN: Piece of message */
+ /*
+ * Beware in case we are not allowed to read extra bytes beyond the
+ * end of the buffer.
+ */
+ switch (myBufSize) {
+ case 1:
+ bp.in.size = myBuf[0];
+ myBufSize -= 1;
+ break;
+ case 2:
+ bp.in.size = myBuf[0] | myBuf[1] << 8;
+ myBufSize -= 2;
+ break;
+ case 3:
+ bp.in.size = myBuf[0] | myBuf[1] << 8 | myBuf[2] << 16;
+ myBufSize -= 3;
+ break;
+ default:
+ bp.in.size = *(const uint32 *)myBuf;
+ myBufSize -= 4;
+ break;
+ }
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
+ /* A checkpoint occurred. Retry the operation. --hpreg */
+ goto retry;
+ }
+
+ MESSAGE_LOG(("Message: Unable to send a message over the "
+ "communication channel %u\n", chan->id));
+ return FALSE;
+ }
+
+ myBuf += 4;
+ }
+ }
+
+ MESSAGE_LOG(("Message: Sent a message over the communication channel %u\n",
+ chan->id));
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MessageBackdoor_Receive --
+ *
+ * If vmware has posted a message for this channel, retrieve it
+ *
+ * Result:
+ * TRUE on success (bufSize is 0 if there is no message)
+ * FALSE on failure
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+MessageBackdoor_Receive(Message_Channel *chan, // IN/OUT
+ unsigned char **buf, // OUT
+ size_t *bufSize) // OUT
+{
+ Backdoor_proto bp;
+ size_t myBufSize;
+ unsigned char *myBuf;
+
+retry:
+ /*
+ * Is there a message waiting for our retrieval?
+ */
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_RECVSIZE;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ MESSAGE_LOG(("Message: Unable to poll for messages over the "
+ "communication channel %u\n", chan->id));
+ return FALSE;
+ }
+
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_DORECV) == 0) {
+ /* No message to retrieve */
+ *bufSize = 0;
+ return TRUE;
+ }
+
+ /*
+ * Receive the size.
+ */
+
+ /* OUT: Type */
+ if (bp.in.dx.halfs.high != MESSAGE_TYPE_SENDSIZE) {
+ MESSAGE_LOG(("Message: Protocol error. Expected a "
+ "MESSAGE_TYPE_SENDSIZE request from vmware\n"));
+ return FALSE;
+ }
+
+ /* OUT: Size */
+ myBufSize = bp.out.bx.word;
+
+ /*
+ * Allocate an extra byte for a trailing NUL character. The code that will
+ * deal with this message may not know about binary strings, and may expect
+ * a C string instead. --hpreg
+ */
+ if (myBufSize + 1 > chan->inAlloc) {
+ myBuf = (unsigned char *)realloc(chan->in, myBufSize + 1);
+ if (myBuf == NULL) {
+ MESSAGE_LOG(("Message: Not enough memory to receive a message over "
+ "the communication channel %u\n", chan->id));
+ goto error_quit;
+ }
+
+ chan->in = myBuf;
+ chan->inAlloc = myBufSize + 1;
+ }
+ *bufSize = myBufSize;
+ myBuf = *buf = chan->in;
+
+ if (bp.in.cx.halfs.high & MESSAGE_STATUS_HB) {
+ /*
+ * High-bandwidth backdoor port supported. Receive the message in one
+ * backdoor operation. --hpreg
+ */
+
+ if (myBufSize) {
+ Backdoor_proto_hb bphb;
+
+ bphb.in.bx.halfs.low = BDOORHB_CMD_MESSAGE;
+ bphb.in.bx.halfs.high = MESSAGE_STATUS_SUCCESS;
+ bphb.in.dx.halfs.high = chan->id;
+ bphb.in.srcAddr = chan->cookieHigh;
+ bphb.in.bp.word = chan->cookieLow;
+ bphb.in.size = myBufSize;
+ bphb.in.dstAddr = (uintptr_t) myBuf;
+ Backdoor_HbIn(&bphb);
+ if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
+ /* A checkpoint occurred. Retry the operation. --hpreg */
+ goto retry;
+ }
+
+ MESSAGE_LOG(("Message: Unable to receive a message over the "
+ "communication channel %u\n", chan->id));
+ goto error_quit;
+ }
+ }
+ } else {
+ /*
+ * High-bandwidth backdoor port not supported. Receive the message, 4
+ * bytes at a time. --hpreg
+ */
+
+ for (;;) {
+ if (myBufSize == 0) {
+ /* We are done */
+ break;
+ }
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_RECVPAYLOAD;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+ /* IN: Status for the previous request (that succeeded) */
+ bp.in.size = MESSAGE_STATUS_SUCCESS;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
+ /* A checkpoint occurred. Retry the operation. --hpreg */
+ goto retry;
+ }
+
+ MESSAGE_LOG(("Message: Unable to receive a message over the "
+ "communication channel %u\n", chan->id));
+ goto error_quit;
+ }
+
+ /* OUT: Type */
+ if (bp.in.dx.halfs.high != MESSAGE_TYPE_SENDPAYLOAD) {
+ MESSAGE_LOG(("Message: Protocol error. Expected a "
+ "MESSAGE_TYPE_SENDPAYLOAD from vmware\n"));
+ goto error_quit;
+ }
+
+ /* OUT: Piece of message */
+ /*
+ * Beware in case we are not allowed to write extra bytes beyond the
+ * end of the buffer. --hpreg
+ */
+ switch (myBufSize) {
+ case 1:
+ myBuf[0] = bp.out.bx.word & 0xff;
+ myBufSize -= 1;
+ break;
+ case 2:
+ myBuf[0] = bp.out.bx.word & 0xff;
+ myBuf[1] = (bp.out.bx.word >> 8) & 0xff;
+ myBufSize -= 2;
+ break;
+ case 3:
+ myBuf[0] = bp.out.bx.word & 0xff;
+ myBuf[1] = (bp.out.bx.word >> 8) & 0xff;
+ myBuf[2] = (bp.out.bx.word >> 16) & 0xff;
+ myBufSize -= 3;
+ break;
+ default:
+ *(uint32 *)myBuf = bp.out.bx.word;
+ myBufSize -= 4;
+ break;
+ }
+
+ myBuf += 4;
+ }
+ }
+
+ /* Write a trailing NUL just after the message. --hpreg */
+ chan->in[*bufSize] = '\0';
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_RECVSTATUS;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+ /* IN: Status for the previous request (that succeeded) */
+ bp.in.size = MESSAGE_STATUS_SUCCESS;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
+ /* A checkpoint occurred. Retry the operation. --hpreg */
+ goto retry;
+ }
+
+ MESSAGE_LOG(("Message: Unable to receive a message over the "
+ "communication channel %u\n", chan->id));
+ goto error_quit;
+ }
+
+ return TRUE;
+
+error_quit:
+ /* IN: Type */
+ if (myBufSize == 0) {
+ bp.in.cx.halfs.high = MESSAGE_TYPE_RECVSTATUS;
+ } else {
+ bp.in.cx.halfs.high = MESSAGE_TYPE_RECVPAYLOAD;
+ }
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+ /* IN: Status for the previous request (that failed) */
+ bp.in.size = 0;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ MESSAGE_LOG(("Message: Unable to signal an error of reception over the "
+ "communication channel %u\n", chan->id));
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MessageBackdoor_Close --
+ *
+ * Close a communication channel
+ *
+ * Result:
+ * TRUE on success, the channel is destroyed
+ * FALSE on failure
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+MessageBackdoor_Close(Message_Channel *chan) // IN/OUT
+{
+ Backdoor_proto bp;
+ Bool ret = TRUE;
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_CLOSE;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ MESSAGE_LOG(("Message: Unable to close the communication channel %u\n",
+ chan->id));
+ ret = FALSE;
+ } else {
+ MESSAGE_LOG(("Message: Communication channel %u closed\n", chan->id));
+ }
+
+ free(chan->in);
+ chan->in = NULL;
+
+ free(chan);
+ return ret;
+}
+
+#ifdef __cplusplus
+}
+#endif
* For reference: Solaris Structures
* =================================
*
- * Driver module struct hierarchy:
- * -------------------------------
- *
- * (Solaris 9 & 10)
- *
- * modlinkage --> modldrv --> dev_ops --> cb_ops
- *
- * - modlinkage & modldrv: module loading/unloading
- * - dev_ops: operations for driver configuration (attach(), detach(), etc)
- * - cb_ops: operations on device, entry points to character device (open(),
- * close(), etc)
- *
- *
* VFS module struct hierarchy:
* ----------------------------
*
*
* (Build 58 contains the same structure named vfsdev_v3)
*
- *
- * Combination:
- * ------------
- *
- * In this file we are placing both modldrv and modlfs inside one modlinkage
- * structure. This is achieved by placing pointers to both of these structures
- * in modlinkage's ml_linkage arary of pointers to module structures. This is
- * done so the two modules can have shared state and to prevent dependency
- * issues between them. This looks like:
- *
- * modlinkage --> modldrv --> as above
- * \
- * -> modlfs --> as above
- *
*/
#include "hgfsSolaris.h"
#include "module.h"
+#include "vnode.h"
+#include "filesystem.h"
#include "debug.h"
#define HGFS_VFSSW_FLAGS 0
-/*
- * Structures
- */
-
-/*
- * Device driver structures
- */
-
-/* Structure defining operations on device */
-static struct cb_ops HgfsDevCBOps = {
- HgfsDevOpen, /* open(9E) */
- HgfsDevClose, /* close(9E) */
- nodev, /* strategy(9E) */
- nodev, /* print(9E) */
- nodev, /* dump(9E) */
- HgfsDevRead, /* read(9E) */
- HgfsDevWrite, /* write(9E) */
- nodev, /* ioctl(9E) */
- nodev, /* devmap(9E) */
- nodev, /* mmap(9E) */
- nodev, /* segmap(9E) */
- HgfsDevChpoll, /* chpoll(9E) */
- ddi_prop_op, /* prop_op(9E) */
- NULL, /* streamtab(9S) */
- (D_NEW | D_MP), /* cb_flag: D_NEW because this is a new-style
- driver and D_MP is required */
- CB_REV, /* cb_rev */
- nodev, /* aread(9E) */
- nodev, /* awrite(9E) */
-};
-
-
-/* Structure defining operations for driver */
-static struct dev_ops HgfsDevOps = {
- DEVO_REV, /* devo_rev */
- 0, /* devo_refcnt */
- HgfsDevGetinfo, /* getinfo(9E) */
- nulldev, /* identify(9E) */
- nulldev, /* probe(9E) */
- HgfsDevAttach, /* attach(9E) */
- HgfsDevDetach, /* detach(9E) */
- nodev, /* devo_reset */
- &HgfsDevCBOps, /* devo_cb_ops (points to struct cb_ops) */
- NULL, /* devo_bus_ops */
- NULL /* power(9E) */
-};
-
-
-/* Driver module linkage structure */
-static struct modldrv HgfsDevModldrv = {
- &mod_driverops, /* drv_modops (don't change) */
- "HGFS Device Interface", /* drv_linkinfo */
- &HgfsDevOps /* drv_dev_ops (points to struct dev_ops) */
-};
-
-
-
/*
* Filesystem structures
*/
/*
- * Modlinkage shared by device driver and filesystem.
+ * Modlinkage containing filesystem.
*/
static struct modlinkage HgfsModlinkage = {
MODREV_1, /* Module revision: must be MODREV_1 */
- /*
- * We put pointers to /both/ modules in the following NULL terminated array
- * of pointers (ml_linkage[]). This is what causes both modules to be
- * loaded into the kernel when the single driver is added.
- */
{
- &HgfsDevModldrv, /* Driver module structure */
&HgfsModlfs, /* FS module structure */
NULL, /* NULL terminator */
}
DEBUG(VM_DEBUG_ENTRY, "_init() for HGFS.\n");
- /*
- * Initialize hgfsInstance so filesystem knows device has not been attached
- * yet, and hgfsType so we know whether to free the vfsops in _fini().
- */
- hgfsInstance = HGFS_INSTANCE_UNINITIALIZED;
- hgfsType = HGFS_TYPE_UNINITIALIZED;
-
- /*
- * For reference:
- *
- * Solaris provides an interface to simplify allocation and deallocation of
- * per-driver-instance state through the DDI Soft State functions.
- *
- * - ddi_soft_state_init() takes a double pointer and uses it as a handle
- * to access the various per-instance state structures. This handle will
- * be passed to the other DDI Soft State functions to indicate which
- * state list to operate on. The second argument is the amount of memory
- * to allocate for each state structure, and the last is the expected number
- * of instances of the driver (number of state structures).
- *
- * - ddi_soft_state_zalloc() and ddi_soft_state_free() allocate and free a
- * soft state structure respectively. The first argument is the
- * handle pointer (see above) and the second is the item number
- * associated with this instance.
- *
- * - ddi_get_soft_state_free() takes a handle and item and returns a
- * pointer to the state structure that was allocated with
- * ddi_soft_state_zalloc() for that item number.
- *
- * See man ddi_soft_state_init for more information.
- *
- */
- ret = ddi_soft_state_init(&superInfoHead,
- sizeof (HgfsSuperInfo), HGFS_EXPECTED_INSTANCES);
- if (ret) {
- goto error;
- }
-
ret = mod_install(&HgfsModlinkage);
if (ret) {
- goto error;
+ cmn_err(HGFS_ERROR, "could not install HGFS module.\n");
+ return ret;
}
DEBUG(VM_DEBUG_DONE, "_init() done.\n");
return 0;
-
-error:
- cmn_err(HGFS_ERROR, "could not install HGFS module.\n");
- ddi_soft_state_fini(&superInfoHead);
- return ret;
}
int
_fini(void)
{
- HgfsSuperInfo *sip;
int error;
DEBUG(VM_DEBUG_ENTRY, "_fini() for HGFS.\n");
- sip = ddi_get_soft_state(superInfoHead, hgfsInstance);
-
/*
- * Make sure the device is closed and the fs is not mounted if we have
- * a valid superinfo pointer.
+ * Make sure that the fs is not mounted.
*/
- if (sip && (sip->devOpen || sip->vfsp)) {
- DEBUG(VM_DEBUG_FAIL, "Cannot unload module because either device"
- "is open or file system is mounted\n");
- return -1;
+ if (HgfsGetSuperInfo()) {
+ DEBUG(VM_DEBUG_FAIL,
+ "Cannot unload module because file system is mounted\n");
+ return EBUSY;
}
error = mod_remove(&HgfsModlinkage);
return error;
}
-#if HGFS_VFS_VERSION > 2
- if (hgfsType != HGFS_TYPE_UNINITIALIZED) {
- vfs_freevfsops_by_type(hgfsType);
- }
- if (sip && sip->vnodeOps) {
- vn_freevnodeops(sip->vnodeOps);
- }
-#endif
- ddi_soft_state_fini(&superInfoHead); /* void return */
+ HgfsFreeVnodeOps();
+ HgfsFreeVfsOps();
DEBUG(VM_DEBUG_DONE, "_fini() done.\n");
return 0;
#include "filesystem.h"
-/*
- * Device driver EXTERNs
- */
-
-/* Functions for the cb_ops structure (see driver.c) */
-EXTERN int HgfsDevOpen(dev_t *devp, int flag, int otyp, cred_t *credp);
-EXTERN int HgfsDevClose(dev_t dev, int flag, int otyp, cred_t *credp);
-EXTERN int HgfsDevRead(dev_t dev, uio_t *uiop, cred_t *credp);
-EXTERN int HgfsDevWrite(dev_t dev, uio_t *uiop, cred_t *credp);
-EXTERN int HgfsDevChpoll(dev_t dev, short int events, int anyyet,
- short int *reventsp, struct pollhead **phpp);
-
-/* Functions for the dev_ops structure (see driver.c) */
-EXTERN int HgfsDevGetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
- void *arg, void **result);
-EXTERN int HgfsDevAttach(dev_info_t *dip, ddi_attach_cmd_t cmd);
-EXTERN int HgfsDevDetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
-
-/* Struct needed in struct modldrv */
-EXTERN struct mod_ops mod_driverops;
-
-
/*
* Filesystem EXTERNs
*/
DEBUG(VM_DEBUG_REQUEST, "HgfsInitRequestList().\n");
ASSERT(sip);
- /*
- * We ASSERT() this because this function must be called before the device is
- * opened to ensure the request lists are ready to be used by the
- * filesystem. (The filesystem won't mount unless the device is open.)
- * By ASSERT()ing this condition we also obviate the need to acquire the
- * mutex when adding requests to reqFreeList in the for loop below, since we
- * are guaranteed (in practice) to have exclusive access.
- */
- ASSERT(!sip->devOpen);
- /* None of these fail */
-
- /* Initialize pending request list */
- DblLnkLst_Init(&sip->reqList);
mutex_init(&sip->reqMutex, NULL, MUTEX_DRIVER, NULL);
- cv_init(&sip->reqCondVar, NULL, CV_DRIVER, NULL);
/* Initialize free request list */
DblLnkLst_Init(&sip->reqFreeList);
for (i = 0; i < ARRAYSIZE(requestPool); i++) {
requestPool[i].id = i;
requestPool[i].state = HGFS_REQ_UNUSED;
- mutex_init(&requestPool[i].stateLock, NULL, MUTEX_DRIVER, NULL);
DblLnkLst_Init(&requestPool[i].listNode);
DblLnkLst_LinkLast(&sip->reqFreeList, &requestPool[i].listNode);
*
* HgfsCancelAllRequests --
*
- * Cancels all pending requests by removing them from the request list and
- * waking up the clients waiting for replies. Also cancels requests that
- * have already been sent to guestd (and are not on the pending list) and
- * are either abandoned or still have clients waiting for them.
+ * Cancels all pending (SUBMITTED) requests by signalling the transport
+ * code that they should be aborted.
*
* Results:
* None.
*
* Side effects:
- * The pending request list is empty and all requests are in the free list.
+ * Threads waiting on requests are woken up with error conditions.
*
*----------------------------------------------------------------------------
*/
HgfsCancelAllRequests(HgfsSuperInfo *sip) // IN: Superinfo containing
// request list
{
- DblLnkLst_Links *currNode, *nextNode;
- HgfsReq *currRequest;
int i;
DEBUG(VM_DEBUG_REQUEST, "HgfsCancelAllRequests().\n");
ASSERT(sip);
+ ASSERT(mutex_owned(&sip->reqMutex));
- /* Traverse list to make sure we cancel all pending requests on the list. */
- mutex_enter(&sip->reqMutex);
-
- DEBUG(VM_DEBUG_REQUEST, "HgfsCancelAllRequests(): traversing pending request list.\n");
-
- for (currNode = HGFS_REQ_LIST_HEAD_NODE(sip);
- currNode != &sip->reqList;
- currNode = nextNode) {
-
- /* Get the next element while we still have a pointer to it. */
- nextNode = currNode->next;
-
- DblLnkLst_Unlink1(currNode);
- currRequest = DblLnkLst_Container(currNode, HgfsReq, listNode);
-
- if (HgfsReqGetState(currRequest) == HGFS_REQ_ABANDONED) {
- /*
- * If the client is no longer waiting, clean up for it by destroying
- * the request.
- */
- HgfsDestroyReq(sip, currRequest);
- } else {
- /*
- * ... otherwise indicate an error and wakeup the client. Note that
- * we can't call HgfsWakeWaitingClient() because we already hold the
- * reqMutex lock.
- *
- * Also, make sure that all non-ABANDONED requests are SUBMITTED.
- */
- ASSERT(HgfsReqGetState(currRequest) == HGFS_REQ_SUBMITTED);
-
- HgfsReqSetState(currRequest, HGFS_REQ_ERROR);
- cv_signal(&currRequest->condVar);
- }
- }
-
- DEBUG(VM_DEBUG_REQUEST, "HgfsCancelAllRequests(): traversing request pool.\n");
-
- /*
- * Now look for abandoned and submitted requests that are in the pool but
- * not on the pending list (because they were already sent to guestd).
- */
for (i = 0; i < ARRAYSIZE(requestPool); i++) {
/*
- * As above, abandoned requests are cleaned up and we wake up the clients
- * for submitted requests.
+ * Signal that all submitted requests need to be cancelled.
+ * We expect that transport implementation wakes up processes
+ * waiting on requests
*/
- if (HgfsReqGetState(&requestPool[i]) == HGFS_REQ_ABANDONED) {
- HgfsDestroyReq(sip, &requestPool[i]);
- } else if (HgfsReqGetState(&requestPool[i]) == HGFS_REQ_SUBMITTED) {
- HgfsReqSetState(&requestPool[i], HGFS_REQ_ERROR);
- cv_signal(&requestPool[i].condVar);
- }
+ if (requestPool[i].state == HGFS_REQ_SUBMITTED)
+ sip->cancelRequest(&requestPool[i]);
}
- mutex_exit(&sip->reqMutex);
-
DEBUG(VM_DEBUG_REQUEST, "HgfsCancelAllRequests() done.\n");
}
HgfsDebugPrintReq("HgfsGetNewReq", newReq);
/* Failure of these indicates error in program's logic */
- ASSERT(newReq && (HgfsReqGetState(newReq) == HGFS_REQ_UNUSED));
+ ASSERT(newReq && newReq->state == HGFS_REQ_UNUSED);
/* Take request off the free list and indicate it has been ALLOCATED */
DblLnkLst_Unlink1(&newReq->listNode);
- HgfsReqSetState(newReq, HGFS_REQ_ALLOCATED);
+ newReq->state = HGFS_REQ_ALLOCATED;
/* Clear packet of request before allocating to clients. */
bzero(newReq->packet, sizeof newReq->packet);
+ DEBUG(VM_DEBUG_LIST, "Dequeued from free list: %s", newReq->packet);
+ HgfsDebugPrintReqList(&sip->reqFreeList);
+
out:
mutex_exit(&sip->reqFreeMutex);
- DEBUG(VM_DEBUG_LIST, "Dequeued from free list: %s", newReq->packet);
- HgfsDebugPrintReqList(&sip->reqFreeList);
DEBUG(VM_DEBUG_REQUEST, "HgfsGetNewReq() done.\n");
-
return newReq;
}
*----------------------------------------------------------------------------
*/
-INLINE void
+void
HgfsDestroyReq(HgfsSuperInfo *sip, // IN: Superinfo containing free list
HgfsReq *oldReq) // IN: Request to destroy
{
DEBUG(VM_DEBUG_ENTRY, "HgfsDestroyReq().\n");
/* XXX This should go away later, just for testing */
- if (HgfsReqGetState(oldReq) != HGFS_REQ_COMPLETED) {
+ if (oldReq->state != HGFS_REQ_COMPLETED) {
DEBUG(VM_DEBUG_ALWAYS, "HgfsDestroyReq() (oldReq state=%d).\n",
- HgfsReqGetState(oldReq));
+ oldReq->state);
}
ASSERT(sip);
ASSERT(oldReq);
/* Failure of this check indicates an error in program logic */
- ASSERT((HgfsReqGetState(oldReq) == HGFS_REQ_COMPLETED) ||
- (HgfsReqGetState(oldReq) == HGFS_REQ_ABANDONED) ||
- (HgfsReqGetState(oldReq) == HGFS_REQ_ERROR));
+ ASSERT(oldReq->state == HGFS_REQ_COMPLETED ||
+ oldReq->state == HGFS_REQ_ABANDONED ||
+ oldReq->state == HGFS_REQ_ERROR);
/*
* To make the request available for other clients we change its state to
*/
mutex_enter(&sip->reqFreeMutex);
- HgfsReqSetState(oldReq, HGFS_REQ_UNUSED);
+ oldReq->state = HGFS_REQ_UNUSED;
DblLnkLst_LinkLast(&sip->reqFreeList, &oldReq->listNode);
/* Wake up clients waiting for a request structure */
cv_signal(&sip->reqFreeCondVar);
/*
*----------------------------------------------------------------------------
*
- * HgfsEnqueueRequest --
+ * HgfsSendRequest --
*
- * Adds the provided request to the end of the request list.
+ * Sends request for execution. The exact details depend on transport used
+ * to communicate with the host.
*
* Note: this assumes it is called with the list lock held because often
* callers will need this function to be atomic with other operations.
*----------------------------------------------------------------------------
*/
-INLINE void
-HgfsEnqueueRequest(HgfsSuperInfo *sip, // IN: Superinfo containing request list
- HgfsReq *newReq) // IN: Request to enqueue
+int
+HgfsSendRequest(HgfsSuperInfo *sip, // IN: Superinfo sructure with methods
+ HgfsReq *req) // IN/OUT: Request to be sent
{
- DEBUG(VM_DEBUG_REQUEST, "HgfsEnqueueRequest().\n");
+ int ret;
ASSERT(sip);
- ASSERT(newReq);
+ ASSERT(req);
/* Failure of this check indicates error in program logic */
- ASSERT(HgfsReqGetState(newReq) == HGFS_REQ_ALLOCATED);
-
- /*
- * This simply changes the state and places the request on the pending
- * request list. Signaling the (potentially sleeping) device is handled by
- * the caller (HgfsSubmitRequest()).
- */
- HgfsReqSetState(newReq, HGFS_REQ_SUBMITTED);
- DblLnkLst_LinkLast(&sip->reqList, &newReq->listNode);
-
- DEBUG(VM_DEBUG_LIST, "Enqueued on pending list: %s", newReq->packet);
- HgfsDebugPrintReqList(&sip->reqList);
- DEBUG(VM_DEBUG_REQUEST, "HgfsEnqueueRequest() done.\n");
-}
+ ASSERT(req->state == HGFS_REQ_ALLOCATED);
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsDequeueRequest --
- *
- * Removes the next request from the list.
- *
- * Note: this assumes it is called with the list lock held because often
- * callers will need this function to be atomic with other operations.
- *
- * Results:
- * Returns a pointer to the request removed from the list, or NULL if the
- * list is empty.
- *
- * Side effects:
- * Request is removed from the pending request list.
- *
- *
- *----------------------------------------------------------------------------
- */
-
-INLINE HgfsReq *
-HgfsDequeueRequest(HgfsSuperInfo *sip) // IN: Superinfo containing request list
-{
- HgfsReq *nextReq;
-
- DEBUG(VM_DEBUG_REQUEST, "HgfsDequeueRequest().\n");
-
- ASSERT(sip);
-
- if (HgfsListIsEmpty(&sip->reqList)) {
- return NULL;
+ req->state = HGFS_REQ_SUBMITTED;
+ ret = sip->sendRequest(req);
+ if (ret) {
+ req->state = HGFS_REQ_ERROR;
}
- nextReq = HGFS_REQ_LIST_HEAD(sip);
-
- /*
- * nextReq should never be NULL since we are called with the lock held and
- * we just checked if the list was empty. The request's state should only
- * be SUBMITTED or ABANDONED. (Errors occurring while copying the request
- * to guestd happen after removal from this list.)
- */
- ASSERT(nextReq);
- ASSERT(HgfsReqGetState(nextReq) == HGFS_REQ_SUBMITTED ||
- HgfsReqGetState(nextReq) == HGFS_REQ_ABANDONED);
-
- DblLnkLst_Unlink1(&nextReq->listNode);
-
- DEBUG(VM_DEBUG_LIST, "Dequeued from pending list: %s", nextReq->packet);
- HgfsDebugPrintReqList(&sip->reqList);
- DEBUG(VM_DEBUG_REQUEST, "HgfsDequeueRequest() done.\n");
-
- return nextReq;
+ return ret;
}
// DEBUG(VM_DEBUG_REQUEST, "HgfsWakeWaitingClient() done.\n");
}
-
-/*
- * These two state functions will help prevent forgetting to lock.
- */
-
-
-/*
- *----------------------------------------------------------------------------
- * HgfsSetState --
- *
- * Sets the state of the request.
- *
- * Results:
- * Returns void.
- *
- * Side effects:
- * The state of the request is modified.
- *
- *----------------------------------------------------------------------------
- */
-
-INLINE void
-HgfsReqSetState(HgfsReq *req, // IN: Request to alter state of
- HgfsReqState state) // IN: State to set request to
-{
-// DEBUG(VM_DEBUG_REQUEST, "HgfsReqSetState().\n");
-
- ASSERT(req);
-
- mutex_enter(&req->stateLock);
-
- req->state = state;
-
- mutex_exit(&req->stateLock);
-
-// DEBUG(VM_DEBUG_REQUEST, "HgfsReqSetState() done.\n");
-}
-
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsReqGetState --
- *
- * Retrieves state of provided request.
- *
- * Results:
- * Returns state of request.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-INLINE HgfsReqState
-HgfsReqGetState(HgfsReq *req) // IN: Request to retrieve state of
-{
- HgfsReqState state;
-
- DEBUG(VM_DEBUG_REQUEST, "HgfsReqGetState().\n");
-
- ASSERT(req);
-
- mutex_enter(&req->stateLock);
-
- state = req->state;
-
- mutex_exit(&req->stateLock);
-
- DEBUG(VM_DEBUG_REQUEST, "HgfsReqGetState() done.\n");
- return state;
-}
void HgfsCancelAllRequests(HgfsSuperInfo *sip);
INLINE Bool HgfsListIsEmpty(DblLnkLst_Links *listAnchor);
HgfsReq *HgfsGetNewReq(HgfsSuperInfo *sip);
-INLINE void HgfsDestroyReq(HgfsSuperInfo *sip, HgfsReq *oldReq);
-INLINE void HgfsEnqueueRequest(HgfsSuperInfo *sip, HgfsReq *newReq);
-INLINE HgfsReq *HgfsDequeueRequest(HgfsSuperInfo *sip);
+void HgfsDestroyReq(HgfsSuperInfo *sip, HgfsReq *oldReq);
+int HgfsSendRequest(HgfsSuperInfo *sip, HgfsReq *req);
INLINE void HgfsWakeWaitingClient(HgfsSuperInfo *sip, HgfsReq *req);
-INLINE void HgfsReqSetState(HgfsReq *req, HgfsReqState state);
-INLINE HgfsReqState HgfsReqGetState(HgfsReq *req);
#endif /* __REQUEST_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * rpcout.c --
+ *
+ * Remote Procedure Call between VMware and guest applications
+ * C implementation.
+ *
+ * This module contains implements the out (guest=>host) direction only.
+ * The in and out modules are separate since some applications (e.g.
+ * drivers that want to do RPC-based logging) only want/need/can have the
+ * out direction.
+ */
+
+
+#if defined(__KERNEL__) || defined(_KERNEL) || defined(KERNEL)
+# include "kernelStubs.h"
+#else
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+# include <stdarg.h>
+# include "str.h"
+# include "debug.h"
+#endif
+
+#include "vmware.h"
+#include "rpcout.h"
+#include "message.h"
+
+
+/*
+ * The RpcOut object
+ */
+
+struct RpcOut {
+ Message_Channel *channel;
+};
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * RpcOut_Construct --
+ *
+ * Constructor for the RpcOut object
+ *
+ * Results:
+ * New RpcOut object.
+ *
+ * Side effects:
+ * Allocates memory.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+RpcOut *
+RpcOut_Construct(void)
+{
+ return (RpcOut *)calloc(1, sizeof(RpcOut));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * RpcOut_Destruct --
+ *
+ * Destructor for the RpcOut object.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Frees RpcOut object memory.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+RpcOut_Destruct(RpcOut *out) // IN
+{
+ ASSERT(out);
+ ASSERT(out->channel == NULL);
+
+ free(out);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * RpcOut_start --
+ *
+ * Open the channel
+ *
+ * Result:
+ * TRUE on success
+ * FALSE on failure
+ *
+ * Side-effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+RpcOut_start(RpcOut *out) // IN
+{
+ ASSERT(out);
+ ASSERT(out->channel == NULL);
+ out->channel = Message_Open(RPCI_PROTOCOL_NUM);
+ if (out->channel == NULL) {
+ Debug("RpcOut: couldn't open channel with RPCI protocol\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * RpcOut_send --
+ *
+ * Make VMware synchroneously execute a TCLO command
+ *
+ * Unlike the other send varieties, RpcOut_send requires that the
+ * caller pass non-NULL reply and repLen arguments.
+ *
+ * Result
+ * TRUE on success. 'reply' contains the result of the rpc
+ * FALSE on error. 'reply' will contain a description of the error
+ *
+ * In both cases, the caller should not free the reply.
+ *
+ * Side-effects
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+RpcOut_send(RpcOut *out, // IN
+ char const *request, // IN
+ size_t reqLen, // IN
+ char const **reply, // OUT
+ size_t *repLen) // OUT
+{
+ unsigned char *myReply;
+ size_t myRepLen;
+ Bool success;
+
+ ASSERT(out);
+
+ ASSERT(out->channel);
+ if (Message_Send(out->channel, (const unsigned char *)request, reqLen) == FALSE) {
+ *reply = "RpcOut: Unable to send the RPCI command";
+ *repLen = strlen(*reply);
+
+ return FALSE;
+ }
+
+ if (Message_Receive(out->channel, &myReply, &myRepLen) == FALSE) {
+ *reply = "RpcOut: Unable to receive the result of the RPCI command";
+ *repLen = strlen(*reply);
+
+ return FALSE;
+ }
+
+ if (myRepLen < 2
+ || ( (success = strncmp((const char *)myReply, "1 ", 2) == 0) == FALSE
+ && strncmp((const char *)myReply, "0 ", 2))) {
+ *reply = "RpcOut: Invalid format for the result of the RPCI command";
+ *repLen = strlen(*reply);
+
+ return FALSE;
+ }
+
+ *reply = ((const char *)myReply) + 2;
+ *repLen = myRepLen - 2;
+
+ return success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * RpcOut_stop --
+ *
+ * Close the channel
+ *
+ * Result
+ * TRUE on success
+ * FALSE on failure
+ *
+ * Side-effects
+ * Frees the result of the last command.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+RpcOut_stop(RpcOut *out) // IN
+{
+ Bool status;
+
+ ASSERT(out);
+
+ status = TRUE;
+
+ if (out->channel) {
+ /* Try to close the channel */
+ if (Message_Close(out->channel) == FALSE) {
+ Debug("RpcOut: couldn't close channel\n");
+ status = FALSE;
+ }
+
+ out->channel = NULL;
+ }
+
+ return status;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * RpcOut_sendOne --
+ *
+ * Make VMware execute a RPCI command
+ *
+ * VMware closes a channel when it detects that there has been no activity
+ * on it for a while. Because we do not know how often this program will
+ * make VMware execute a RPCI, we open/close one channel per RPCI command
+ *
+ * Return value:
+ * TRUE on success. '*reply' contains an allocated result of the rpc
+ * FALSE on error. '*reply' contains an allocated description of the error
+ * or NULL.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+RpcOut_sendOne(char **reply, // OUT: Result
+ size_t *repLen, // OUT: Length of the result
+ char const *reqFmt, // IN: RPCI command
+ ...) // Unspecified
+{
+ va_list args;
+ Bool status;
+ char *request;
+ size_t reqLen = 0;
+
+ status = FALSE;
+
+ /* Format the request string */
+ va_start(args, reqFmt);
+ request = Str_Vasprintf(&reqLen, reqFmt, args);
+ va_end(args);
+
+ /*
+ * If Str_Vasprintf failed, write NULL into the reply if the caller wanted
+ * a reply back.
+ */
+ if (request == NULL) {
+ if (reply) {
+ *reply = NULL;
+ }
+ return FALSE;
+ }
+
+ /*
+ * If the command doesn't contain a space, add one to the end to maintain
+ * compatibility with old VMXs.
+ *
+ * For a long time, the GuestRpc logic in the VMX was wired to expect a
+ * trailing space in every command, even commands without arguments. That is
+ * no longer true, but we must continue to add a trailing space because we
+ * don't know whether we're talking to an old or new VMX.
+ */
+ if (strchr(request, ' ') == NULL) {
+ char *tmp;
+
+ tmp = Str_Asprintf(NULL, "%s ", request);
+ free(request);
+ request = tmp;
+
+ /*
+ * If Str_Asprintf failed, write NULL into reply if the caller wanted
+ * a reply back.
+ */
+ if (request == NULL) {
+ if (reply != NULL) {
+ *reply = NULL;
+ }
+ return FALSE;
+ }
+ }
+
+ status = RpcOut_SendOneRaw(request, reqLen, reply, repLen);
+
+ free(request);
+
+ return status;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * RpcOut_SendOneRaw --
+ *
+ * Make VMware execute a RPCI command
+ *
+ * VMware closes a channel when it detects that there has been no activity
+ * on it for a while. Because we do not know how often this program will
+ * make VMware execute a RPCI, we open/close one channel per RPCI command.
+ *
+ * This function sends a message over the backdoor without using
+ * any of the Str_ functions on the request buffer; Str_Asprintf() in
+ * particular uses FormatMessage on Win32, which corrupts some UTF-8
+ * strings. Using this function directly instead of using RpcOut_SendOne()
+ * avoids these problems.
+ *
+ * If this is not an issue, you can use RpcOut_sendOne(), which has
+ * varargs.
+ *
+ * Note: It is the caller's responsibility to ensure that the RPCI command
+ * followed by a space appear at the start of the request buffer. See
+ * the command in RpcOut_sendOne for details.
+ *
+ * Return value:
+ * TRUE on success. '*reply' contains an allocated result of the rpc
+ * FALSE on error. '*reply' contains an allocated description of the
+ * error or NULL.
+ *
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+RpcOut_SendOneRaw(void *request, // IN: RPCI command
+ size_t reqLen, // IN: Size of request buffer
+ char **reply, // OUT: Result
+ size_t *repLen) // OUT: Length of the result
+{
+ Bool status;
+ RpcOut *out = NULL;
+ char const *myReply;
+ size_t myRepLen;
+
+ status = FALSE;
+
+ Debug("Rpci: Sending request='%s'\n", (char *)request);
+ out = RpcOut_Construct();
+ if (out == NULL) {
+ myReply = "RpcOut: Unable to create the RpcOut object";
+ myRepLen = strlen(myReply);
+
+ goto sent;
+ } else if (RpcOut_start(out) == FALSE) {
+ myReply = "RpcOut: Unable to open the communication channel";
+ myRepLen = strlen(myReply);
+
+ goto sent;
+ } else if (RpcOut_send(out, request, reqLen, &myReply, &myRepLen)
+ == FALSE) {
+ /* We already have the description of the error */
+ goto sent;
+ }
+
+ status = TRUE;
+
+sent:
+ Debug("Rpci: Sent request='%s', reply='%s', len=%"FMTSZ"u, status=%d\n",
+ (char *)request, myReply, myRepLen, status);
+
+ if (reply != NULL) {
+ /*
+ * If we got a non-NULL reply, make a copy of it, because the reply
+ * we got back is inside the channel buffer, which will get destroyed
+ * at the end of this function.
+ */
+ if (myReply != NULL) {
+ /*
+ * We previously used strdup to duplicate myReply, but that
+ * breaks if you are sending binary (not string) data over the
+ * backdoor. Don't assume the data is a string.
+ *
+ * myRepLen is strlen(myReply), so we need an extra byte to
+ * cover the NUL terminator.
+ */
+ *reply = malloc(myRepLen + 1);
+ if (*reply != NULL) {
+ memcpy(*reply, myReply, myRepLen);
+ /*
+ * The message layer already writes a trailing NUL but we might
+ * change that someday, so do it again here.
+ */
+ (*reply)[myRepLen] = 0;
+ }
+ } else {
+ /*
+ * Our reply was NULL, so just pass the NULL back up to the caller.
+ */
+ *reply = NULL;
+ }
+
+ /*
+ * Only set the length if the caller wanted it and if we got a good
+ * reply.
+ */
+ if (repLen != NULL && *reply != NULL) {
+ *repLen = myRepLen;
+ }
+ }
+
+ if (out) {
+ if (RpcOut_stop(out) == FALSE) {
+ /*
+ * We couldn't stop the channel. Free anything we allocated, give our
+ * client a reply of NULL, and return FALSE.
+ */
+
+ if (reply != NULL) {
+ free(*reply);
+ *reply = NULL;
+ }
+ Debug("Rpci: unable to close the communication channel\n");
+ status = FALSE;
+ }
+
+ RpcOut_Destruct(out);
+ out = NULL;
+ }
+
+ return status;
+}
+
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * rpcout.h --
+ *
+ * Remote Procedure Call between VMware and guest applications
+ * C declarations
+ */
+
+
+#ifndef __RPCOUT_H__
+# define __RPCOUT_H__
+
+#include "vm_basic_types.h"
+
+#define RPCI_PROTOCOL_NUM 0x49435052 /* 'RPCI' ;-) */
+
+typedef struct RpcOut RpcOut;
+
+RpcOut *RpcOut_Construct(void);
+void RpcOut_Destruct(RpcOut *out);
+Bool RpcOut_start(RpcOut *out);
+Bool RpcOut_send(RpcOut *out, char const *request, size_t reqLen,
+ char const **reply, size_t *repLen);
+Bool RpcOut_stop(RpcOut *out);
+
+
+/*
+ * This is the only method needed to send a message to vmware for
+ * 99% of uses. I'm leaving the others defined here so people know
+ * they can be exported again if the need arises. [greg]
+ */
+Bool RpcOut_sendOne(char **reply, size_t *repLen, char const *reqFmt, ...);
+
+/*
+ * A new version of the above function that works with UTF-8 strings
+ * and other data that would be corrupted by Win32's FormatMessage
+ * function (which is used by RpcOut_sendOne()).
+ */
+
+Bool RpcOut_SendOneRaw(void *request, size_t reqLen, char **reply, size_t *repLen);
+
+#endif /* __RPCOUT_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * str.h --
+ *
+ * string wrapping functions
+ */
+
+#ifndef _STR_H_
+#define _STR_H_
+
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMCORE
+#include "includeCheck.h"
+
+#if defined(GLIBC_VERSION_22)
+#include <wchar.h>
+#elif defined(_WIN32)
+#include <tchar.h>
+#elif __APPLE__
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+
+#include "vm_basic_types.h"
+
+
+/*
+ * These platforms use bsd_vsnprintf().
+ * This does not mean it has bsd_vsnwprintf().
+ */
+#if defined _WIN32 && !defined STR_NO_WIN32_LIBS || \
+ defined __linux__ && !defined N_PLAT_NLM || defined __APPLE__
+#define HAS_BSD_PRINTF 1
+#endif
+
+/*
+ * And these platforms/setups use bsd_vsnwprintf()
+ */
+#if (defined _WIN32 && !defined STR_NO_WIN32_LIBS) || \
+ (defined __GNUC__ && (__GNUC__ < 2 \
+ || (__GNUC__ == 2 \
+ && __GNUC_MINOR__ < 96)))
+#define HAS_BSD_WPRINTF 1
+#endif
+
+/*
+ * ASCII/UTF-8 versions
+ *
+ * NOTE: All size_t arguments and integer returns values are in bytes.
+ *
+ * NOTE: Str_Asprintf/Str_Vasprintf return NULL on failure, while
+ * Str_SafeAsprintf/Str_SafeVasprintf ASSERT_NOT_IMPLEMENTED.
+ *
+ * NOTE: "%s" refers to strings of "char" units, while "%S" refers to
+ * strings of "wchar_t" units, regardless of platform.
+ */
+
+EXTERN int Str_Sprintf(char *buf, size_t max,
+ const char *fmt, ...) PRINTF_DECL(3, 4);
+EXTERN int Str_Snprintf(char *buf, size_t len,
+ const char *fmt, ...) PRINTF_DECL(3, 4);
+EXTERN int Str_Vsnprintf(char *buf, size_t len,
+ const char *fmt, va_list args);
+EXTERN size_t Str_Strlen(const char *src, size_t maxLen);
+EXTERN char *Str_Strnstr(const char *src, const char *sub, size_t n);
+EXTERN char *Str_Strcpy(char *dst, const char *src, size_t maxLen);
+EXTERN char *Str_Strcat(char *dst, const char *src, size_t maxLen);
+EXTERN char *Str_Strncat(char *buf, size_t bufSize, const char *src, size_t n);
+
+EXTERN char *Str_Asprintf(size_t *length,
+ const char *format, ...) PRINTF_DECL(2, 3);
+EXTERN char *Str_Vasprintf(size_t *length, const char *format,
+ va_list arguments);
+EXTERN char *Str_SafeAsprintf(size_t *length,
+ const char *format, ...) PRINTF_DECL(2, 3);
+EXTERN char *Str_SafeVasprintf(size_t *length, const char *format,
+ va_list arguments);
+
+#if defined(_WIN32) || defined(GLIBC_VERSION_22) // {
+
+/*
+ * wchar_t versions
+ *
+ * NOTE: All size_t arguments and integer return values are in
+ * wchar_ts, not bytes.
+ *
+ * NOTE: Str_Aswprintf/Str_Vaswprintf return NULL on failure, while
+ * Str_SafeAswprintf/Str_SafeVaswprintf ASSERT_NOT_IMPLEMENTED.
+ *
+ * NOTE: "%s" refers to strings of "char" units, while "%S" refers to
+ * strings of "wchar_t" units, regardless of platform.
+ */
+
+EXTERN int Str_Swprintf(wchar_t *buf, size_t max,
+ const wchar_t *fmt, ...);
+EXTERN int Str_Snwprintf(wchar_t *buf, size_t len,
+ const wchar_t *fmt, ...);
+EXTERN int Str_Vsnwprintf(wchar_t *buf, size_t len,
+ const wchar_t *fmt, va_list args);
+EXTERN wchar_t *Str_Wcscpy(wchar_t *dst, const wchar_t *src, size_t maxLen);
+EXTERN wchar_t *Str_Wcscat(wchar_t *dst, const wchar_t *src, size_t maxLen);
+EXTERN wchar_t *Str_Wcsncat(wchar_t *buf, size_t bufSize, const wchar_t *src,
+ size_t n);
+
+EXTERN wchar_t *Str_Aswprintf(size_t *length,
+ const wchar_t *format, ...);
+EXTERN wchar_t *Str_Vaswprintf(size_t *length, const wchar_t *format,
+ va_list arguments);
+EXTERN wchar_t *Str_SafeAswprintf(size_t *length,
+ const wchar_t *format, ...);
+EXTERN wchar_t *Str_SafeVaswprintf(size_t *length, const wchar_t *format,
+ va_list arguments);
+
+unsigned char *Str_Mbscpy(char *buf, const char *src,
+ size_t maxSize);
+unsigned char *Str_Mbscat(char *buf, const char *src,
+ size_t maxSize);
+
+/*
+ * These are handly for Windows programmers. They are like
+ * the _tcs functions, but with Str_Strcpy-style bounds checking.
+ *
+ * We don't have Str_Mbsncat() because it has some odd semantic
+ * ambiguity (whether to truncate in the middle of a multibyte
+ * sequence) that I want to stay away from. -- edward
+ */
+
+#ifdef _WIN32
+#ifdef UNICODE
+ #define Str_Tcscpy(s1, s2, n) Str_Wcscpy(s1, s2, n)
+ #define Str_Tcscat(s1, s2, n) Str_Wcscat(s1, s2, n)
+#else
+ #define Str_Tcscpy(s1, s2, n) Str_Mbscpy(s1, s2, n)
+ #define Str_Tcscat(s1, s2, n) Str_Mbscat(s1, s2, n)
+#endif
+#endif
+
+#endif // } defined(_WIN32) || defined(GLIBC_VERSION_22)
+
+
+/*
+ * Wrappers for standard string functions
+ *
+ * These are either for Windows-Posix compatibility,
+ * or just gratuitous wrapping for consistency.
+ */
+
+#define Str_Strcmp(s1, s2) strcmp(s1, s2)
+#define Str_Strncmp(s1, s2, n) strncmp(s1, s2, n)
+
+#define Str_Strchr(s, c) strchr(s, c)
+#define Str_Strrchr(s, c) strrchr(s, c)
+#define Str_Strspn(s1, s2) strspn(s1, s2)
+#define Str_Strcspn(s1, s2) strcspn(s1, s2)
+
+#if defined(_WIN32)
+ #define Str_Strcasecmp(s1, s2) _stricmp(s1, s2)
+ #define Str_Strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
+ #define Str_ToUpper(s) _strupr(s)
+ #define Str_ToLower(s) _strlwr(s)
+#elif defined(N_PLAT_NLM)
+ #define Str_Strcasecmp(s1, s2) stricmp(s1, s2)
+ #define Str_Strncasecmp(s1, s2, n) strnicmp(s1, s2, n)
+ char *Str_ToUpper(char *string);
+ char *Str_ToLower(char *string);
+#else
+ #define Str_Strcasecmp(s1, s2) strcasecmp(s1, s2)
+ #define Str_Strncasecmp(s1, s2, n) strncasecmp(s1, s2, n)
+ char *Str_ToUpper(char *string);
+ char *Str_ToLower(char *string);
+#endif
+
+#ifdef _WIN32
+ #define Str_Tcscmp(s1, s2) _tcscmp(s1, s2)
+ #define Str_Tcsncmp(s1, s2, n) _tcsncmp(s1, s2, n)
+ #define Str_Tcsicmp(s1, s2) _tcsicmp(s1, s2)
+ #define Str_Tcsnicmp(s1, s2, n) _tcsnicmp(s1, s2, n)
+ #define Str_Tcschr(s, c) _tcschr(s, c)
+ #define Str_Tcsrchr(s, c) _tcsrchr(s, c)
+ #define Str_Tcsspn(s1, s2) _tcsspn(s1, s2)
+ #define Str_Tcscspn(s1, s2) _tcscspn(s1, s2)
+ #define Str_Tcsupr(s) _tcsupr(s)
+ #define Str_Tcslwr(s) _tcslwr(s)
+#endif
+
+#endif /* _STR_H_ */
*/
#ifndef ASSERT_IFNOT
- #ifdef __cplusplus
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+ /*
+ * PR 271512: When compiling with gcc, catch assignments inside an ASSERT.
+ *
+ * 'UNLIKELY' is defined with __builtin_expect, which does not warn when passed an
+ * assignment (gcc bug 36050).
+ * To get around this, we put 'cond' in an 'if' statement and make sure it never gets
+ * executed by putting that inside of 'if (0)'.
+ * We use gcc's statement expression syntax to make ASSERT an expression because some
+ * code uses it that way.
+ *
+ * Since statement expression syntax is a gcc extension and since it's not clear if
+ * this is a problem with other compilers, the ASSERT definition was not changed for
+ * them. Using a bare 'cond' with the ternary operator may provide a solution.
+ */
+ #ifdef __GNUC__
+ #define ASSERT_IFNOT(cond, panic) \
+ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;})
#else
- #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+ #define ASSERT_IFNOT(cond, panic) \
+ (UNLIKELY(!(cond)) ? (panic) : (void)0)
#endif
#endif
#error No compiler defined for RDTSC
#endif /* __GNUC__ */
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DEBUGBREAK --
+ *
+ * Does an int3 for MSVC / GCC. This is a macro to make sure int3 is
+ * always inlined.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef _MSC_VER
+#define DEBUGBREAK() __debugbreak()
+#else
+#define DEBUGBREAK() __asm__ (" int $3 ")
+#endif
+
#endif
#ifdef _MSC_VER
#define CONST64(c) c##I64
#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
#elif __GNUC__
#ifdef VM_X86_64
#define CONST64(c) c##L
*/
typedef VA32 UserVA32;
typedef VA64 UserVA64;
-typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
#ifdef VMKERNEL
-typedef UserVA32 UserVA;
+typedef UserVA64 UserVA;
#else
typedef void * UserVA;
#endif
#include "hgfsSolaris.h"
#include "hgfsState.h"
+#include "hgfsBdGlue.h"
#include "vnode.h"
#include "filesystem.h"
#include "request.h"
uint64_t offset, uint32_t size, uio_t *uiop);
static int HgfsDelete(HgfsSuperInfo *sip, char *filename, HgfsOp op);
-/* Local utility functions */
-#if HGFS_VFS_VERSION > 2
-static int HgfsMakeVnodeOps(HgfsSuperInfo *sip);
-#endif
static int HgfsSubmitRequest(HgfsSuperInfo *sip, HgfsReq *req);
static int HgfsValidateReply(HgfsReq *req, uint32_t minSize);
static void HgfsAttrToSolaris(struct vnode *vp, const HgfsAttr *hgfsAttr,
#if HGFS_VFS_VERSION == 2
/* vnode Operations Structure */
-struct vnodeops HgfsVnodeOps = {
+struct vnodeops hgfsVnodeOps = {
HgfsOpen, /* vop_open() */
HgfsClose, /* vop_close() */
HgfsRead, /* vop_read() */
HgfsShrlock /* vop_shrlock() */
};
+#else
+
+/* Will be set up during HGFS initialization (see HgfsInit) */
+static struct vnodeops *hgfsVnodeOpsP;
+
#endif
+static HgfsSuperInfo hgfsSuperInfo;
+
/*
* Vnode Entry Points
if ( !HGFS_KNOW_FILENAME(vp) ) {
DEBUG(VM_DEBUG_FAIL, "HgfsClose: we don't know the filename of:\n");
- HgfsDebugPrintVnode(VM_DEBUG_STRUCT, "HgfsClose", vp);
+ HgfsDebugPrintVnode(VM_DEBUG_STRUCT, "HgfsClose", vp, TRUE);
return EINVAL;
}
DEBUG(VM_DEBUG_FAIL, "HgfsGetattr: CPName_ConvertTo failed.\n");
ret = ENAMETOOLONG;
/* We need to set the request's state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
request->fileName.length = ret;
*/
ret = HgfsSubmitRequest(sip, req);
if (ret) {
- /* HgfsSubmitRequest destroys the request if necessary */
goto out;
}
if (HgfsValidateReply(req, sizeof reply->header) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsGetattr: reply not valid.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
switch (reply->header.status) {
break;
}
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
DEBUG(VM_DEBUG_DONE, "HgfsSetattr: don't need to update attributes.\n");
ret = 0;
/* We need to set the request state to completed before destroying. */
- HgfsReqSetState(req, HGFS_REQ_COMPLETED);
- goto destroy_out;
+ req->state = HGFS_REQ_COMPLETED;
+ goto out;
}
/* Convert the filename to cross platform and escape its buffer. */
DEBUG(VM_DEBUG_FAIL, "HgfsSetattr: CPName_ConvertTo failed.\n");
ret = ENAMETOOLONG;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
request->fileName.length = ret;
ret = HgfsSubmitRequest(sip, req);
if (ret) {
- /* HgfsSubmitRequest() destroys the request if necessary. */
goto out;
}
if (HgfsValidateReply(req, sizeof *reply) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsSetattr: invalid reply received.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
switch(reply->header.status) {
case HGFS_STATUS_INVALID_NAME:
DEBUG(VM_DEBUG_FAIL, "HgfsSetattr: no such file or directory.\n");
ret = ENOENT;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_OPERATION_NOT_PERMITTED:
DEBUG(VM_DEBUG_FAIL, "HgfsSetattr: operation not permitted.\n");
ret = EPERM;
- goto destroy_out;
+ goto out;
default:
DEBUG(VM_DEBUG_FAIL, "HgfsSetattr: default error.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
/* Success */
ret = 0;
DEBUG(VM_DEBUG_DONE, "HgfsSetattr: done.\n");
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
path, // Destination buffer
sizeof path); // Size of dest buffer
if (ret < 0) {
- ret = EINVAL;
- goto out;
+ return EINVAL;
}
DEBUG(VM_DEBUG_LOAD, "HgfsLookup: full path is \"%s\"\n", path);
* per-open state for it.
*/
DEBUG(VM_DEBUG_DONE, "HgfsLookup: created per-open state from filename.\n");
- goto out;
+ return 0;
}
#endif
DEBUG(VM_DEBUG_FAIL, "HgfsLookup: CPName_ConvertTo failed.\n");
ret = ENAMETOOLONG;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
request->fileName.length = ret;
DEBUG(VM_DEBUG_COMM, " fileName.name: \"%s\"\n", request->fileName.name);
/*
- * Submit the request and wait for the reply. HgfsSubmitRequest handles
- * destroying the request on both error and interrupt cases.
+ * Submit the request and wait for the reply.
*/
ret = HgfsSubmitRequest(sip, req);
if (ret) {
DEBUG(VM_DEBUG_FAIL, "HgfsLookup(): invalid reply received for ID %d "
"with status %d.\n", reply->header.id, reply->header.status);
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
DEBUG(VM_DEBUG_COMM, "HgfsLookup: received reply for ID %d\n", reply->header.id);
DEBUG(VM_DEBUG_COMM,
"HgfsLookup: invalid packet size received for \"%s\".\n", nm);
ret = EIO;
- goto destroy_out;
+ goto out;
}
/* Success */
break;
case HGFS_STATUS_OPERATION_NOT_PERMITTED:
DEBUG(VM_DEBUG_LOG, "HgfsLookup: operation not permitted on \"%s\".\n", nm);
ret = EACCES;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_NO_SUCH_FILE_OR_DIR:
case HGFS_STATUS_INVALID_NAME:
*/
DEBUG(VM_DEBUG_LOG, "HgfsLookup: \"%s\" does not exist.\n", nm);
ret = ENOENT;
- goto destroy_out;
+ goto out;
default:
DEBUG(VM_DEBUG_LOG, "HgfsLookup: error on \"%s\".\n", nm);
ret = EIO;
- goto destroy_out;
+ goto out;
}
/*
if (ret) {
DEBUG(VM_DEBUG_FAIL, "HgfsLookup: couldn't create vnode for \"%s\".\n", path);
ret = EIO;
- goto destroy_out;
+ goto out;
}
/* HgfsVnodeGet guarantees this. */
ASSERT(*vpp);
ret = 0; /* Return success */
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
"HgfsRename: couldn't convert source to cross platform name.\n");
ret = ENAMETOOLONG;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
request->oldName.length = ret;
"HgfsRename: couldn't convert destination to cross platform name.\n");
ret = ENAMETOOLONG;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
newNameP->length = ret;
ret = HgfsSubmitRequest(sip, req);
if (ret) {
- /* HgfsSubmitRequest() destroys the request if necessary. */
goto out;
}
if (HgfsValidateReply(req, sizeof *reply) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsRename: invalid reply received.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
/* Return appropriate value. */
case HGFS_STATUS_OPERATION_NOT_PERMITTED:
DEBUG(VM_DEBUG_FAIL, "HgfsRename: operation not permitted.\n");
ret = EACCES;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_NOT_DIRECTORY:
DEBUG(VM_DEBUG_FAIL, "HgfsRename: not a directory.\n");
ret = ENOTDIR;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_DIR_NOT_EMPTY:
DEBUG(VM_DEBUG_FAIL, "HgfsRename: directory not empty.\n");
ret = EEXIST;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_NO_SUCH_FILE_OR_DIR:
case HGFS_STATUS_INVALID_NAME:
DEBUG(VM_DEBUG_FAIL, "HgfsRename: no such file or directory.\n");
ret = ENOENT;
- goto destroy_out;
+ goto out;
default:
DEBUG(VM_DEBUG_FAIL, "HgfsRename: default error.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
ret = 0;
DEBUG(VM_DEBUG_DONE, "HgfsRename: done.\n");
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
DEBUG(VM_DEBUG_FAIL, "HgfsMkdir: cross-platform name is too long.\n");
ret = ENAMETOOLONG;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
request->fileName.length = ret;
/* Set the size of this request. */
req->packetSize = sizeof *request + request->fileName.length;
- /* Send the request to guestd. */
+ /* Send the request. */
ret = HgfsSubmitRequest(sip, req);
if (ret) {
- /* Request is destroyed in HgfsSubmitRequest() if necessary. */
goto out;
}
if (HgfsValidateReply(req, sizeof *reply) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsMkdir: invalid reply received.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
switch (reply->header.status) {
case HGFS_STATUS_OPERATION_NOT_PERMITTED:
DEBUG(VM_DEBUG_FAIL, "HgfsMkdir: operation not permitted.\n");
ret = EACCES;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_FILE_EXISTS:
DEBUG(VM_DEBUG_FAIL, "HgfsMkdir: directory already exists.\n");
ret = EEXIST;
- goto destroy_out;
+ goto out;
default:
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
/* We now create the vnode for the new directory. */
HGFS_FILE_TYPE_DIRECTORY, &sip->fileHashTable);
if (ret) {
ret = EIO;
- goto destroy_out;
+ goto out;
}
ASSERT(*vpp); /* HgfsIget guarantees this. */
ret = 0;
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
if (ret < 0) {
ret = ENAMETOOLONG;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
request->dirName.length = ret;
/* Submit the request to the Hgfs server */
ret = HgfsSubmitRequest(sip, req);
if (ret) {
- /* HgfsSubmitRequest destroys the request if necessary */
goto out;
}
if (HgfsValidateReply(req, sizeof reply->header) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsDirOpen(): invalid reply received.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
DEBUG(VM_DEBUG_COMM, "HgfsDirOpen: received reply for ID %d\n", reply->header.id);
if (req->packetSize != sizeof *reply) {
DEBUG(VM_DEBUG_FAIL, "HgfsDirOpen: incorrect packet size.\n");
ret = EIO;
- goto destroy_out;
+ goto out;
}
/* Success handled after switch. */
break;
DEBUG(VM_DEBUG_FAIL, "HgfsDirOpen: operation not permitted (%s).\n",
HGFS_VP_TO_FILENAME(vp));
ret = EACCES;
- goto destroy_out;
+ goto out;
default:
DEBUG(VM_DEBUG_FAIL, "HgfsDirOpen: default error (%s).\n",
HGFS_VP_TO_FILENAME(vp));
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
/* Set the search open handle for use in HgfsReaddir() */
if (ret) {
DEBUG(VM_DEBUG_FAIL, "HgfsDirOpen: couldn't assign handle=%d to %s\n",
reply->search, HGFS_VP_TO_FILENAME(vp));
- HgfsReqSetState(req, HGFS_REQ_ERROR);
+ req->state = HGFS_REQ_ERROR;
ret = EINVAL;
- goto destroy_out;
+ goto out;
}
ret = 0; /* Return success */
-destroy_out:
+out:
/* Make sure we put the request back on the list */
HgfsDestroyReq(sip, req);
-out:
DEBUG(VM_DEBUG_DONE, "HgfsDirOpen: done\n");
return ret;
}
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: HgfsGetOpenMode failed.\n");
ret = EINVAL;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
request->mode = ret;
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: HgfsGetOpenFlags failed.\n");
ret = EINVAL;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
request->flags = ret;
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: CPName_ConvertTo failed.\n");
ret = ENAMETOOLONG;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
request->fileName.length = ret;
ret = HgfsSubmitRequest(sip, req);
if (ret) {
- /* HgfsSubmitRequest will destroy the request if necessary. */
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: could not submit request.\n");
goto out;
}
if (HgfsValidateReply(req, sizeof reply->header) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: request not valid.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
switch (reply->header.status) {
if (req->packetSize != sizeof *reply) {
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: size of reply is incorrect.\n");
ret = EIO;
- goto destroy_out;
+ goto out;
}
/* Success case is handled after switch. */
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: no such file \"%s\".\n",
HGFS_VP_TO_FILENAME(vp));
ret = ENOENT;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_FILE_EXISTS:
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: \"%s\" exists.\n",
HGFS_VP_TO_FILENAME(vp));
ret = EEXIST;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_OPERATION_NOT_PERMITTED:
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: operation not permitted on %s.\n",
HGFS_VP_TO_FILENAME(vp));
ret = EACCES;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_ACCESS_DENIED:
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: access denied on %s.\n",
HGFS_VP_TO_FILENAME(vp));
ret = EACCES;
- goto destroy_out;
+ goto out;
default:
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: default/unknown error %d.\n",
reply->header.status);
ret = EACCES;
- goto destroy_out;
+ goto out;
}
/*
if (ret) {
DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: couldn't assign handle %d (%s)\n",
reply->file, HGFS_VP_TO_FILENAME(vp));
- HgfsReqSetState(req, HGFS_REQ_ERROR);
+ req->state = HGFS_REQ_ERROR;
ret = EINVAL;
- goto destroy_out;
+ goto out;
}
ret = 0;
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
HGFS_VP_TO_FILENAME(vp));
ret = EINVAL;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
req->packetSize = sizeof *request;
/* Submit the request to the Hgfs server */
ret = HgfsSubmitRequest(sip, req);
if (ret) {
- /* HgfsSubmitRequest destroys the request if necessary */
goto out;
}
if (HgfsValidateReply(req, sizeof reply->header) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsDirClose: invalid reply received.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
DEBUG(VM_DEBUG_COMM, "HgfsDirClose: received reply for ID %d\n", reply->header.id);
/* Ensure server was able to close directory. */
if (reply->header.status != HGFS_STATUS_SUCCESS) {
ret = EIO;
- goto destroy_out;
+ goto out;
}
/* Now clear this open file's handle for future use. */
if (ret) {
DEBUG(VM_DEBUG_FAIL, "HgfsDirClose: couldn't clear handle.\n");
ret = EINVAL;
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
/* The directory was closed successfully so we return success. */
ret = 0;
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: couldn't get handle.\n");
ret = EINVAL;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
req->packetSize = sizeof *request;
ret = HgfsSubmitRequest(sip, req);
if (ret) {
- /* HgfsSubmitRequest will destroy the request if necessary. */
DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: submit request failed.\n");
goto out;
}
if (HgfsValidateReply(req, sizeof *reply) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: reply was invalid.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
reply = (HgfsReplyClose *)req->packet;
if (ret) {
DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: couldn't clear handle.\n");
ret = EINVAL;
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
ret = 0;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_INVALID_HANDLE:
DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: invalid handle error.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_OPERATION_NOT_PERMITTED:
DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: operation not permitted error.\n");
ret = EACCES;
- goto destroy_out;
+ goto out;
default:
DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: other/unknown error.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
DEBUG(VM_DEBUG_DONE, "HgfsFileClose: returning %d\n", ret);
return ret;
}
ret = HgfsSubmitRequest(sip, req);
if (ret) {
- /* HgfsSubmitRequest will destroy the request if necessary. */
DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: HgfsSubmitRequest failed.\n");
goto out;
}
if (HgfsValidateReply(req, sizeof reply->header) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: reply not valid.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
DEBUG(VM_DEBUG_COMM, "HgfsGetNextDirEntry: received reply for ID %d\n",
DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: server didn't return success (%d).\n",
reply->header.status);
ret = EINVAL;
- goto destroy_out;
+ goto out;
}
/* Make sure we got an entire reply (excluding filename) */
if (req->packetSize < sizeof *reply) {
DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: server didn't provide entire reply.\n");
ret = EIO;
- goto destroy_out;
+ goto out;
}
/* See if there are no more filenames to read */
DEBUG(VM_DEBUG_DONE, "HgfsGetNextDirEntry: no more directory entries.\n");
*done = TRUE;
ret = 0; /* return success */
- goto destroy_out;
+ goto out;
}
/* Make sure filename isn't too long */
(reply->fileName.length > HGFS_PAYLOAD_MAX(reply)) ) {
DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: filename is too long.\n");
ret = EOVERFLOW;
- goto destroy_out;
+ goto out;
}
/*
ret = 0;
DEBUG(VM_DEBUG_DONE, "HgfsGetNextDirEntry: done.\n");
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
if (ret) {
/*
* We need to flip the sign of the return value to indicate error; see
- * the comment in the function header. HgfsSubmitRequest() handles
- * destroying the request if necessary, so we don't here.
+ * the comment in the function header.
*/
ret = -ret;
goto out;
if (HgfsValidateReply(req, sizeof reply->header) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsDoRead: invalid reply received.\n");
ret = -EPROTO;
- goto destroy_out;
+ goto out;
}
if (reply->header.status != HGFS_STATUS_SUCCESS) {
DEBUG(VM_DEBUG_FAIL, "HgfsDoRead: request not completed successfully.\n");
ret = -EACCES;
- goto destroy_out;
+ goto out;
}
/*
ret = uiomove(reply->payload, reply->actualSize, UIO_READ, uiop);
if (ret) {
ret = -EIO;
- goto destroy_out;
+ goto out;
}
/* We successfully copied the payload to the user's buffer */
/* We got too much data: server error. */
DEBUG(VM_DEBUG_FAIL, "HgfsDoRead: received too much data in payload.\n");
ret = -EPROTO;
- goto destroy_out;
+ goto out;
}
success:
ret = reply->actualSize;
DEBUG(VM_DEBUG_DONE, "HgfsDoRead: successfully read %d bytes to user.\n", ret);
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
"HgfsDoWrite: uiomove(9F) failed copying data from user.\n");
ret = -EIO;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
/* We subtract one so request's 'char payload[1]' member isn't double counted. */
if (HgfsValidateReply(req, sizeof reply->header) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsDoWrite: invalid reply received.\n");
ret = -EPROTO;
- goto destroy_out;
+ goto out;
}
if (reply->header.status != HGFS_STATUS_SUCCESS) {
DEBUG(VM_DEBUG_FAIL, "HgfsDoWrite: write failed (status=%d).\n",
reply->header.status);
ret = -EACCES;
- goto destroy_out;
+ goto out;
}
if (req->packetSize != sizeof *reply) {
DEBUG(VM_DEBUG_FAIL,
"HgfsDoWrite: invalid size of reply on successful reply.\n");
ret = -EPROTO;
- goto destroy_out;
+ goto out;
}
/* The write was completed successfully, so return the amount written. */
ret = reply->actualSize;
DEBUG(VM_DEBUG_DONE, "HgfsDoWrite: wrote %d bytes.\n", ret);
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
if (ret < 0) {
ret = ENAMETOOLONG;
/* We need to set the request state to error before destroying. */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- goto destroy_out;
+ req->state = HGFS_REQ_ERROR;
+ goto out;
}
request->fileName.length = ret;
DEBUG(VM_DEBUG_COMM, "HgfsDelete: deleting \"%s\"\n", filename);
- /* Submit our request to guestd. */
+ /* Submit our request. */
ret = HgfsSubmitRequest(sip, req);
if (ret) {
- /* HgfsSubmitRequest() handles destroying the request if necessary. */
goto out;
}
if (HgfsValidateReply(req, sizeof *reply) != 0) {
DEBUG(VM_DEBUG_FAIL, "HgfsDelete: invalid reply received.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
/* Return the appropriate value. */
case HGFS_STATUS_OPERATION_NOT_PERMITTED:
DEBUG(VM_DEBUG_FAIL, "HgfsDelete: operation not permitted.\n");
ret = EACCES;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_NOT_DIRECTORY:
DEBUG(VM_DEBUG_FAIL, "HgfsDelete: not a directory.\n");
ret = ENOTDIR;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_DIR_NOT_EMPTY:
DEBUG(VM_DEBUG_FAIL, "HgfsDelete: directory not empty.\n");
ret = EEXIST;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_NO_SUCH_FILE_OR_DIR:
case HGFS_STATUS_INVALID_NAME:
DEBUG(VM_DEBUG_FAIL, "HgfsDelete: no such file or directory.\n");
ret = ENOENT;
- goto destroy_out;
+ goto out;
case HGFS_STATUS_ACCESS_DENIED:
DEBUG(VM_DEBUG_FAIL, "HgfsDelete: access denied.\n");
/* XXX: Add retry behavior after removing r/o bit. */
ret = EACCES;
- goto destroy_out;
+ goto out;
default:
DEBUG(VM_DEBUG_FAIL, "HgfsDelete: default error.\n");
ret = EPROTO;
- goto destroy_out;
+ goto out;
}
DEBUG(VM_DEBUG_DONE, "HgfsDelete: done.\n");
-destroy_out:
- HgfsDestroyReq(sip, req);
out:
+ HgfsDestroyReq(sip, req);
return ret;
}
*/
inline HgfsSuperInfo *
-HgfsGetSuperInfo()
+HgfsGetSuperInfo(void)
{
- HgfsSuperInfo *sip;
+ return hgfsSuperInfo.vfsp ? &hgfsSuperInfo : NULL;
+}
- /*
- * The superInfoHead and hgfsInstance are global variables set by the device
- * have of the driver at attach-time (HgfsDevAttach()). We access the soft
- * state from the filesystem in this way to ensure consistency with the
- * driver.
- */
- sip = (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, hgfsInstance);
- if (!sip) {
- return NULL;
- }
- /* Only return the superinfo if the filesystem is mounted. */
- return (sip->vfsp) ? sip : NULL;
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsInitSuperInfo --
+ *
+ * Initializes superinfo structure to indicate that filesystem has been
+ * mounted and can be used now.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsInitSuperInfo(struct vfs *vfsp) // IN: pointer to vfs being mounted
+{
+ hgfsSuperInfo.vfsp = vfsp;
+
+ /* For now we are only using the backdoor transport. */
+ hgfsSuperInfo.sendRequest = HgfsBackdoorSendRequest;
+ hgfsSuperInfo.cancelRequest = HgfsBackdoorCancelRequest;
+ hgfsSuperInfo.transportInit = HgfsBackdoorInit;
+ hgfsSuperInfo.transportCleanup = HgfsBackdoorCleanup;
+
+ HgfsInitRequestList(&hgfsSuperInfo);
+ HgfsInitFileHashTable(&hgfsSuperInfo.fileHashTable);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsClearSuperInfo --
+ *
+ * Clears superinfo structure to indicate that filesystem has been
+ * unmounted.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsClearSuperInfo(void)
+{
+ hgfsSuperInfo.vfsp = NULL;
}
*
* Sets the vnode operations for the provided vnode.
*
- * Solaris 9:
- * We just set the vnode's operations field to point to our statically
- * created array of entry points.
- *
- * Solaris 10:
- * The first time this function is called it will create the vnode
- * operations and place a pointer to them in the superinfo structure. On
- * subsequent invocations the same operations structure will be assigned to
- * vnodes.
- *
* Results:
* Returns zero on success and a non-zero error code on error.
*
*/
int
-HgfsSetVnodeOps(HgfsSuperInfo *sip, // IN: Superinfo pointer
- struct vnode *vp) // IN: vnode for this file
-#if HGFS_VFS_VERSION == 2
+HgfsSetVnodeOps(struct vnode *vp) // IN: vnode for this file
{
ASSERT(vp);
- vp->v_op = &HgfsVnodeOps;
- return 0;
-}
+#if HGFS_VFS_VERSION == 2
+ vp->v_op = &hgfsVnodeOps;
#else
-{
- int ret;
-
- ASSERT(sip);
- ASSERT(vp);
-
- /* See if we need to create the vnode operations structure */
- if (!sip->vnodeOps) {
- ret = HgfsMakeVnodeOps(sip);
- if (ret) {
- DEBUG(VM_DEBUG_FAIL, "HgfsSetVnodeOps: couldn't create vnode ops.\n");
- return HGFS_ERR;
- } else {
- DEBUG(VM_DEBUG_INFO, "HgfsSetVnodeOps: made vnode ops.\n");
- }
- }
-
- if (vn_getops(vp) == sip->vnodeOps) {
+ /* hgfsVnodeOpsP is set up when we mounted HGFS volume. */
+ if (vn_getops(vp) == hgfsVnodeOpsP) {
DEBUG(VM_DEBUG_INFO, "HgfsSetVnodeOps: vnode ops already set.\n");
} else {
DEBUG(VM_DEBUG_INFO, "HgfsSetVnodeOps: we had to set the vnode ops.\n");
- /* Set the operations for this vnode */
- vn_setops(vp, sip->vnodeOps);
+ /* Set the operations for this vnode. */
+ vn_setops(vp, hgfsVnodeOpsP);
}
+#endif
return 0;
}
* completes, all calls to vn_alloc() for our filesystem should return vnodes
* with the correct operations.
*
- * The operation structure allocated here will be freed in
- * HgfsFreevfs() which is called by the Kernel when the filesystem is
- * unmounted.
- *
* Results:
* Return 0 on success and non-zero on failure.
*
*----------------------------------------------------------------------------
*/
-static int
-HgfsMakeVnodeOps(HgfsSuperInfo *sip) // IN: Superinfo
+int
+HgfsMakeVnodeOps(void)
{
+#if HGFS_VFS_VERSION > 2
int ret;
- fs_operation_def_t vnodeOpsArr[] = {
+ static fs_operation_def_t vnodeOpsArr[] = {
HGFS_VOP(VOPNAME_OPEN, vop_open, HgfsOpen),
HGFS_VOP(VOPNAME_CLOSE, vop_close, HgfsClose),
HGFS_VOP(VOPNAME_READ, vop_read, HgfsRead),
HGFS_VOP(VOPNAME_GETSECATTR, vop_getsecattr, fs_fab_acl),
HGFS_VOP(VOPNAME_SETSECATTR, vop_setsecattr, HgfsSetsecattr),
HGFS_VOP(VOPNAME_SHRLOCK, vop_shrlock, HgfsShrlock),
-#if HGFS_VFS_VERSION > 2
HGFS_VOP(VOPNAME_VNEVENT, vop_vnevent, HgfsVnevent),
-#endif
#if HGFS_VFS_VERSION <= 3
- { NULL, NULL}
+ { NULL, NULL }
#else
{ NULL, { NULL } }
#endif
DEBUG(VM_DEBUG_ENTRY, "HgfsMakeVnodeOps: making vnode ops.\n");
/*
- * Create a vnodeops structure and register it with the kernel. We save the
- * operations structure in the superinfo so it can be assigned in the
+ * Create a vnodeops structure and register it with the kernel.
+ * We save the operations structure so it can be assigned in the
* future.
*/
- ret = vn_make_ops(HGFS_FS_NAME, vnodeOpsArr, &sip->vnodeOps);
+ ret = vn_make_ops(HGFS_FS_NAME, vnodeOpsArr, &hgfsVnodeOpsP);
if (ret) {
DEBUG(VM_DEBUG_FAIL, "HgfsMakeVnodeOps: vn_make_ops returned %d\n", ret);
- return HGFS_ERR;
+ return ret;
}
- DEBUG(VM_DEBUG_DONE, "HgfsMakeVnodeOps: sip->vnodeOps=%p\n", sip->vnodeOps);
+ DEBUG(VM_DEBUG_DONE, "HgfsMakeVnodeOps: hgfsVnodeOpsP=%p\n", hgfsVnodeOpsP);
+#endif
return 0;
}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFreeVnodeOps --
+ *
+ * Unregisters vnode operations from the kernel.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The kernel frees memory allocated for our operations structure.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsFreeVnodeOps(void)
+{
+#if HGFS_VFS_VERSION > 2
+ if (hgfsVnodeOpsP)
+ vn_freevnodeops(hgfsVnodeOpsP);
#endif
+}
/*
*
* HgfsSubmitRequest --
*
- * Places a request on the queue for submission to guestd, then waits for
+ * Sends request through the transport channel, then waits for
* the response.
*
* Both submitting request and waiting for reply are in this function
// condition variable, and mutex
HgfsReq *req) // IN: Request to submit
{
+ int ret = 0;
+
ASSERT(sip);
ASSERT(req);
- /* The device must be open to submit requests */
- if (!sip->devOpen) {
- /*
- * Destroy the request here to make things simpler for callers: they
- * only need to destroy the request if they get a reply.
- */
- HgfsReqSetState(req, HGFS_REQ_ERROR);
- HgfsDestroyReq(sip, req);
- return ENODEV;
- }
-
- /*
- * The process of submitting the request involves putting it on the request
- * list, waking up guestd if it is waiting for a request, then atomically
- * waiting for the reply. We must loop on cv_wait_sig(9F) because Solaris
- * says it may return prematurely. We must signify that we have abandoned
- * the request if we are interrupted.
- */
-
mutex_enter(&sip->reqMutex);
- HgfsEnqueueRequest(sip, req);
+ if (sip->vfsp->vfs_flag & VFS_UNMOUNTED) {
+ DEBUG(VM_DEBUG_REQUEST, "HgfsSubmitRequest(): filesystem not mounted.\n");
+ ret = ENODEV;
+ goto out;
+ }
+
+ ret = HgfsSendRequest(sip, req);
+ if (ret) {
+ DEBUG(VM_DEBUG_REQUEST, "HgfsSubmitRequest(): transport failed.\n");
+ goto out;
+ }
/*
- * We unconditionally signal the request list's condition variable because
- * if guestd is waiting then we want to wake it up and if guestd isn't
- * waiting then this has no effect.
- *
- * We also call pollwakeup to let callers of poll(2) on the device know
- * there is now something to read. XXX: This is bad because a caller of
- * poll(2) could end up blocked in read(2) if operations are interleaved
- * just so. For now we only allow the device to be opened once to prevent
- * this.
- */
- cv_signal(&sip->reqCondVar);
- /*
- * XXX: This will wake any process waiting for a POLLRDNORM event on our
- * device. We should probably change this so HgfsDevChpoll() tells us what
- * event to signal since it knows what guestd is waiting for. This would
- * prevent having to change this macro should guestd or the poll()
- * implementation ever change. It seems like that would be a bit messy
- * though, so we've left this as is.
- *
- * We release and reacquire the request mutex around the call to
- * pollwakeup() since HgfsDevChpoll() also acquires it, and that's not
- * allowed (see chpoll(9E) man page). This is completely safe since nothing
- * bad can happen to the request by allowing other code to run; we release
- * this same lock in the loop below when we call cv_wait_sig().
+ * If we are using synchronous transport we should have the result right
+ * here and status will not be equal HGFS_REQ_SUBMITTED. If we are using
+ * async transport we'll sleep till somebody wakes us up.
*/
- mutex_exit(&sip->reqMutex);
- pollwakeup(&sip->hgfsPollhead, POLLRDNORM);
- mutex_enter(&sip->reqMutex);
-
- while (HgfsReqGetState(req) == HGFS_REQ_SUBMITTED) {
+ while (req->state == HGFS_REQ_SUBMITTED) {
k_sigset_t oldIgnoreSet;
//DEBUG(VM_DEBUG_SIG, "HgfsSubmitRequest: currproc is %s.\n", u.u_comm);
if (cv_wait_sig(&req->condVar, &sip->reqMutex) == 0) {
/*
* We received a system signal (e.g., SIGKILL) while waiting for the
- * reply from guestd.
+ * reply.
*
* Since we gave up the mutex while waiting on the condition
* variable, we must make sure the reply didn't come /after/ we were
DEBUG(VM_DEBUG_SIG, "HgfsSubmitRequest(): interrupted while waiting for reply.\n");
- if (HgfsReqGetState(req) != HGFS_REQ_SUBMITTED) {
+ if (req->state != HGFS_REQ_SUBMITTED) {
/* It it's not SUBMITTED, it must be COMPLETED or ERROR */
- ASSERT((HgfsReqGetState(req) == HGFS_REQ_COMPLETED) ||
- (HgfsReqGetState(req) == HGFS_REQ_ERROR));
-
- DEBUG(VM_DEBUG_REQUEST, "HgfsSubmitRequest(): destroying request.\n");
- HgfsDestroyReq(sip, req);
+ ASSERT(req->state == HGFS_REQ_COMPLETED ||
+ req->state == HGFS_REQ_ERROR);
+ DEBUG(VM_DEBUG_REQUEST, "HgfsSubmitRequest(): request not in submitted status.\n");
} else {
DEBUG(VM_DEBUG_REQUEST, "HgfsSubmitRequest(): setting request state to abandoned.\n");
- HgfsReqSetState(req, HGFS_REQ_ABANDONED);
+ req->state = HGFS_REQ_ABANDONED;
}
- mutex_exit(&sip->reqMutex);
- return EINTR;
+ ret = EINTR;
+ goto out;
}
HgfsRestoreSignals(&oldIgnoreSet);
/* The reply should now be in req->packet. */
DEBUG(VM_DEBUG_SIG, "HgfsSubmitRequest(): awoken because reply received.\n");
+ out:
mutex_exit(&sip->reqMutex);
-
- return 0;
+ return ret;
}
ASSERT(req);
ASSERT(minSize <= HGFS_PACKET_MAX); /* we want to know if this fails */
- switch (HgfsReqGetState(req)) {
+ switch (req->state) {
case HGFS_REQ_ERROR:
DEBUG(VM_DEBUG_FAIL, "HgfsValidateReply(): received reply with error.\n");
return -1;
DEBUG(VM_DEBUG_INFO, "HgfsMakeFullName:\n"
" path: \"%s\" (%d)\n"
" file: \"%s\" (%ld)\n",
- path, pathLen, file, strlen(file));
+ path, pathLen, file, (long) strlen(file));
/*
* Here there are three possibilities:
#include "hgfsSolaris.h"
-int HgfsSetVnodeOps(HgfsSuperInfo *sip, struct vnode *vp);
+int HgfsSetVnodeOps(struct vnode *vp);
inline HgfsSuperInfo *HgfsGetSuperInfo(void);
+void HgfsInitSuperInfo(struct vfs *vfsp);
+void HgfsClearSuperInfo(void);
+int HgfsMakeVnodeOps(void);
+void HgfsFreeVnodeOps(void);
#endif
FLAGDEF( 87, EDX, AMD, 5, 1, STC, NA, IGNORE, 0, FALSE) \
FLAGDEF( 87, EDX, AMD, 6, 1, 100MHZSTEPS, NA, IGNORE, 0, FALSE) \
FLAGDEF( 87, EDX, AMD, 7, 1, HWPSTATE, NA, IGNORE, 0, FALSE) \
-FLAGDEF( 87, EDX, AMD, 8, 1, TSC_INVARIANT, NA, IGNORE, 0, FALSE) \
+FLAGDEF( 87, EDX, COMMON, 8, 1, TSC_INVARIANT, NA, IGNORE, 0, FALSE) \
FIELDDEFA(88, EAX, COMMON, 0, 8, PHYSBITS, NA, IGNORE, 0, FALSE, PHYS_BITS) \
FIELDDEFA(88, EAX, COMMON, 8, 8, VIRTBITS, NA, IGNORE, 0, FALSE, VIRT_BITS) \
FIELDDEFA(88, ECX, AMD, 0, 8, CORE_COUNT, NA, IGNORE, 0, FALSE, AMD_CORE_COUNT) \
#define CPUID_MODEL_PIII_08 8
#define CPUID_MODEL_PIII_0A 10
+/* AMD model information */
+#define CPUID_MODEL_BARCELONA_02 0x02 // Barcelona (both Opteron & Phenom kind)
+
/*
*----------------------------------------------------------------------
*
CPUID_FAMILY_IS_K8MOBILE(_eax);
}
+/*
+ * AMD Barcelona (of either Opteron or Phenom kind).
+ */
+static INLINE Bool
+CPUID_MODEL_IS_BARCELONA(uint32 v) // IN: %eax from CPUID with %eax=1.
+{
+ /* Assumes the CPU manufacturer is AMD. */
+ return CPUID_FAMILY_IS_K8L(v) &&
+ CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_BARCELONA_02;
+}
+
#define CPUID_TYPE_PRIMARY 0
#define CPUID_TYPE_OVERDRIVE 1
--- /dev/null
+
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+
+1. Definitions.
+
+ 1.1. "Contributor" means each individual or entity that creates
+ or contributes to the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the Original
+ Software, prior Modifications used by a Contributor (if any),
+ and the Modifications made by that particular Contributor.
+
+ 1.3. "Covered Software" means (a) the Original Software, or (b)
+ Modifications, or (c) the combination of files containing
+ Original Software with files containing Modifications, in
+ each case including portions thereof.
+
+ 1.4. "Executable" means the Covered Software in any form other
+ than Source Code.
+
+ 1.5. "Initial Developer" means the individual or entity that first
+ makes Original Software available under this License.
+
+ 1.6. "Larger Work" means a work which combines Covered Software or
+ portions thereof with code not governed by the terms of this
+ License.
+
+ 1.7. "License" means this document.
+
+ 1.8. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed
+ herein.
+
+ 1.9. "Modifications" means the Source Code and Executable form of
+ any of the following:
+
+ A. Any file that results from an addition to, deletion from or
+ modification of the contents of a file containing Original
+ Software or previous Modifications;
+
+ B. Any new file that contains any part of the Original
+ Software or previous Modifications; or
+
+ C. Any new file that is contributed or otherwise made
+ available under the terms of this License.
+
+ 1.10. "Original Software" means the Source Code and Executable
+ form of computer software code that is originally released
+ under this License.
+
+ 1.11. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by
+ grantor.
+
+ 1.12. "Source Code" means (a) the common form of computer software
+ code in which modifications are made and (b) associated
+ documentation included in or with such code.
+
+ 1.13. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms
+ of, this License. For legal entities, "You" includes any
+ entity which controls, is controlled by, or is under common
+ control with You. For purposes of this definition,
+ "control" means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by
+ contract or otherwise, or (b) ownership of more than fifty
+ percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants.
+
+ 2.1. The Initial Developer Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and
+ subject to third party intellectual property claims, the Initial
+ Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer, to use,
+ reproduce, modify, display, perform, sublicense and
+ distribute the Original Software (or portions thereof),
+ with or without Modifications, and/or as part of a Larger
+ Work; and
+
+ (b) under Patent Claims infringed by the making, using or
+ selling of Original Software, to make, have made, use,
+ practice, sell, and offer for sale, and/or otherwise
+ dispose of the Original Software (or portions thereof).
+
+ (c) The licenses granted in Sections 2.1(a) and (b) are
+ effective on the date Initial Developer first distributes
+ or otherwise makes the Original Software available to a
+ third party under the terms of this License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: (1) for code that You delete from the Original
+ Software, or (2) for infringements caused by: (i) the
+ modification of the Original Software, or (ii) the
+ combination of the Original Software with other software
+ or devices.
+
+ 2.2. Contributor Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and
+ subject to third party intellectual property claims, each
+ Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor to use, reproduce,
+ modify, display, perform, sublicense and distribute the
+ Modifications created by such Contributor (or portions
+ thereof), either on an unmodified basis, with other
+ Modifications, as Covered Software and/or as part of a
+ Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or
+ selling of Modifications made by that Contributor either
+ alone and/or in combination with its Contributor Version
+ (or portions of such combination), to make, use, sell,
+ offer for sale, have made, and/or otherwise dispose of:
+ (1) Modifications made by that Contributor (or portions
+ thereof); and (2) the combination of Modifications made by
+ that Contributor with its Contributor Version (or portions
+ of such combination).
+
+ (c) The licenses granted in Sections 2.2(a) and 2.2(b) are
+ effective on the date Contributor first distributes or
+ otherwise makes the Modifications available to a third
+ party.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: (1) for any code that Contributor has deleted
+ from the Contributor Version; (2) for infringements caused
+ by: (i) third party modifications of Contributor Version,
+ or (ii) the combination of Modifications made by that
+ Contributor with other software (except as part of the
+ Contributor Version) or other devices; or (3) under Patent
+ Claims infringed by Covered Software in the absence of
+ Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Availability of Source Code.
+
+ Any Covered Software that You distribute or otherwise make
+ available in Executable form must also be made available in Source
+ Code form and that Source Code form must be distributed only under
+ the terms of this License. You must include a copy of this
+ License with every copy of the Source Code form of the Covered
+ Software You distribute or otherwise make available. You must
+ inform recipients of any such Covered Software in Executable form
+ as to how they can obtain such Covered Software in Source Code
+ form in a reasonable manner on or through a medium customarily
+ used for software exchange.
+
+ 3.2. Modifications.
+
+ The Modifications that You create or to which You contribute are
+ governed by the terms of this License. You represent that You
+ believe Your Modifications are Your original creation(s) and/or
+ You have sufficient rights to grant the rights conveyed by this
+ License.
+
+ 3.3. Required Notices.
+
+ You must include a notice in each of Your Modifications that
+ identifies You as the Contributor of the Modification. You may
+ not remove or alter any copyright, patent or trademark notices
+ contained within the Covered Software, or any notices of licensing
+ or any descriptive text giving attribution to any Contributor or
+ the Initial Developer.
+
+ 3.4. Application of Additional Terms.
+
+ You may not offer or impose any terms on any Covered Software in
+ Source Code form that alters or restricts the applicable version
+ of this License or the recipients' rights hereunder. You may
+ choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of
+ Covered Software. However, you may do so only on Your own behalf,
+ and not on behalf of the Initial Developer or any Contributor.
+ You must make it absolutely clear that any such warranty, support,
+ indemnity or liability obligation is offered by You alone, and You
+ hereby agree to indemnify the Initial Developer and every
+ Contributor for any liability incurred by the Initial Developer or
+ such Contributor as a result of warranty, support, indemnity or
+ liability terms You offer.
+
+ 3.5. Distribution of Executable Versions.
+
+ You may distribute the Executable form of the Covered Software
+ under the terms of this License or under the terms of a license of
+ Your choice, which may contain terms different from this License,
+ provided that You are in compliance with the terms of this License
+ and that the license for the Executable form does not attempt to
+ limit or alter the recipient's rights in the Source Code form from
+ the rights set forth in this License. If You distribute the
+ Covered Software in Executable form under a different license, You
+ must make it absolutely clear that any terms which differ from
+ this License are offered by You alone, not by the Initial
+ Developer or Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred
+ by the Initial Developer or such Contributor as a result of any
+ such terms You offer.
+
+ 3.6. Larger Works.
+
+ You may create a Larger Work by combining Covered Software with
+ other code not governed by the terms of this License and
+ distribute the Larger Work as a single product. In such a case,
+ You must make sure the requirements of this License are fulfilled
+ for the Covered Software.
+
+4. Versions of the License.
+
+ 4.1. New Versions.
+
+ Sun Microsystems, Inc. is the initial license steward and may
+ publish revised and/or new versions of this License from time to
+ time. Each version will be given a distinguishing version number.
+ Except as provided in Section 4.3, no one other than the license
+ steward has the right to modify this License.
+
+ 4.2. Effect of New Versions.
+
+ You may always continue to use, distribute or otherwise make the
+ Covered Software available under the terms of the version of the
+ License under which You originally received the Covered Software.
+ If the Initial Developer includes a notice in the Original
+ Software prohibiting it from being distributed or otherwise made
+ available under any subsequent version of the License, You must
+ distribute and make the Covered Software available under the terms
+ of the version of the License under which You originally received
+ the Covered Software. Otherwise, You may also choose to use,
+ distribute or otherwise make the Covered Software available under
+ the terms of any subsequent version of the License published by
+ the license steward.
+
+ 4.3. Modified Versions.
+
+ When You are an Initial Developer and You want to create a new
+ license for Your Original Software, You may create and use a
+ modified version of this License if You: (a) rename the license
+ and remove any references to the name of the license steward
+ (except to note that the license differs from this License); and
+ (b) otherwise make it clear that the license contains terms which
+ differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+ COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
+ BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+ INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
+ SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+ PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
+ PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY
+ COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+ INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+ NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
+ WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+ DISCLAIMER.
+
+6. TERMINATION.
+
+ 6.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to
+ cure such breach within 30 days of becoming aware of the breach.
+ Provisions which, by their nature, must remain in effect beyond
+ the termination of this License shall survive.
+
+ 6.2. If You assert a patent infringement claim (excluding
+ declaratory judgment actions) against Initial Developer or a
+ Contributor (the Initial Developer or Contributor against whom You
+ assert such claim is referred to as "Participant") alleging that
+ the Participant Software (meaning the Contributor Version where
+ the Participant is a Contributor or the Original Software where
+ the Participant is the Initial Developer) directly or indirectly
+ infringes any patent, then any and all rights granted directly or
+ indirectly to You by such Participant, the Initial Developer (if
+ the Initial Developer is not the Participant) and all Contributors
+ under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
+ notice from Participant terminate prospectively and automatically
+ at the expiration of such 60 day notice period, unless if within
+ such 60 day period You withdraw Your claim with respect to the
+ Participant Software against such Participant either unilaterally
+ or pursuant to a written agreement with Participant.
+
+ 6.3. In the event of termination under Sections 6.1 or 6.2 above,
+ all end user licenses that have been validly granted by You or any
+ distributor hereunder prior to termination (excluding licenses
+ granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+ INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+ COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+ LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+ CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+ LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
+ STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+ INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
+ APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO
+ NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
+ APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+ The Covered Software is a "commercial item," as that term is
+ defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
+ computer software" (as that term is defined at 48
+ C.F.R. 252.227-7014(a)(1)) and "commercial computer software
+ documentation" as such terms are used in 48 C.F.R. 12.212
+ (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48
+ C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+ U.S. Government End Users acquire Covered Software with only those
+ rights set forth herein. This U.S. Government Rights clause is in
+ lieu of, and supersedes, any other FAR, DFAR, or other clause or
+ provision that addresses Government rights in computer software
+ under this License.
+
+9. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed
+ by the law of the jurisdiction specified in a notice contained
+ within the Original Software (except to the extent applicable law,
+ if any, provides otherwise), excluding such jurisdiction's
+ conflict-of-law provisions. Any litigation relating to this
+ License shall be subject to the jurisdiction of the courts located
+ in the jurisdiction and venue specified in a notice contained
+ within the Original Software, with the losing party responsible
+ for costs, including, without limitation, court costs and
+ reasonable attorneys' fees and expenses. The application of the
+ United Nations Convention on Contracts for the International Sale
+ of Goods is expressly excluded. Any law or regulation which
+ provides that the language of a contract shall be construed
+ against the drafter shall not apply to this License. You agree
+ that You alone are responsible for compliance with the United
+ States export administration regulations (and the export control
+ laws and regulation of any other countries) when You use,
+ distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or
+ indirectly, out of its utilization of rights under this License
+ and You agree to work with Initial Developer and Contributors to
+ distribute such responsibility on an equitable basis. Nothing
+ herein is intended or shall be deemed to constitute any admission
+ of liability.
+
--- /dev/null
+#!/usr/bin/make -f
+##########################################################
+# Copyright (C) 2009 VMware, Inc. All rights reserved.
+#
+# The contents of this file are subject to the terms of the Common
+# Development and Distribution License (the "License") version 1.0
+# and no later version. You may not use this file except in
+# compliance with the License.
+#
+# You can obtain a copy of the License at
+# http://www.opensource.org/licenses/cddl1.php
+#
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+##########################################################
+
+##
+## General build locations and variables
+##
+
+MODULE := vmxnet
+MODULE_32 := i386/$(MODULE)
+MODULE_64 := amd64/$(MODULE)
+
+CFLAGS :=
+LDFLAGS :=
+
+CFLAGS += -O2
+CFLAGS += -Wall -Werror
+CFLAGS += -U_NO_LONGLONG
+CFLAGS += -D_KERNEL
+CFLAGS += -I../../../lib/include # for buildNumber.h
+
+##
+## Objects needed to build the HGFS kernel module
+##
+VMXNET_OBJS := vmxnet.o
+
+VMXNET_32_OBJS := $(addprefix i386/, $(VMXNET_OBJS))
+VMXNET_64_OBJS := $(addprefix amd64/, $(VMXNET_OBJS))
+
+ifeq ($(shell echo "$(VM_UNAME)" | cut -c-4),5.9) # {
+
+# Solaris 9
+MODULES := $(MODULE_32)
+
+else # } {
+ifeq ($(shell echo "$(VM_UNAME)" | cut -c-4),5.10) # {
+
+# Solaris 10
+MODULES := $(MODULE_32) $(MODULE_64)
+CFLAGS += -ffreestanding
+CFLAGS += -nodefaultlibs
+
+else # } {
+
+$(error "This makefile is only used for Solaris 9 and 10")
+
+endif # }
+endif # }
+
+CFLAGS_32 := $(CFLAGS)
+CFLAGS_32 += -m32
+LDFLAGS_32 := $(LDFLAGS)
+
+CFLAGS_64 := $(CFLAGS)
+CFLAGS_64 += -m64
+CFLAGS_64 += -mcmodel=kernel
+CFLAGS_64 += -mno-red-zone
+LDFLAGS_64 := $(LDFLAGS)
+ifdef HAVE_GNU_LD
+LDFLAGS_64 += -m elf_x86_64
+else
+LDFLAGS_64 += -64
+endif
+
+all: prepare_dirs $(MODULES)
+
+prepare_dirs:
+ @echo "Creating build directories"
+ mkdir -p i386
+ mkdir -p amd64
+
+$(MODULE_32): $(VMXNET_32_OBJS)
+ @echo "Linking $@"
+ $(LD) $(LDFLAGS_32) -r $(VMXNET_32_OBJS) -o $@
+
+$(VMXNET_32_OBJS): i386/%.o: %.c
+ @echo "Compiling $(<F)"
+ $(CC) $(CFLAGS_32) -c $< -o $@
+
+$(MODULE_64): $(VMXNET_64_OBJS)
+ @echo "Linking $@"
+ $(LD) $(LDFLAGS_64) -r $(VMXNET_64_OBJS) -o $@
+
+$(VMXNET_64_OBJS): amd64/%.o: %.c
+ @echo "Compiling $(<F)"
+ $(CC) $(CFLAGS_64) -c $< -o $@
+
+clean:
+ @echo "Cleaning directories"
+ @rm -rf $(MODULE_32) $(VMXNET_32_OBJS) i386
+ @rm -rf $(MODULE_64) $(VMXNET_64_OBJS) amd64
+
+install:
+ @echo "Installing modules"
+ cp $(MODULE_32) /kernel/drv/
+ chmod 755 /kernel/drv/$(MODULE)
+ cp $(MODULE_64) /kernel/drv/amd64
+ chmod 755 /kernel/drv/amd64/$(MODULE)
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * includeCheck.h --
+ *
+ * Restrict include file use.
+ *
+ * In every .h file, define one or more of these
+ *
+ * INCLUDE_ALLOW_VMX
+ * INCLUDE_ALLOW_USERLEVEL
+ * INCLUDE_ALLOW_VMMEXT
+ * INCLUDE_ALLOW_VMCORE
+ * INCLUDE_ALLOW_MODULE
+ * INCLUDE_ALLOW_VMNIXMOD
+ * INCLUDE_ALLOW_VMKERNEL
+ * INCLUDE_ALLOW_DISTRIBUTE
+ * INCLUDE_ALLOW_VMK_MODULE
+ * INCLUDE_ALLOW_VMKDRIVERS
+ * INCLUDE_ALLOW_VMIROM
+ *
+ * Then include this file.
+ *
+ * Any file that has INCLUDE_ALLOW_DISTRIBUTE defined will potentially
+ * be distributed in source form along with GPLed code. Ensure
+ * that this is acceptable.
+ */
+
+
+/*
+ * Declare a VMCORE-only variable to help classify object
+ * files. The variable goes in the common block and does
+ * not create multiple definition link-time conflicts.
+ */
+
+#if defined VMCORE && defined VMX86_DEVEL && defined VMX86_DEBUG && \
+ defined linux && !defined MODULE && \
+ !defined COMPILED_WITH_VMCORE
+#define COMPILED_WITH_VMCORE compiled_with_vmcore
+#ifdef ASM
+ .comm compiled_with_vmcore, 0
+#else
+ asm(".comm compiled_with_vmcore, 0");
+#endif /* ASM */
+#endif
+
+
+#if defined VMCORE && \
+ !(defined VMX86_VMX || defined VMM || \
+ defined MONITOR_APP || defined VMMON)
+#error "Makefile problem: VMCORE without VMX86_VMX or \
+ VMM or MONITOR_APP or MODULE."
+#endif
+
+#if defined VMCORE && !defined INCLUDE_ALLOW_VMCORE
+#error "The surrounding include file is not allowed in vmcore."
+#endif
+#undef INCLUDE_ALLOW_VMCORE
+
+#if defined VMX86_VMX && !defined VMCORE && \
+ !(defined INCLUDE_ALLOW_VMX || defined INCLUDE_ALLOW_USERLEVEL)
+#error "The surrounding include file is not allowed in the VMX."
+#endif
+#undef INCLUDE_ALLOW_VMX
+
+#if defined USERLEVEL && !defined VMX86_VMX && !defined VMCORE && \
+ !defined INCLUDE_ALLOW_USERLEVEL
+#error "The surrounding include file is not allowed at userlevel."
+#endif
+#undef INCLUDE_ALLOW_USERLEVEL
+
+#if defined VMM && !defined VMCORE && \
+ !defined INCLUDE_ALLOW_VMMEXT
+#error "The surrounding include file is not allowed in the monitor."
+#endif
+#undef INCLUDE_ALLOW_VMMEXT
+
+#if defined MODULE && !defined VMKERNEL_MODULE && !defined VMNIXMOD && \
+ !defined VMMON && !defined INCLUDE_ALLOW_MODULE
+#error "The surrounding include file is not allowed in driver modules."
+#endif
+#undef INCLUDE_ALLOW_MODULE
+
+#if defined VMMON && !defined INCLUDE_ALLOW_VMMON
+#error "The surrounding include file is not allowed in vmmon."
+#endif
+#undef INCLUDE_ALLOW_VMMON
+
+#if defined VMKERNEL && !defined INCLUDE_ALLOW_VMKERNEL
+#error "The surrounding include file is not allowed in the vmkernel."
+#endif
+#undef INCLUDE_ALLOW_VMKERNEL
+
+#if defined GPLED_CODE && !defined INCLUDE_ALLOW_DISTRIBUTE
+#error "The surrounding include file is not allowed in GPL code."
+#endif
+#undef INCLUDE_ALLOW_DISTRIBUTE
+
+#if defined VMKERNEL_MODULE && !defined VMKERNEL && \
+ !defined INCLUDE_ALLOW_VMK_MODULE && !defined INCLUDE_ALLOW_VMKDRIVERS
+#error "The surrounding include file is not allowed in vmkernel modules."
+#endif
+#undef INCLUDE_ALLOW_VMK_MODULE
+#undef INCLUDE_ALLOW_VMKDRIVERS
+
+#if defined VMNIXMOD && !defined INCLUDE_ALLOW_VMNIXMOD
+#ifndef VMNIXMOD_VM
+#error "The surrounding include file is not allowed in vmnixmod."
+#endif
+#endif
+#undef INCLUDE_ALLOW_VMNIXMOD
+
+#if defined VMIROM && ! defined INCLUDE_ALLOW_VMIROM
+#error "The surrounding include file is not allowed in vmirom."
+#endif
+#undef INCLUDE_ALLOW_VMIROM
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/************************************************************
+ *
+ * net.h
+ *
+ * This file should contain all network global defines.
+ * No vlance/vmxnet/vnet/vmknet specific stuff should be
+ * put here only defines used/usable by all network code.
+ * --gustav
+ *
+ ************************************************************/
+
+#ifndef VMWARE_DEVICES_NET_H
+#define VMWARE_DEVICES_NET_H
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMEXT
+#include "includeCheck.h"
+#include "vm_device_version.h"
+
+#define ETHERNET_MTU 1518
+#define ETH_MIN_FRAME_LEN 60
+
+#ifndef ETHER_ADDR_LEN
+#define ETHER_ADDR_LEN 6 /* length of MAC address */
+#endif
+#define ETH_HEADER_LEN 14 /* length of Ethernet header */
+#define IP_ADDR_LEN 4 /* length of IPv4 address */
+#define IP_HEADER_LEN 20 /* minimum length of IPv4 header */
+
+#define ETHER_MAX_QUEUED_PACKET 1600
+
+
+/*
+ * State's that a NIC can be in currently we only use this
+ * in VLance but if we implement/emulate new adapters that
+ * we also want to be able to morph a new corresponding
+ * state should be added.
+ */
+
+#define LANCE_CHIP 0x2934
+#define VMXNET_CHIP 0x4392
+
+/*
+ * Size of reserved IO space needed by the LANCE adapter and
+ * the VMXNET adapter. If you add more ports to Vmxnet than
+ * there is reserved space you must bump VMXNET_CHIP_IO_RESV_SIZE.
+ * The sizes must be powers of 2.
+ */
+
+#define LANCE_CHIP_IO_RESV_SIZE 0x20
+#define VMXNET_CHIP_IO_RESV_SIZE 0x40
+
+#define MORPH_PORT_SIZE 4
+
+
+#ifdef USERLEVEL
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Net_AddAddrToLADRF --
+ *
+ * Given a MAC address, sets the corresponding bit in the LANCE style
+ * Logical Address Filter 'ladrf'.
+ * The caller should have initialized the ladrf to all 0's, as this
+ * function only ORs on a bit in the array.
+ * 'addr' is presumed to be ETHER_ADDR_LEN in size;
+ * 'ladrf' is presumed to point to a 64-bit vector.
+ *
+ * Derived from a long history of derivations, originally inspired by
+ * sample code from the AMD "Network Products: Ethernet Controllers 1998
+ * Data Book, Book 2", pages 1-53..1-55.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * Updates 'ladrf'.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+Net_AddAddrToLadrf(const uint8 *addr, // IN: pointer to MAC address
+ uint8 *ladrf) // IN/OUT: pointer to ladrf
+{
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+
+ uint16 hashcode;
+ int32 crc = 0xffffffff; /* init CRC for each address */
+ int32 j;
+ int32 bit;
+ int32 byte;
+
+ ASSERT(addr);
+ ASSERT(ladrf);
+
+ for (byte = 0; byte < ETHER_ADDR_LEN; byte++) { /* for each address byte */
+ /* process each address bit */
+ for (bit = *addr++, j = 0;
+ j < 8;
+ j++, bit >>= 1) {
+ crc = (crc << 1) ^ ((((crc < 0 ? 1 : 0) ^ bit) & 0x01) ?
+ CRC_POLYNOMIAL_BE : 0);
+ }
+ }
+ hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */
+ for (j = 0; j < 5; j++) { /* ... in reverse order. */
+ hashcode = (hashcode << 1) | ((crc>>=1) & 1);
+ }
+
+ ladrf[hashcode >> 3] |= 1 << (hashcode & 0x07);
+}
+
+#endif // USERLEVEL
+
+#endif // VMWARE_DEVICES_NET_H
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2000 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * net_sg.h --
+ *
+ * Network packet scatter gather structure.
+ */
+
+
+#ifndef _NET_SG_H
+#define _NET_SG_H
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#define NET_SG_DEFAULT_LENGTH 16
+
+/*
+ * A single scatter-gather element for a network packet.
+ * The address is split into low and high to save space.
+ * If we make it 64 bits then Windows pads things out such that
+ * we lose a lot of space for each scatter gather array.
+ * This adds up when you have embedded scatter-gather
+ * arrays for transmit and receive ring buffers.
+ */
+typedef struct NetSG_Elem {
+ uint32 addrLow;
+ uint16 addrHi;
+ uint16 length;
+} NetSG_Elem;
+
+typedef enum NetSG_AddrType {
+ NET_SG_MACH_ADDR,
+ NET_SG_PHYS_ADDR,
+ NET_SG_VIRT_ADDR,
+ NET_SG_VMM_STACK_OFFSET,
+} NetSG_AddrType;
+
+typedef struct NetSG_Array {
+ uint16 addrType;
+ uint16 length;
+ NetSG_Elem sg[NET_SG_DEFAULT_LENGTH];
+} NetSG_Array;
+
+#define NET_SG_SIZE(len) (sizeof(NetSG_Array) + (len - NET_SG_DEFAULT_LENGTH) * sizeof(NetSG_Elem))
+
+#define NET_SG_MAKE_PA(elem) (PA)QWORD(elem.addrHi, elem.addrLow)
+#define NET_SG_MAKE_PTR(elem) (char *)(uintptr_t)QWORD(elem.addrHi, elem.addrLow)
+
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998-2008 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ *
+ * vm_basic_types.h --
+ *
+ * basic data types.
+ */
+
+
+#ifndef _VM_BASIC_TYPES_H_
+#define _VM_BASIC_TYPES_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMKDRIVERS
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+
+/* STRICT ANSI means the Xserver build and X defines Bool differently. */
+#if !defined(__STRICT_ANSI__) || defined(__FreeBSD__)
+typedef char Bool;
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#define IsBool(x) (((x) & ~1) == 0)
+#define IsBool2(x, y) ((((x) | (y)) & ~1) == 0)
+
+/*
+ * Macros __i386__ and __ia64 are intrinsically defined by GCC
+ */
+#ifdef __i386__
+#define VM_I386
+#endif
+
+#ifdef _WIN64
+#define __x86_64__
+#endif
+
+#ifdef __x86_64__
+#define VM_X86_64
+#define VM_I386
+#define vm_x86_64 (1)
+#else
+#define vm_x86_64 (0)
+#endif
+
+
+
+#ifdef _WIN32
+/* safe assumption for a while */
+#define VM_I386
+#endif
+
+#ifdef _MSC_VER
+
+#pragma warning (3 :4505) // unreferenced local function
+#pragma warning (disable :4018) // signed/unsigned mismatch
+#pragma warning (disable :4761) // integral size mismatch in argument; conversion supplied
+#pragma warning (disable :4305) // truncation from 'const int' to 'short'
+#pragma warning (disable :4244) // conversion from 'unsigned short' to 'unsigned char'
+#pragma warning (disable :4267) // truncation of 'size_t'
+#pragma warning (disable :4146) // unary minus operator applied to unsigned type, result still unsigned
+#pragma warning (disable :4142) // benign redefinition of type
+
+#endif
+
+#if defined(__APPLE__) || defined(HAVE_STDINT_H)
+
+/*
+ * TODO: This is a C99 standard header. We should be able to test for
+ * #if __STDC_VERSION__ >= 199901L, but that breaks the Netware build
+ * (which doesn't have stdint.h).
+ */
+
+#include <stdint.h>
+
+typedef uint64_t uint64;
+typedef int64_t int64;
+typedef uint32_t uint32;
+typedef int32_t int32;
+typedef uint16_t uint16;
+typedef int16_t int16;
+typedef uint8_t uint8;
+
+/*
+ * XXX: int8_t is defined to be 'signed char' on Mac hosts.
+ *
+ * Unfortunately, GCC 4.0.1 warns when doing pointer assignment or
+ * comparison between signed char * and char * (even if char is
+ * signed).
+ *
+ * If we want to use int8_t to define int8, we need to go through and
+ * replace uses of char * with signed char * to prevent warnings.
+ */
+typedef char int8;
+
+#else /* !HAVE_STDINT_H */
+
+#ifdef _MSC_VER
+
+typedef unsigned __int64 uint64;
+typedef signed __int64 int64;
+
+#elif __GNUC__
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+#if defined(VM_X86_64)
+typedef unsigned long uint64;
+typedef long int64;
+#else
+typedef unsigned long long uint64;
+typedef long long int64;
+#endif
+#elif __FreeBSD__
+typedef unsigned long long uint64;
+typedef long long int64;
+#endif
+#else
+#error - Need compiler define for int64/uint64
+#endif /* _MSC_VER */
+
+typedef unsigned int uint32;
+typedef unsigned short uint16;
+typedef unsigned char uint8;
+
+typedef int int32;
+typedef short int16;
+typedef char int8;
+
+#endif /* HAVE_STDINT_H */
+
+/*
+ * FreeBSD (for the tools build) unconditionally defines these in
+ * sys/inttypes.h so don't redefine them if this file has already
+ * been included. [greg]
+ *
+ * This applies to Solaris as well.
+ */
+
+/*
+ * Before trying to do the includes based on OS defines, see if we can use
+ * feature-based defines to get as much functionality as possible
+ */
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_INTTYPES_H
+#include <sys/inttypes.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/param.h> /* For __FreeBSD_version */
+#endif
+
+#if !defined(USING_AUTOCONF)
+# if defined(__FreeBSD__) || defined(sun)
+# ifdef KLD_MODULE
+# include <sys/types.h>
+# else
+# if !defined(VMKERNEL) && (__FreeBSD_version >= 500043)
+# include <inttypes.h>
+# include <sys/types.h>
+# else
+# include <sys/inttypes.h>
+# endif
+# endif
+# elif defined __APPLE__
+# if KERNEL
+# include <sys/unistd.h>
+# include <sys/types.h> /* mostly for size_t */
+# include <stdint.h>
+# else
+# include <unistd.h>
+# include <inttypes.h>
+# include <stdlib.h>
+# include <stdint.h>
+# endif
+# else
+# if !defined(__intptr_t_defined) && !defined(intptr_t)
+# define __intptr_t_defined
+# define intptr_t intptr_t
+# ifdef VM_I386
+# ifdef VM_X86_64
+typedef int64 intptr_t;
+# else
+typedef int32 intptr_t;
+# endif
+# endif
+# endif
+
+# ifndef _STDINT_H
+# ifdef VM_I386
+# ifdef VM_X86_64
+typedef uint64 uintptr_t;
+# else
+typedef uint32 uintptr_t;
+# endif
+# endif
+# endif
+# endif
+#endif
+
+
+/*
+ * Time
+ * XXX These should be cleaned up. -- edward
+ */
+
+typedef int64 VmTimeType; /* Time in microseconds */
+typedef int64 VmTimeRealClock; /* Real clock kept in microseconds */
+typedef int64 VmTimeVirtualClock; /* Virtual Clock kept in CPU cycles */
+
+/*
+ * Printf format specifiers for size_t and 64-bit number.
+ * Use them like this:
+ * printf("%"FMT64"d\n", big);
+ *
+ * FMTH is for handles/fds.
+ */
+
+#ifdef _MSC_VER
+ #define FMT64 "I64"
+ #ifdef VM_X86_64
+ #define FMTSZ "I64"
+ #define FMTPD "I64"
+ #define FMTH "I64"
+ #else
+ #define FMTSZ "I"
+ #define FMTPD "I"
+ #define FMTH "I"
+ #endif
+#elif defined __APPLE__
+ /* Mac OS hosts use the same formatters for 32- and 64-bit. */
+ #define FMT64 "ll"
+ #define FMTSZ "z"
+ #define FMTPD "l"
+ #define FMTH ""
+#elif __GNUC__
+ #define FMTH ""
+ #if defined(N_PLAT_NLM) || defined(sun) || \
+ (defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) < 5))
+ /*
+ * Why (__FreeBSD__ + 0)? See bug 141008.
+ * Yes, we really need to test both (__FreeBSD__ + 0) and
+ * ((__FreeBSD__ + 0) < 5). No, we can't remove "+ 0" from
+ * ((__FreeBSD__ + 0) < 5).
+ */
+ #ifdef VM_X86_64
+ #define FMTSZ "l"
+ #define FMTPD "l"
+ #else
+ #define FMTSZ ""
+ #define FMTPD ""
+ #endif
+ #elif defined(__linux__) \
+ || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \
+ || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \
+ || (defined(_POSIX2_VERSION) && _POSIX2_VERSION >= 200112L)
+ /* BSD, Linux */
+ #define FMTSZ "z"
+
+ #if defined(VM_X86_64)
+ #define FMTPD "l"
+ #else
+ #define FMTPD ""
+ #endif
+ #else
+ /* Systems with a pre-C99 libc */
+ #define FMTSZ "Z"
+ #ifdef VM_X86_64
+ #define FMTPD "l"
+ #else
+ #define FMTPD ""
+ #endif
+ #endif
+ #ifdef VM_X86_64
+ #define FMT64 "l"
+ #elif defined(sun) || defined(__FreeBSD__)
+ #define FMT64 "ll"
+ #else
+ #define FMT64 "L"
+ #endif
+#else
+ #error - Need compiler define for FMT64 and FMTSZ
+#endif
+
+/*
+ * Suffix for 64-bit constants. Use it like this:
+ * CONST64(0x7fffffffffffffff) for signed or
+ * CONST64U(0x7fffffffffffffff) for unsigned.
+ *
+ * 2004.08.30(thutt):
+ * The vmcore/asm64/gen* programs are compiled as 32-bit
+ * applications, but must handle 64 bit constants. If the
+ * 64-bit-constant defining macros are already defined, the
+ * definition will not be overwritten.
+ */
+
+#if !defined(CONST64) || !defined(CONST64U)
+#ifdef _MSC_VER
+#define CONST64(c) c##I64
+#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
+#elif __GNUC__
+#ifdef VM_X86_64
+#define CONST64(c) c##L
+#define CONST64U(c) c##uL
+#else
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
+#endif
+#else
+#error - Need compiler define for CONST64
+#endif
+#endif
+
+/*
+ * Use CONST3264/CONST3264U if you want a constant to be
+ * treated as a 32-bit number on 32-bit compiles and
+ * a 64-bit number on 64-bit compiles. Useful in the case
+ * of shifts, like (CONST3264U(1) << x), where x could be
+ * more than 31 on a 64-bit compile.
+ */
+
+#ifdef VM_X86_64
+ #define CONST3264(a) CONST64(a)
+ #define CONST3264U(a) CONST64U(a)
+#else
+ #define CONST3264(a) (a)
+ #define CONST3264U(a) (a)
+#endif
+
+#define MIN_INT32 ((int32)0x80000000)
+#define MAX_INT32 ((int32)0x7fffffff)
+
+#define MIN_UINT32 ((uint32)0)
+#define MAX_UINT32 ((uint32)0xffffffff)
+
+#define MIN_INT64 (CONST64(0x8000000000000000))
+#define MAX_INT64 (CONST64(0x7fffffffffffffff))
+
+#define MIN_UINT64 (CONST64U(0))
+#define MAX_UINT64 (CONST64U(0xffffffffffffffff))
+
+typedef uint8 *TCA; /* Pointer into TC (usually). */
+
+/*
+ * Type big enough to hold an integer between 0..100
+ */
+typedef uint8 Percent;
+#define AsPercent(v) ((Percent)(v))
+#define CHOOSE_PERCENT AsPercent(101)
+
+
+typedef uintptr_t VA;
+typedef uintptr_t VPN;
+
+typedef uint64 PA;
+typedef uint32 PPN;
+
+typedef uint64 PhysMemOff;
+typedef uint64 PhysMemSize;
+
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+typedef uint64 BA;
+#endif
+typedef uint32 BPN;
+typedef uint32 PageNum;
+typedef unsigned MemHandle;
+typedef int32 World_ID;
+
+#define INVALID_WORLD_ID ((World_ID)-1)
+
+typedef World_ID User_CartelID;
+#define INVALID_CARTEL_ID INVALID_WORLD_ID
+
+typedef User_CartelID User_SessionID;
+#define INVALID_SESSION_ID INVALID_CARTEL_ID
+
+typedef User_CartelID User_CartelGroupID;
+#define INVALID_CARTELGROUP_ID INVALID_CARTEL_ID
+
+typedef uint32 Worldlet_ID;
+#define INVALID_WORLDLET_ID ((Worldlet_ID)-1)
+
+/* world page number */
+typedef uint32 WPN;
+
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+typedef uint64 MA;
+typedef uint32 MPN;
+#endif
+
+/*
+ * This type should be used for variables that contain sector
+ * position/quantity.
+ */
+typedef uint64 SectorType;
+
+/*
+ * Linear address
+ */
+
+typedef uintptr_t LA;
+typedef uintptr_t LPN;
+#define LA_2_LPN(_la) ((_la) >> PAGE_SHIFT)
+#define LPN_2_LA(_lpn) ((_lpn) << PAGE_SHIFT)
+
+#define LAST_LPN ((((LA) 1) << (8 * sizeof(LA) - PAGE_SHIFT)) - 1)
+#define LAST_LPN32 ((((LA32)1) << (8 * sizeof(LA32) - PAGE_SHIFT)) - 1)
+#define LAST_LPN64 ((((LA64)1) << (8 * sizeof(LA64) - PAGE_SHIFT)) - 1)
+
+/* Valid bits in a LPN. */
+#define LPN_MASK LAST_LPN
+#define LPN_MASK32 LAST_LPN32
+#define LPN_MASK64 LAST_LPN64
+
+/*
+ * On 64 bit platform, address and page number types default
+ * to 64 bit. When we need to represent a 32 bit address, we use
+ * types defined below.
+ *
+ * On 32 bit platform, the following types are the same as the
+ * default types.
+ */
+typedef uint32 VA32;
+typedef uint32 VPN32;
+typedef uint32 LA32;
+typedef uint32 LPN32;
+typedef uint32 PA32;
+typedef uint32 PPN32;
+typedef uint32 MA32;
+typedef uint32 MPN32;
+
+/*
+ * On 64 bit platform, the following types are the same as the
+ * default types.
+ */
+typedef uint64 VA64;
+typedef uint64 VPN64;
+typedef uint64 LA64;
+typedef uint64 LPN64;
+typedef uint64 PA64;
+typedef uint64 PPN64;
+typedef uint64 MA64;
+typedef uint64 MPN64;
+
+/*
+ * VA typedefs for user world apps.
+ */
+typedef VA32 UserVA32;
+typedef VA64 UserVA64;
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
+#ifdef VMKERNEL
+typedef UserVA64 UserVA;
+#else
+typedef void * UserVA;
+#endif
+
+
+/*
+ * Maximal possible PPN value (errors too) that PhysMem can handle.
+ * Must be at least as large as MAX_PPN which is the maximum PPN
+ * for any region other than buserror.
+ */
+#define PHYSMEM_MAX_PPN ((PPN)0xffffffff)
+#define MAX_PPN ((PPN)0x1fffffff) /* Maximal observable PPN value. */
+#define INVALID_PPN ((PPN)0xffffffff)
+
+#define INVALID_BPN ((BPN) 0x1fffffff)
+
+#define INVALID_MPN ((MPN)-1)
+#define MEMREF_MPN ((MPN)-2)
+#define RESERVED_MPN ((MPN) 0)
+/* Support 43 bits of address space. */
+#define MAX_MPN ((MPN)0x7fffffff)
+
+#define INVALID_LPN ((LPN)-1)
+#define INVALID_VPN ((VPN)-1)
+#define INVALID_LPN64 ((LPN64)-1)
+#define INVALID_PAGENUM ((PageNum)-1)
+#define INVALID_WPN ((WPN) -1)
+
+
+/*
+ * Format modifier for printing VA, LA, and VPN.
+ * Use them like this: Log("%#"FMTLA"x\n", laddr)
+ */
+
+#if defined(VMM64) || defined(FROBOS64) || vm_x86_64 || defined __APPLE__
+# define FMTLA "l"
+# define FMTVA "l"
+# define FMTVPN "l"
+#else
+# define FMTLA ""
+# define FMTVA ""
+# define FMTVPN ""
+#endif
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+#define CONST const
+
+
+#ifndef INLINE
+# ifdef _MSC_VER
+# define INLINE __inline
+# else
+# define INLINE inline
+# endif
+#endif
+
+
+/*
+ * Annotation for data that may be exported into a DLL and used by other
+ * apps that load that DLL and import the data.
+ */
+#if defined(_WIN32) && defined(VMX86_IMPORT_DLLDATA)
+# define VMX86_EXTERN_DATA extern __declspec(dllimport)
+#else // !_WIN32
+# define VMX86_EXTERN_DATA extern
+#endif
+
+#if defined(_WIN32) && !defined(VMX86_NO_THREADS)
+#define THREADSPECIFIC __declspec(thread)
+#else
+#define THREADSPECIFIC
+#endif
+
+/*
+ * Due to the wonderful "registry redirection" feature introduced in
+ * 64-bit Windows, if you access any key under HKLM\Software in 64-bit
+ * code, you need to open/create/delete that key with
+ * VMKEY_WOW64_32KEY if you want a consistent view with 32-bit code.
+ */
+
+#ifdef _WIN32
+#ifdef _WIN64
+#define VMW_KEY_WOW64_32KEY KEY_WOW64_32KEY
+#else
+#define VMW_KEY_WOW64_32KEY 0x0
+#endif
+#endif
+
+
+/*
+ * Consider the following reasons functions are inlined:
+ *
+ * 1) inlined for performance reasons
+ * 2) inlined because it's a single-use function
+ *
+ * Functions which meet only condition 2 should be marked with this
+ * inline macro; It is not critical to be inlined (but there is a
+ * code-space & runtime savings by doing so), so when other callers
+ * are added the inline-ness should be removed.
+ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+/*
+ * Starting at version 3.3, gcc does not always inline functions marked
+ * 'inline' (it depends on their size). To force gcc to do so, one must use the
+ * extra __always_inline__ attribute.
+ */
+# define INLINE_SINGLE_CALLER INLINE __attribute__((__always_inline__))
+# if defined(VMM) \
+ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1))
+# warning Verify INLINE_SINGLE_CALLER '__always_inline__' attribute (did \
+ monitor size change?)
+# endif
+#else
+# define INLINE_SINGLE_CALLER INLINE
+#endif
+
+/*
+ * Used when a hard guaranteed of no inlining is needed. Very few
+ * instances need this since the absence of INLINE is a good hint
+ * that gcc will not do inlining.
+ */
+
+#if defined(__GNUC__) && defined(VMM)
+#define ABSOLUTELY_NOINLINE __attribute__((__noinline__))
+#endif
+
+/*
+ * Attributes placed on function declarations to tell the compiler
+ * that the function never returns.
+ */
+
+#ifdef _MSC_VER
+#define NORETURN __declspec(noreturn)
+#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 9)
+#define NORETURN __attribute__((__noreturn__))
+#else
+#define NORETURN
+#endif
+
+/*
+ * GCC 3.2 inline asm needs the + constraint for input/ouput memory operands.
+ * Older GCCs don't know about it --hpreg
+ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
+# define VM_ASM_PLUS 1
+#else
+# define VM_ASM_PLUS 0
+#endif
+
+/*
+ * Branch prediction hints:
+ * LIKELY(exp) - Expression exp is likely TRUE.
+ * UNLIKELY(exp) - Expression exp is likely FALSE.
+ * Usage example:
+ * if (LIKELY(excCode == EXC_NONE)) {
+ * or
+ * if (UNLIKELY(REAL_MODE(vc))) {
+ *
+ * We know how to predict branches on gcc3 and later (hopefully),
+ * all others we don't so we do nothing.
+ */
+
+#if (__GNUC__ >= 3)
+/*
+ * gcc3 uses __builtin_expect() to inform the compiler of an expected value.
+ * We use this to inform the static branch predictor. The '!!' in LIKELY
+ * will convert any !=0 to a 1.
+ */
+#define LIKELY(_exp) __builtin_expect(!!(_exp), 1)
+#define UNLIKELY(_exp) __builtin_expect((_exp), 0)
+#else
+#define LIKELY(_exp) (_exp)
+#define UNLIKELY(_exp) (_exp)
+#endif
+
+/*
+ * GCC's argument checking for printf-like functions
+ * This is conditional until we have replaced all `"%x", void *'
+ * with `"0x%08x", (uint32) void *'. Note that %p prints different things
+ * on different platforms. Argument checking is enabled for the
+ * vmkernel, which has already been cleansed.
+ *
+ * fmtPos is the position of the format string argument, beginning at 1
+ * varPos is the position of the variable argument, beginning at 1
+ */
+
+#if defined(__GNUC__)
+# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos)))
+#else
+# define PRINTF_DECL(fmtPos, varPos)
+#endif
+
+#if defined(__GNUC__)
+# define SCANF_DECL(fmtPos, varPos) __attribute__((__format__(__scanf__, fmtPos, varPos)))
+#else
+# define SCANF_DECL(fmtPos, varPos)
+#endif
+
+/*
+ * UNUSED_PARAM should surround the parameter name and type declaration,
+ * e.g. "int MyFunction(int var1, UNUSED_PARAM(int var2))"
+ *
+ */
+
+#ifndef UNUSED_PARAM
+# if defined(__GNUC__)
+# define UNUSED_PARAM(_parm) _parm __attribute__((__unused__))
+# else
+# define UNUSED_PARAM(_parm) _parm
+# endif
+#endif
+
+/*
+ * REGPARM defaults to REGPARM3, i.e., a requent that gcc
+ * puts the first three arguments in registers. (It is fine
+ * if the function has fewer than three args.) Gcc only.
+ * Syntactically, put REGPARM where you'd put INLINE or NORETURN.
+ */
+
+#if defined(__GNUC__)
+# define REGPARM0 __attribute__((regparm(0)))
+# define REGPARM1 __attribute__((regparm(1)))
+# define REGPARM2 __attribute__((regparm(2)))
+# define REGPARM3 __attribute__((regparm(3)))
+# define REGPARM REGPARM3
+#else
+# define REGPARM0
+# define REGPARM1
+# define REGPARM2
+# define REGPARM3
+# define REGPARM
+#endif
+
+/*
+ * ALIGNED specifies minimum alignment in "n" bytes.
+ */
+
+#ifdef __GNUC__
+#define ALIGNED(n) __attribute__((__aligned__(n)))
+#else
+#define ALIGNED(n)
+#endif
+
+/*
+ ***********************************************************************
+ * STRUCT_OFFSET_CHECK -- */ /**
+ *
+ * \brief Check if the actual offsef of a member in a structure
+ * is what is expected
+ *
+ *
+ * \param[in] STRUCT Structure the member is a part of.
+ * \param[in] MEMBER Member to check the offset of.
+ * \param[in] OFFSET Expected offset of MEMBER in STRUCTURE.
+ * \param[in] DEBUG_EXTRA Additional bytes to be added to OFFSET to
+ * compensate for extra info in debug builds.
+ *
+ ***********************************************************************
+ */
+#ifdef VMX86_DEBUG
+#define STRUCT_OFFSET_CHECK(STRUCT, MEMBER, OFFSET, DEBUG_EXTRA) \
+ ASSERT_ON_COMPILE(vmk_offsetof(STRUCT, MEMBER) == (OFFSET + DEBUG_EXTRA))
+#else
+#define STRUCT_OFFSET_CHECK(STRUCT, MEMBER, OFFSET, DEBUG_EXTRA) \
+ ASSERT_ON_COMPILE(vmk_offsetof(STRUCT, MEMBER) == OFFSET)
+#endif
+
+/*
+ ***********************************************************************
+ * STRUCT_SIZE_CHECK -- */ /**
+ *
+ * \brief Check if the actual size of a structure is what is expected
+ *
+ *
+ * \param[in] STRUCT Structure whose size is to be checked.
+ * \param[in] SIZE Expected size of STRUCT.
+ * \param[in] DEBUG_EXTRA Additional bytes to be added to SIZE to
+ * compensate for extra info in debug builds.
+ *
+ ***********************************************************************
+ */
+#ifdef VMX86_DEBUG
+#define STRUCT_SIZE_CHECK(STRUCT, SIZE, DEBUG_EXTRA) \
+ ASSERT_ON_COMPILE(sizeof(STRUCT) == (SIZE + DEBUG_EXTRA))
+#else
+#define STRUCT_SIZE_CHECK(STRUCT, SIZE, DEBUG_EXTRA) \
+ ASSERT_ON_COMPILE(sizeof(STRUCT) == SIZE)
+#endif
+
+/*
+ * __func__ is a stringified function name that is part of the C99 standard. The block
+ * below defines __func__ on older systems where the compiler does not support that
+ * macro.
+ */
+#if defined(__GNUC__) \
+ && ((__GNUC__ == 2 && __GNUC_MINOR < 96) \
+ || (__GNUC__ < 2))
+# define __func__ __FUNCTION__
+#endif
+
+/*
+ * Once upon a time, this was used to silence compiler warnings that
+ * get generated when the compiler thinks that a function returns
+ * when it is marked noreturn. Don't do it. Use NOT_REACHED().
+ */
+
+#define INFINITE_LOOP() do { } while (1)
+
+/*
+ * On FreeBSD (for the tools build), size_t is typedef'd if _BSD_SIZE_T_
+ * is defined. Use the same logic here so we don't define it twice. [greg]
+ */
+#ifdef __FreeBSD__
+# ifdef _BSD_SIZE_T_
+# undef _BSD_SIZE_T_
+# ifdef VM_I386
+# ifdef VM_X86_64
+ typedef uint64 size_t;
+# else
+ typedef uint32 size_t;
+# endif
+# endif /* VM_I386 */
+# endif
+
+# ifdef _BSD_SSIZE_T_
+# undef _BSD_SSIZE_T_
+# define _SSIZE_T
+# define __ssize_t_defined
+# define _SSIZE_T_DECLARED
+# ifdef VM_I386
+# ifdef VM_X86_64
+ typedef int64 ssize_t;
+# else
+ typedef int32 ssize_t;
+# endif
+# endif /* VM_I386 */
+# endif
+
+#else
+# ifndef _SIZE_T
+# define _SIZE_T
+# ifdef VM_I386
+# ifdef VM_X86_64
+ typedef uint64 size_t;
+# else
+ typedef uint32 size_t;
+# endif
+# endif /* VM_I386 */
+# endif
+
+# if !defined(FROBOS) && !defined(_SSIZE_T) && !defined(ssize_t) && \
+ !defined(__ssize_t_defined) && !defined(_SSIZE_T_DECLARED)
+# define _SSIZE_T
+# define __ssize_t_defined
+# define _SSIZE_T_DECLARED
+# ifdef VM_I386
+# ifdef VM_X86_64
+ typedef int64 ssize_t;
+# else
+ typedef int32 ssize_t;
+# endif
+# endif /* VM_I386 */
+# endif
+
+#endif
+
+/*
+ * Format modifier for printing pid_t. On sun the pid_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The pid is %"FMTPID".\n", pid);
+ */
+#ifdef sun
+# ifdef VM_X86_64
+# define FMTPID "d"
+# else
+# define FMTPID "lu"
+# endif
+#else
+# define FMTPID "d"
+#endif
+
+/*
+ * Format modifier for printing uid_t. On sun the uid_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The uid is %"FMTUID".\n", uid);
+ */
+#ifdef sun
+# ifdef VM_X86_64
+# define FMTUID "u"
+# else
+# define FMTUID "lu"
+# endif
+#else
+# define FMTUID "u"
+#endif
+
+/*
+ * Format modifier for printing mode_t. On sun the mode_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The mode is %"FMTMODE".\n", mode);
+ */
+#ifdef sun
+# ifdef VM_X86_64
+# define FMTMODE "o"
+# else
+# define FMTMODE "lo"
+# endif
+#else
+# define FMTMODE "o"
+#endif
+
+/*
+ * Format modifier for printing time_t. Most platforms define a time_t to be
+ * a long int, but on FreeBSD (as of 5.0, it seems), the time_t is a signed
+ * size quantity. Refer to the definition of FMTSZ to see why we need silly
+ * preprocessor arithmetic.
+ * Use this like this: printf("The mode is %"FMTTIME".\n", time);
+ */
+#if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5)
+# define FMTTIME FMTSZ"d"
+#else
+# define FMTTIME "ld"
+#endif
+
+/*
+ * Define MXSemaHandle here so both vmmon and vmx see this definition.
+ */
+
+#ifdef _WIN32
+typedef uintptr_t MXSemaHandle;
+#else
+typedef int MXSemaHandle;
+#endif
+
+/*
+ * Define type for poll device handles.
+ */
+
+#ifdef _WIN32
+typedef uintptr_t PollDevHandle;
+#else
+typedef int PollDevHandle;
+#endif
+
+/*
+ * Define the utf16_t type.
+ */
+
+#if defined(_WIN32) && defined(_NATIVE_WCHAR_T_DEFINED)
+typedef wchar_t utf16_t;
+#else
+typedef uint16 utf16_t;
+#endif
+
+#endif /* _VM_BASIC_TYPES_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+#ifndef VM_DEVICE_VERSION_H
+#define VM_DEVICE_VERSION_H
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMCORE
+#include "includeCheck.h"
+
+#ifdef _WIN32
+#include "guiddef.h"
+#endif
+
+/* LSILogic 53C1030 Parallel SCSI controller
+ * LSILogic SAS1068 SAS controller
+ */
+#define PCI_VENDOR_ID_LSILOGIC 0x1000
+#define PCI_DEVICE_ID_LSI53C1030 0x0030
+#define PCI_DEVICE_ID_LSISAS1068 0x0054
+
+/* Our own PCI IDs
+ * VMware SVGA II (Unified VGA)
+ * VMware SVGA (PCI Accelerator)
+ * VMware vmxnet (Idealized NIC)
+ * VMware vmxscsi (Abortive idealized SCSI controller)
+ * VMware chipset (Subsystem ID for our motherboards)
+ * VMware e1000 (Subsystem ID)
+ * VMware vmxnet3 (Uniform Pass Through NIC)
+ */
+#define PCI_VENDOR_ID_VMWARE 0x15AD
+#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
+#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710
+#define PCI_DEVICE_ID_VMWARE_NET 0x0720
+#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730
+#define PCI_DEVICE_ID_VMWARE_VMCI 0x0740
+#define PCI_DEVICE_ID_VMWARE_CHIPSET 0x1976
+#define PCI_DEVICE_ID_VMWARE_82545EM 0x0750 /* single port */
+#define PCI_DEVICE_ID_VMWARE_82546EB 0x0760 /* dual port */
+#define PCI_DEVICE_ID_VMWARE_EHCI 0x0770
+#define PCI_DEVICE_ID_VMWARE_1394 0x0780
+#define PCI_DEVICE_ID_VMWARE_BRIDGE 0x0790
+#define PCI_DEVICE_ID_VMWARE_ROOTPORT 0x07A0
+#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0
+#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0
+
+/* The hypervisor device might grow. Please leave room
+ * for 7 more subfunctions.
+ */
+#define PCI_DEVICE_ID_VMWARE_HYPER 0x0800
+#define PCI_DEVICE_ID_VMWARE_VMI 0x0801
+
+#define PCI_DEVICE_VMI_CLASS 0x05
+#define PCI_DEVICE_VMI_SUBCLASS 0x80
+#define PCI_DEVICE_VMI_INTERFACE 0x00
+#define PCI_DEVICE_VMI_REVISION 0x01
+
+/* From linux/pci_ids.h:
+ * AMD Lance Ethernet controller
+ * BusLogic SCSI controller
+ * Ensoniq ES1371 sound controller
+ */
+#define PCI_VENDOR_ID_AMD 0x1022
+#define PCI_DEVICE_ID_AMD_VLANCE 0x2000
+#define PCI_VENDOR_ID_BUSLOGIC 0x104B
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040
+#define PCI_VENDOR_ID_ENSONIQ 0x1274
+#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
+
+/* From linux/pci_ids.h:
+ * Intel 82439TX (430 HX North Bridge)
+ * Intel 82371AB (PIIX4 South Bridge)
+ * Intel 82443BX (440 BX North Bridge and AGP Bridge)
+ * Intel 82545EM (e1000, server adapter, single port)
+ * Intel 82546EB (e1000, server adapter, dual port)
+ * Intel ICH7_16 (Hight Definition Audio controller)
+ */
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_DEVICE_ID_INTEL_82439TX 0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
+#define PCI_DEVICE_ID_INTEL_82443BX 0x7190
+#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191
+#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 /* Used when no AGP support */
+#define PCI_DEVICE_ID_INTEL_82545EM 0x100f
+#define PCI_DEVICE_ID_INTEL_82546EB 0x1010
+#define PCI_DEVICE_ID_INTEL_ICH7_16 0x27d8
+
+
+/************* Strings for IDE Identity Fields **************************/
+#define VIDE_ID_SERIAL_STR "00000000000000000001" /* Must be 20 Bytes */
+#define VIDE_ID_FIRMWARE_STR "00000001" /* Must be 8 Bytes */
+
+/* No longer than 40 Bytes */
+#define VIDE_ATA_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE Hard Drive"
+#define VIDE_ATAPI_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE CDROM Drive"
+
+#define ATAPI_VENDOR_ID "NECVMWar" /* Must be 8 Bytes */
+#define ATAPI_PRODUCT_ID PRODUCT_GENERIC_NAME " IDE CDROM" /* Must be 16 Bytes */
+#define ATAPI_REV_LEVEL "1.00" /* Must be 4 Bytes */
+
+#define IDE_NUM_INTERFACES 2 /* support for two interfaces */
+#define IDE_DRIVES_PER_IF 2
+
+/************* Strings for SCSI Identity Fields **************************/
+#define SCSI_DISK_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI Hard Drive"
+#define SCSI_DISK_VENDOR_NAME COMPANY_NAME
+#define SCSI_DISK_REV_LEVEL "1.0"
+#define SCSI_CDROM_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI CDROM Drive"
+#define SCSI_CDROM_VENDOR_NAME COMPANY_NAME
+#define SCSI_CDROM_REV_LEVEL "1.0"
+
+/************* SCSI implementation limits ********************************/
+#define SCSI_MAX_CONTROLLERS 4 // Need more than 1 for MSCS clustering
+#define SCSI_MAX_DEVICES 16 // BT-958 emulates only 16
+#define SCSI_IDE_CHANNEL SCSI_MAX_CONTROLLERS
+#define SCSI_IDE_HOSTED_CHANNEL (SCSI_MAX_CONTROLLERS + 1)
+#define SCSI_MAX_CHANNELS (SCSI_MAX_CONTROLLERS + 2)
+
+/************* Strings for the VESA BIOS Identity Fields *****************/
+#define VBE_OEM_STRING COMPANY_NAME " SVGA"
+#define VBE_VENDOR_NAME COMPANY_NAME
+#define VBE_PRODUCT_NAME PRODUCT_GENERIC_NAME
+
+/************* PCI implementation limits ********************************/
+#define PCI_MAX_BRIDGES 15
+
+/************* Ethernet implementation limits ***************************/
+#define MAX_ETHERNET_CARDS 10
+
+/************* PCI Passthrough implementation limits ********************/
+#define MAX_PCI_PASSTHRU_DEVICES 2
+
+/************* USB implementation limits ********************************/
+#define MAX_USB_DEVICES_PER_HOST_CONTROLLER 127
+
+/************* Strings for Host USB Driver *******************************/
+
+#ifdef _WIN32
+
+/*
+ * Globally unique ID for the VMware device interface. Define INITGUID before including
+ * this header file to instantiate the variable.
+ */
+DEFINE_GUID(GUID_DEVICE_INTERFACE_VMWARE_USB_DEVICES,
+0x2da1fe75, 0xaab3, 0x4d2c, 0xac, 0xdf, 0x39, 0x8, 0x8c, 0xad, 0xa6, 0x65);
+
+/*
+ * Globally unique ID for the VMware device setup class.
+ */
+DEFINE_GUID(GUID_CLASS_VMWARE_USB_DEVICES,
+0x3b3e62a5, 0x3556, 0x4d7e, 0xad, 0xad, 0xf5, 0xfa, 0x3a, 0x71, 0x2b, 0x56);
+
+/*
+ * This string defines the device ID string of a VMware USB device.
+ * The format is USB\Vid_XXXX&Pid_YYYY, where XXXX and YYYY are the
+ * hexadecimal representations of the vendor and product ids, respectively.
+ *
+ * The official vendor ID for VMware, Inc. is 0x0E0F.
+ * The product id for USB generic devices is 0x0001.
+ */
+#define USB_VMWARE_DEVICE_ID_WIDE L"USB\\Vid_0E0F&Pid_0001"
+#define USB_DEVICE_ID_LENGTH (sizeof(USB_VMWARE_DEVICE_ID_WIDE) / sizeof(WCHAR))
+
+#ifdef UNICODE
+#define USB_PNP_SETUP_CLASS_NAME L"VMwareUSBDevices"
+#define USB_PNP_DRIVER_NAME L"vmusb"
+#else
+#define USB_PNP_SETUP_CLASS_NAME "VMwareUSBDevices"
+#define USB_PNP_DRIVER_NAME "vmusb"
+#endif
+#endif
+
+#endif /* VM_DEVICE_VERSION_H */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vmnet_def.h
+ *
+ * - definitions which are (mostly) not vmxnet or vlance specific
+ */
+
+#ifndef _VMNET_DEF_H_
+#define _VMNET_DEF_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMNIXMOD
+#include "includeCheck.h"
+
+/*
+ * capabilities - not all of these are implemented in the virtual HW
+ * (eg VLAN support is in the virtual switch) so even vlance
+ * can use them
+ */
+#define VMNET_CAP_SG 0x0001 /* Can do scatter-gather transmits. */
+#define VMNET_CAP_IP4_CSUM 0x0002 /* Can checksum only TCP/UDP over IPv4. */
+#define VMNET_CAP_HW_CSUM 0x0004 /* Can checksum all packets. */
+#define VMNET_CAP_HIGH_DMA 0x0008 /* Can DMA to high memory. */
+#define VMNET_CAP_TOE 0x0010 /* Supports TCP/IP offload. */
+#define VMNET_CAP_TSO 0x0020 /* Supports TCP Segmentation offload */
+#define VMNET_CAP_SW_TSO 0x0040 /* Supports SW TCP Segmentation */
+#define VMNET_CAP_VMXNET_APROM 0x0080 /* Vmxnet APROM support */
+#define VMNET_CAP_HW_TX_VLAN 0x0100 /* Can we do VLAN tagging in HW */
+#define VMNET_CAP_HW_RX_VLAN 0x0200 /* Can we do VLAN untagging in HW */
+#define VMNET_CAP_SW_VLAN 0x0400 /* Can we do VLAN tagging/untagging in SW */
+#define VMNET_CAP_WAKE_PCKT_RCV 0x0800 /* Can wake on network packet recv? */
+#define VMNET_CAP_ENABLE_INT_INLINE 0x1000 /* Enable Interrupt Inline */
+#define VMNET_CAP_ENABLE_HEADER_COPY 0x2000 /* copy header for vmkernel */
+#define VMNET_CAP_TX_CHAIN 0x4000 /* Guest can use multiple tx entries for a pkt */
+#define VMNET_CAP_RX_CHAIN 0x8000 /* a pkt can span multiple rx entries */
+#define VMNET_CAP_LPD 0x10000 /* large pkt delivery */
+#define VMNET_CAP_BPF 0x20000 /* BPF Support in VMXNET Virtual Hardware */
+#define VMNET_CAP_SG_SPAN_PAGES 0x40000 /* Can do scatter-gather span multiple pages transmits. */
+#define VMNET_CAP_IP6_CSUM 0x80000 /* Can do IPv6 csum offload. */
+#define VMNET_CAP_TSO6 0x100000 /* Can do TSO segmentation offload for IPv6 pkts. */
+#define VMNET_CAP_TSO256k 0x200000 /* Can do TSO segmentation offload for pkts up to 256kB. */
+#endif // _VMNET_DEF_H_
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/debug.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/strlog.h>
+#include <sys/kmem.h>
+#include <sys/stat.h>
+#include <sys/kstat.h>
+#include <sys/vtrace.h>
+#include <sys/dlpi.h>
+#include <sys/strsun.h>
+#include <sys/ethernet.h>
+#include <sys/modctl.h>
+#include <sys/errno.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/gld.h>
+#include <sys/pci.h>
+#include <sys/strsubr.h>
+
+/*
+ * This used to be defined in sys/gld.h, but was flagged as private,
+ * and we used it anyway. Now it no longer exists, and we're stuck
+ * with it for the time being.
+ */
+#ifndef GLD_MAX_MULTICAST
+#define GLD_MAX_MULTICAST 64
+#endif
+
+#define __intptr_t_defined
+#define _STDINT_H
+#include "vm_basic_types.h"
+#include "vmxnet2_def.h"
+#include "vm_device_version.h"
+#include "net.h"
+#include "buildNumber.h"
+
+#define SOLVMXNET_SUCCESS 1
+#define SOLVMXNET_FAILURE 0
+
+#ifdef SOLVMXNET_DEBUG_LEVEL
+static int vxn_debug = SOLVMXNET_DEBUG_LEVEL;
+#define DPRINTF(n, args) if (vxn_debug>(n)) cmn_err args
+#else
+#define DPRINTF(n, args)
+#endif
+
+static char ident[] = "VMware Ethernet Adapter b" BUILD_NUMBER_NUMERIC_STRING;
+char _depends_on[] = {"misc/gld"};
+
+#define MAX_NUM_RECV_BUFFERS 128
+#define DEFAULT_NUM_RECV_BUFFERS 100
+#define MAX_NUM_XMIT_BUFFERS 128
+#define DEFAULT_NUM_XMIT_BUFFERS 100
+#define CRC_POLYNOMIAL_LE 0xedb88320UL
+#define SOLVMXNET_MAXNAME 20
+#define MAX_TX_WAIT_ON_STOP 2000
+
+#define ETHERALIGN 2
+#define SLACKBYTES 4
+#define MAXPKTBUF (14 + ETHERALIGN + ETHERMTU + SLACKBYTES)
+
+
+#define QHIWATER (MAX_NUM_RECV_BUFFERS*ETHERMTU)
+
+#define OUTB(dp, p, v) \
+ ddi_put8((dp)->vxnIOHdl, \
+ (uint8_t *)((caddr_t)((dp)->vxnIOp) + (p)), v)
+#define OUTW(dp, p, v) \
+ ddi_put16((dp)->vxnIOHdl, \
+ (uint16_t *)((caddr_t)((dp)->vxnIOp) + (p)), v)
+#define OUTL(dp, p, v) \
+ ddi_put32((dp)->vxnIOHdl, \
+ (uint32_t *)((caddr_t)((dp)->vxnIOp) + (p)), v)
+#define INB(dp, p) \
+ ddi_get8((dp)->vxnIOHdl, \
+ (uint8_t *)(((caddr_t)(dp)->vxnIOp) + (p)))
+#define INW(dp, p) \
+ ddi_get16((dp)->vxnIOHdl, \
+ (uint16_t *)(((caddr_t)(dp)->vxnIOp) + (p)))
+#define INL(dp, p) \
+ ddi_get32((dp)->vxnIOHdl, \
+ (uint32_t *)(((caddr_t)(dp)->vxnIOp) + (p)))
+
+#define VMXNET_INC(val, max) \
+ val++; \
+ if (UNLIKELY(val == max)) { \
+ val = 0; \
+ }
+
+#define TX_RINGBUF_MBLK(dp, idx) (dp->txRingBuf[idx].mblk)
+#define TX_RINGBUF_DMAMEM(dp, idx) (dp->txRingBuf[idx].dmaMem)
+
+typedef struct {
+ caddr_t buf; /* Virtual address */
+ uint32_t phyBuf; /* Physical address */
+ size_t bufLen; /* Buffer length */
+ ddi_dma_cookie_t cookie; /* Dma cookie */
+ uint_t cookieCount; /* Cookie count */
+ ddi_dma_handle_t dmaHdl; /* Dma handle */
+ ddi_acc_handle_t dataAccHdl; /* Dada access handle */
+} dma_buf_t;
+
+typedef struct rx_dma_buf {
+ dma_buf_t dmaDesc; /* Dma descriptor */
+ mblk_t *mblk; /* Streams message block */
+ frtn_t freeCB; /* Free callback */
+ struct vxn_softc *softc; /* Back pointer to softc */
+ struct rx_dma_buf *next; /* Next one in list */
+} rx_dma_buf_t;
+
+typedef struct vxn_stats {
+ uint32_t errxmt; /* Transmit errors */
+ uint32_t errrcv; /* Receive errors */
+ uint32_t runt; /* Runt packets */
+ uint32_t norcvbuf; /* Buffer alloc errors */
+ uint32_t interrupts; /* Interrupts */
+ uint32_t defer; /* Deferred transmits */
+} vxn_stats_t;
+
+typedef struct tx_ring_buf {
+ mblk_t *mblk;
+ dma_buf_t dmaMem;
+} tx_ring_buf_t;
+
+typedef struct vxn_softc {
+ char drvName[SOLVMXNET_MAXNAME]; /* Driver name string */
+ int unit; /* Driver instance */
+ vxn_stats_t stats; /* Stats */
+
+ dev_info_t *dip; /* Info pointer */
+ ddi_iblock_cookie_t iblockCookie; /* Interrupt block cookie */
+ gld_mac_info_t *macInfo; /* GLD mac info */
+ ddi_acc_handle_t confHdl; /* Configuration space handle */
+ ddi_acc_handle_t vxnIOHdl; /* I/O space handle */
+ caddr_t vxnIOp; /* I/O space pointer */
+ boolean_t morphed; /* Adapter morphed ? */
+
+ kmutex_t intrlock; /* Interrupt lock */
+ kmutex_t xmitlock; /* Transmit lock */
+ kmutex_t rxlistlock; /* Rx free pool lock */
+
+ boolean_t nicActive; /* NIC active flag */
+ boolean_t inIntr; /* Interrupt processing flag */
+
+ struct ether_addr devAddr; /* MAC address */
+
+ uint32_t vxnNumRxBufs; /* Number of reveice buffers */
+ uint32_t vxnNumTxBufs; /* Number of transmit buffers */
+
+ dma_buf_t driverDataDmaMem; /* Driver Data (dma handle) */
+ Vmxnet2_DriverData *driverData; /* Driver Data */
+ void *driverDataPhy; /* Driver Data busaddr pointer */
+ Vmxnet2_RxRingEntry *rxRing; /* Receive ring */
+ Vmxnet2_TxRingEntry *txRing; /* Transmit ring */
+ ddi_dma_handle_t txDmaHdl; /* Tx buffers dma handle */
+ rx_dma_buf_t *rxRingBuffPtr[MAX_NUM_RECV_BUFFERS];
+ /* DMA buffers associated with rxRing */
+ tx_ring_buf_t txRingBuf[MAX_NUM_XMIT_BUFFERS]; /* tx Ring buffers */
+
+ rx_dma_buf_t *rxFreeBufList;
+ uint32_t rxNumFreeBufs; /* current # of buffers in pool */
+ uint32_t rxMaxFreeBufs; /* max # of buffers in pool */
+
+ uint32_t txPending; /* Pending transmits */
+ uint32_t maxTxFrags; /* Max Tx fragments */
+
+ int multiCount; /* Multicast address count */
+ struct ether_addr multicastList[GLD_MAX_MULTICAST]; /* Multicast list */
+
+ struct vxn_softc *next; /* Circular list of instances */
+ struct vxn_softc *prev;
+} vxn_softc_t;
+
+/* used for rx buffers or buffers allocated by ddi_dma_mem_alloc() */
+static ddi_dma_attr_t vxn_dma_attrs = {
+ DMA_ATTR_V0, /* dma_attr version */
+ 0, /* dma_attr_addr_lo */
+ (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */
+ 0x7FFFFFFF, /* dma_attr_count_max */
+ 4, /* dma_attr_align */
+ 0x3F, /* dma_attr_burstsizes */
+ 1, /* dma_attr_minxfer */
+ (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */
+ (uint64_t)0xFFFFFFFF, /* dma_attr_seg */
+ 1, /* dma_attr_sgllen */
+ 1, /* dma_attr_granular */
+ 0, /* dma_attr_flags */
+};
+
+/* used for tx buffers */
+static ddi_dma_attr_t vxn_dma_attrs_tx = {
+ DMA_ATTR_V0, /* dma_attr version */
+ 0, /* dma_attr_addr_lo */
+ (uint64_t)0xFFFFFFFF, /* dma_attr_addr_hi */
+ 0x7FFFFFFF, /* dma_attr_count_max */
+ 1, /* dma_attr_align */
+ 0x3F, /* dma_attr_burstsizes */
+ 1, /* dma_attr_minxfer */
+ (uint64_t)0xFFFFFFFF, /* dma_attr_maxxfer */
+ (uint64_t)0xFFFFFFFF, /* dma_attr_seg */
+ 1, /* dma_attr_sgllen */
+ 1, /* dma_attr_granular */
+ 0, /* dma_attr_flags */
+};
+
+
+static struct ether_addr etherbroadcastaddr = {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+};
+
+static struct ddi_device_acc_attr vxn_buf_attrs = {
+ DDI_DEVICE_ATTR_V0,
+ DDI_STRUCTURE_LE_ACC,
+ DDI_STRICTORDER_ACC
+};
+
+static struct ddi_device_acc_attr dev_attr = {
+ DDI_DEVICE_ATTR_V0,
+ DDI_STRUCTURE_LE_ACC,
+ DDI_STRICTORDER_ACC
+};
+
+static vxn_softc_t vxnList; /* for debugging */
+static kmutex_t vxnListLock;
+
+static void *Vxn_Memset(void *s, int c, size_t n);
+static int Vxn_Reset(gld_mac_info_t *macInfo);
+static int Vxn_SetPromiscuous(gld_mac_info_t *macInfo, int flag);
+static int Vxn_GetStats(gld_mac_info_t *macInfo, struct gld_stats *gs);
+static void Vxn_ApplyAddressFilter(vxn_softc_t *dp);
+static int Vxn_SetMulticast(gld_mac_info_t *macinfo, uint8_t *ep, int flag);
+static int Vxn_SetMacAddress(gld_mac_info_t *macInfo, uint8_t *mac);
+static int Vxn_Start(gld_mac_info_t *macInfo);
+static int Vxn_Stop(gld_mac_info_t *macInfo);
+static void Vxn_FreeTxBuf(vxn_softc_t *dp, int idx);
+static int Vxn_EncapTxBuf(vxn_softc_t *dp, mblk_t *mp, Vmxnet2_TxRingEntry *xre,
+ tx_ring_buf_t *txBuf);
+static int Vxn_Send(gld_mac_info_t *macinfo, mblk_t *mp);
+static boolean_t Vxn_TxComplete(vxn_softc_t *dp, boolean_t *reschedp);
+static boolean_t Vxn_Receive(vxn_softc_t *dp);
+static u_int Vxn_Interrupt(gld_mac_info_t *macInfo);
+static void Vxn_ReclaimRxBuf(rx_dma_buf_t *rxDesc);
+static void Vxn_FreeRxBuf(rx_dma_buf_t *rxDesc);
+static rx_dma_buf_t *Vxn_AllocRxBuf(vxn_softc_t *dp, int cansleep);
+static void Vxn_FreeInitBuffers(vxn_softc_t *dp);
+static int Vxn_AllocInitBuffers(vxn_softc_t *dp);
+static void Vxn_FreeDmaMem(dma_buf_t *dma);
+static int Vxn_AllocDmaMem(vxn_softc_t *dp, int size, int cansleep, dma_buf_t *dma);
+static void Vxn_FreeDriverData(vxn_softc_t *dp);
+static int Vxn_AllocDriverData(vxn_softc_t *dp);
+static int Vxn_Attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+static int Vxn_Detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
+static int Vxn_AllocRxBufPool(vxn_softc_t *dp);
+static void Vxn_FreeRxBufPool(vxn_softc_t *dp);
+static rx_dma_buf_t * Vxn_AllocRxBufFromPool(vxn_softc_t *dp);
+static void Vxn_FreeRxBufToPool(rx_dma_buf_t *rxDesc);
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_Memset --
+ * memset() (Because bzero does not get resolved by module loader)
+ *
+ * Results:
+ * pointer to the memory area s
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static void *
+Vxn_Memset(void *s, int c, size_t n)
+{
+ while (n--) {
+ ((uint8_t *)s)[n] = c;
+ }
+
+ return s;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_Reset --
+ * Stub routine to reset hardware. Presently does nothing. Start/Stop should
+ * take care of resets.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_Reset(gld_mac_info_t *macInfo)
+{
+ return GLD_SUCCESS;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_SetPromiscuous --
+ * Set/Reset NIC to/from promiscuous mode
+ *
+ * Results:
+ * GLD_SUCCESS
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_SetPromiscuous(gld_mac_info_t *macInfo, int flag)
+{
+ vxn_softc_t *dp = (vxn_softc_t *)macInfo->gldm_private;
+ Vmxnet2_DriverData *dd = dp->driverData;
+
+ mutex_enter(&dp->intrlock);
+ if (flag == GLD_MAC_PROMISC_PHYS) {
+ dd->ifflags |= VMXNET_IFF_PROMISC;
+ } else if (flag == GLD_MAC_PROMISC_MULTI) {
+ /*
+ * This should really set VMXNET_IFF_ALLMULTI,
+ * but unfortunately it doesn't exist. The next
+ * best thing would be to set the LADRFs to all
+ * 0xFFs and set VMXNET_IFF_MULTICAST, but that
+ * opens up a whole new set of potential pitfalls,
+ * so this is a reasonable temporary solution.
+ */
+ dd->ifflags |= VMXNET_IFF_PROMISC;
+ } else if (flag == GLD_MAC_PROMISC_NONE) {
+ dd->ifflags &= ~VMXNET_IFF_PROMISC;
+ } else {
+ /* This could be GLD_MAC_PROMISC_NOOP? */
+ mutex_exit(&dp->intrlock);
+ cmn_err(CE_WARN, "%s%d: Vxn_SetPromiscuous: Unexpected mode flag: 0x%x",
+ dp->drvName, dp->unit, flag);
+
+ return GLD_FAILURE;
+ }
+
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_UPDATE_IFF);
+ mutex_exit(&dp->intrlock);
+
+ return GLD_SUCCESS;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_GetStats --
+ * Get driver specific stats
+ *
+ * Results:
+ * GLD_SUCCESS
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_GetStats(gld_mac_info_t *macInfo, struct gld_stats *gs)
+{
+ vxn_softc_t *dp = (vxn_softc_t *)macInfo->gldm_private;
+
+ gs->glds_errxmt = dp->stats.errxmt;
+ gs->glds_errrcv = dp->stats.errrcv;
+ gs->glds_short = dp->stats.runt;
+ gs->glds_norcvbuf = dp->stats.norcvbuf;
+ gs->glds_intr = dp->stats.interrupts;
+ gs->glds_defer = dp->stats.defer;
+
+ return GLD_SUCCESS;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_ApplyAddressFilter --
+ * Go over multicast list and compute/apply address filter
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static void
+Vxn_ApplyAddressFilter(vxn_softc_t *dp)
+{
+ uint8_t *ep;
+ int i, j, bit, byte;
+ uint32_t crc, poly = CRC_POLYNOMIAL_LE;
+ Vmxnet2_DriverData *dd = dp->driverData;
+ volatile uint16_t *mcastTable = (uint16_t *)dd->LADRF;
+
+ ASSERT(MUTEX_HELD(&dp->intrlock));
+
+ /* clear the multicast filter */
+ dd->LADRF[0] = 0;
+ dd->LADRF[1] = 0;
+
+ for (i = 0; i < dp->multiCount; i++) {
+ crc = 0xffffffff;
+ ep = (uint8_t *)&dp->multicastList[i].ether_addr_octet;
+
+ for (byte = 0; byte < 6; byte++) {
+ for (bit = *ep++, j = 0; j < 8; j++, bit >>= 1) {
+ int test;
+
+ test = ((bit ^ crc) & 0x01);
+ crc >>= 1;
+
+ if (test) {
+ crc = crc ^ poly;
+ }
+ }
+ }
+
+ crc = crc >> 26;
+ mcastTable[crc >> 4] |= 1 << (crc & 0xf);
+ }
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_SetMulticast --
+ * Add delete entry from multicast list
+ *
+ * Results:
+ * GLD_FAILURE on failure
+ * GLD_SUCCESS on success
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_SetMulticast(gld_mac_info_t *macinfo, uint8_t *ep, int flag)
+{
+ int i;
+ int copyLen;
+ vxn_softc_t *dp = (vxn_softc_t *)macinfo->gldm_private;
+ Vmxnet2_DriverData *dd = dp->driverData;
+
+ if (flag == GLD_MULTI_ENABLE) {
+ /*
+ * Exceeded multicast address limit
+ */
+ if (dp->multiCount >= GLD_MAX_MULTICAST) {
+ return GLD_FAILURE;
+ }
+
+ /*
+ * Add mac address to multicast list
+ */
+ bcopy(ep, dp->multicastList[dp->multiCount].ether_addr_octet,
+ ETHERADDRL);
+ dp->multiCount++;
+ }
+ else {
+ for (i=0; i<dp->multiCount; i++) {
+ if (bcmp(ep, dp->multicastList[i].ether_addr_octet, ETHERADDRL) == 0) {
+ goto found;
+ }
+ }
+ return GLD_FAILURE;
+
+ found:
+ /*
+ * Delete mac address from multicast list
+ */
+ copyLen = (dp->multiCount - (i+1)) * sizeof(struct ether_addr);
+ if (copyLen > 0) {
+ bcopy(&dp->multicastList[i+1], &dp->multicastList[i], copyLen);
+ }
+ dp->multiCount--;
+ }
+
+ /*
+ * Compute address filter from list of addressed and apply it
+ */
+ mutex_enter(&dp->intrlock);
+ Vxn_ApplyAddressFilter(dp);
+
+ if (dp->multiCount) {
+ ASSERT(dd->LADRF[0] || dd->LADRF[1]);
+ dd->ifflags |= VMXNET_IFF_MULTICAST;
+ } else {
+ ASSERT(!(dd->LADRF[0] || dd->LADRF[1]));
+ dd->ifflags &= ~VMXNET_IFF_MULTICAST;
+ }
+
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_UPDATE_IFF);
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_UPDATE_LADRF);
+ mutex_exit(&dp->intrlock);
+
+ return GLD_SUCCESS;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_SetMacAddress --
+ * Change device MAC address
+ *
+ * Results:
+ * GLD_SUCCESS
+ * GLD_FAILURE
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_SetMacAddress(gld_mac_info_t *macInfo, uint8_t *mac)
+{
+ int i;
+ int err = GLD_SUCCESS;
+ vxn_softc_t * dp = (vxn_softc_t *)macInfo->gldm_private;
+
+ mutex_enter(&dp->intrlock);
+ mutex_enter(&dp->xmitlock);
+
+ /*
+ * Don't change MAC address on a running NIC
+ */
+ if (dp->nicActive) {
+ err = GLD_FAILURE;
+ goto out;
+ }
+
+ /*
+ * Save new MAC address
+ */
+ for (i = 0; i < 6; i++) {
+ dp->devAddr.ether_addr_octet[i] = mac[i];
+ }
+
+ /*
+ * Push new MAC address down into hardware
+ */
+ for (i = 0; i < 6; i++) {
+ OUTB(dp, VMXNET_MAC_ADDR + i, mac[i]);
+ }
+
+out:
+ mutex_exit(&dp->xmitlock);
+ mutex_exit(&dp->intrlock);
+ return err;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_Start --
+ * Device start routine. Called on "ifconfig plumb"
+ *
+ * Results:
+ * GLD_SUCCESS
+ * GLD_FAILURE
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_Start(gld_mac_info_t *macInfo)
+{
+ int err = GLD_SUCCESS;
+ uint32_t r, capabilities, features;
+ vxn_softc_t * dp = (vxn_softc_t *)macInfo->gldm_private;
+
+ mutex_enter(&dp->intrlock);
+ mutex_enter(&dp->xmitlock);
+
+ if (!dp->nicActive) {
+ /*
+ * Register ring structure with hardware
+ *
+ * This downcast is OK because we requested a 32-bit physical address
+ */
+ OUTL(dp, VMXNET_INIT_ADDR, (uint32_t)(uintptr_t)dp->driverDataPhy);
+ OUTL(dp, VMXNET_INIT_LENGTH, dp->driverData->length);
+
+ /*
+ * Make sure registeration succeded
+ */
+ r = INL(dp, VMXNET_INIT_LENGTH);
+ if (!r) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Start: failed to register ring",
+ dp->drvName, dp->unit);
+ err = GLD_FAILURE;
+ goto out;
+ }
+
+ /*
+ * Get maximum tx fragments supported
+ */
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_GET_CAPABILITIES);
+ capabilities = INL(dp, VMXNET_COMMAND_ADDR);
+
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_GET_FEATURES);
+ features = INL(dp, VMXNET_COMMAND_ADDR);
+
+ DPRINTF(3, (CE_CONT, "%s%d: chip capabilities=0x%x features=0x%x\n",
+ dp->drvName, dp->unit, capabilities, features));
+
+ if ((capabilities & VMNET_CAP_SG) &&
+ (features & VMXNET_FEATURE_ZERO_COPY_TX)) {
+ dp->maxTxFrags = VMXNET2_SG_DEFAULT_LENGTH;
+ } else {
+ dp->maxTxFrags = 1;
+ }
+ ASSERT(dp->maxTxFrags >= 1);
+
+ /*
+ * Alloc Tx DMA handle
+ */
+ vxn_dma_attrs_tx.dma_attr_sgllen = dp->maxTxFrags;
+ if (ddi_dma_alloc_handle(dp->dip, &vxn_dma_attrs_tx, DDI_DMA_SLEEP,
+ NULL, &dp->txDmaHdl) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Start: failed to alloc tx dma handle",
+ dp->drvName, dp->unit);
+ err = GLD_FAILURE;
+ goto out;
+ }
+
+ /*
+ * Enable interrupts on the card
+ */
+ dp->driverData->ifflags |= VMXNET_IFF_BROADCAST | VMXNET_IFF_DIRECTED;
+
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_INTR_ENABLE);
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_UPDATE_IFF);
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_UPDATE_LADRF);
+
+ dp->nicActive = TRUE;
+ }
+
+out:
+ mutex_exit(&dp->xmitlock);
+ mutex_exit(&dp->intrlock);
+ return err;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_Stop --
+ * Device stop routine. Called on "ifconfig unplumb"
+ *
+ * Results:
+ * GLD_SUCCESS
+ * GLD_FAILURE
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_Stop(gld_mac_info_t *macInfo)
+{
+ int i;
+ int err = GLD_SUCCESS;
+ vxn_softc_t * dp = (vxn_softc_t *)macInfo->gldm_private;
+ boolean_t resched;
+
+ mutex_enter(&dp->intrlock);
+ mutex_enter(&dp->xmitlock);
+
+ if (!dp->nicActive) {
+ goto out;
+ }
+
+ /*
+ * Disable interrupts
+ */
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_INTR_DISABLE);
+
+ /*
+ * Wait for pending transmits
+ */
+ if (dp->txPending) {
+ for (i=0; i < MAX_TX_WAIT_ON_STOP && dp->txPending; i++) {
+ delay(drv_usectohz(1000));
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_CHECK_TX_DONE);
+ (void) Vxn_TxComplete(dp, &resched);
+ /*
+ * Don't worry about rescheduling transmits - GLD handles
+ * this automatically.
+ */
+ }
+ }
+ if (dp->txPending) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Stop: giving up on %d pending transmits",
+ dp->drvName, dp->unit, dp->txPending);
+ }
+
+ OUTL(dp, VMXNET_INIT_ADDR, 0);
+ dp->nicActive = FALSE;
+
+ /*
+ * Free Tx DMA handle
+ *
+ * The ddi_dma_free_handle() man page says that ddi_dma_unbind_handle() must be called
+ * prior to calling ddi_dma_free_handle().
+ * However, call to ddi_dma_unbind_handle() is not required here, because
+ * ddi_dma_addr_bind_handle() and matching ddi_dma_unbind_handle() are called from
+ * Vxn_EncapTxBuf().
+ * xmitlock is held in Vxn_EncapTxBuf() as well as acquired above in Vxn_Stop().
+ */
+ ddi_dma_free_handle(&dp->txDmaHdl);
+ dp->txDmaHdl = NULL;
+
+out:
+ mutex_exit(&dp->xmitlock);
+ mutex_exit(&dp->intrlock);
+ return err;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_FreeTxBuf --
+ * Free transmit buffer
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static void
+Vxn_FreeTxBuf(vxn_softc_t *dp, int idx)
+{
+ mblk_t **txMblkp = &TX_RINGBUF_MBLK(dp, idx);
+ dma_buf_t *dmaMem = &TX_RINGBUF_DMAMEM(dp, idx);
+
+ if (*txMblkp) {
+ freemsg(*txMblkp);
+ *txMblkp = NULL;
+ }
+
+ if (dmaMem->buf) {
+ Vxn_FreeDmaMem(dmaMem);
+ ASSERT(dmaMem->buf == NULL);
+ }
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_EncapTxBuf --
+ * Go over dma mappings of Tx buffers and drop buffer physical address
+ * into ring entry
+ *
+ * Results:
+ * SOLVMXNET_SUCCESS on success
+ * SOLVMXNET_FAILURE on failure
+ *
+ * Side effects:
+ * None
+ *---------------- -------------------------------------------------------------
+ */
+static int
+Vxn_EncapTxBuf(vxn_softc_t *dp,
+ mblk_t *mp,
+ Vmxnet2_TxRingEntry *xre,
+ tx_ring_buf_t *txBuf)
+{
+ int frag;
+ int fragcount;
+ int rval;
+ mblk_t *tp;
+ mblk_t *mblk;
+ boolean_t needPullup = FALSE;
+ boolean_t dmaMemAlloced = FALSE;
+
+ ASSERT(txBuf);
+ ASSERT(txBuf->mblk == NULL);
+ ASSERT(MUTEX_HELD(&dp->xmitlock));
+
+ xre->sg.length = 0;
+ xre->flags = 0;
+
+ fragcount = 0;
+ for (tp = mp; tp != NULL; tp = tp->b_cont) {
+ fragcount++;
+ }
+ if (fragcount > dp->maxTxFrags) {
+ needPullup = TRUE;
+ }
+
+pullup:
+ frag = 0;
+ if (needPullup) {
+ if (!(mblk = msgpullup(mp, -1))) {
+ cmn_err(CE_WARN, "%s%d: Vxn_EncapTxBuf: msgpullup failed",
+ dp->drvName, dp->unit);
+ goto err;
+ }
+ } else {
+ mblk = mp;
+ }
+
+ /*
+ * Go through message chain and drop packet pointers into ring
+ * scatter/gather array
+ */
+ for (tp = mblk; tp != NULL; tp = tp->b_cont) {
+
+ uint_t nCookies;
+ ddi_dma_cookie_t dmaCookie;
+ int len = tp->b_wptr - tp->b_rptr;
+
+ if (len) {
+ /*
+ * Associate tx buffer with dma handle
+ */
+ ASSERT(dp->txDmaHdl);
+ if ((rval = ddi_dma_addr_bind_handle(dp->txDmaHdl, NULL, (caddr_t)tp->b_rptr,
+ len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
+ DDI_DMA_DONTWAIT, NULL,
+ &dmaCookie, &nCookies))
+ != DDI_DMA_MAPPED) {
+
+ /*
+ * Try to handle bind failure caused by a page boundary spill
+ * by allocating a private dma buffer and copying data into it
+ */
+ if ((rval == DDI_DMA_TOOBIG) && !dmaMemAlloced ) {
+ /*
+ * Force pullup
+ */
+ if (!needPullup && (dp->maxTxFrags > 1)) {
+ needPullup = TRUE;
+ goto pullup;
+ }
+
+ if (Vxn_AllocDmaMem(dp, len, FALSE, &txBuf->dmaMem)
+ != SOLVMXNET_SUCCESS) {
+ goto err;
+ }
+
+ dmaMemAlloced = TRUE;
+
+ /*
+ * Copy data into DMA capable buffer
+ */
+ bcopy(tp->b_rptr, txBuf->dmaMem.buf, len);
+
+ /*
+ * Stick buffer physical addr in the ring
+ */
+ xre->sg.sg[frag].addrLow = txBuf->dmaMem.phyBuf;
+ xre->sg.sg[frag].length = len;
+ frag++;
+
+ continue;
+
+ } else {
+ cmn_err(CE_WARN, "%s%d: Vxn_EncapTxBuf: failed (%d) to bind dma "
+ "handle for len %d. [dmaMemAlloced=%d]",
+ dp->drvName, dp->unit, rval, len, dmaMemAlloced);
+ goto err;
+ }
+ }
+
+ /*
+ * Extract tx buffer physical addresses from cookie
+ */
+ while (nCookies) {
+ if (UNLIKELY(frag == dp->maxTxFrags)) {
+ (void)ddi_dma_unbind_handle(dp->txDmaHdl);
+
+ if (!needPullup) {
+ ASSERT(!dmaMemAlloced);
+ needPullup = TRUE;
+ goto pullup;
+ } else {
+ cmn_err(CE_WARN, "%s%d: Vxn_EncapTxBuf: "
+ "exceeded max (%d) fragments in message",
+ dp->drvName, dp->unit, dp->maxTxFrags);
+ goto err;
+ }
+ }
+
+ /*
+ * Stick it in the ring
+ */
+ xre->sg.sg[frag].addrLow = dmaCookie.dmac_address;
+ xre->sg.sg[frag].length = dmaCookie.dmac_size;
+ frag++;
+
+ if (--nCookies) {
+ ddi_dma_nextcookie(dp->txDmaHdl, &dmaCookie);
+ }
+ }
+
+ (void)ddi_dma_unbind_handle(dp->txDmaHdl);
+ }
+ }
+
+ if (frag > 0) {
+ xre->sg.length = frag;
+
+ /* Give ownership to NIC */
+ xre->sg.addrType = NET_SG_PHYS_ADDR;
+ xre->ownership = VMXNET2_OWNERSHIP_NIC;
+ xre->flags |= VMXNET2_TX_CAN_KEEP;
+ txBuf->mblk = mblk;
+
+ /*
+ * If we called msgpullup to concatenate fragments, free
+ * original mblk now since we're going to return success.
+ */
+ if (mblk != mp) {
+ freemsg(mp);
+ }
+
+ return SOLVMXNET_SUCCESS;
+ }
+
+err:
+ if (mblk != NULL && mblk != mp) {
+ /*
+ * Free mblk allocated by msgpullup.
+ */
+ freemsg(mblk);
+ }
+
+ if (dmaMemAlloced) {
+ ASSERT(txBuf->dmaMem.buf);
+ Vxn_FreeDmaMem(&txBuf->dmaMem);
+ }
+
+ return SOLVMXNET_FAILURE;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_Send --
+ * GLD Transmit routine. Starts packet hard tx.
+ *
+ * Results:
+ * GLD_SUCCESS on success
+ * GLD_FAILURE on failure
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_Send(gld_mac_info_t *macinfo, mblk_t *mp)
+{
+ Vmxnet2_TxRingEntry *xre;
+ int err = GLD_SUCCESS;
+ vxn_softc_t *dp = (vxn_softc_t *)macinfo->gldm_private;
+ Vmxnet2_DriverData *dd = dp->driverData;
+ boolean_t resched = FALSE;
+
+ mutex_enter(&dp->xmitlock);
+
+ /*
+ * Check if ring entry at drop pointer is available
+ */
+ if (TX_RINGBUF_MBLK(dp, dd->txDriverNext) != NULL) {
+ DPRINTF(3, (CE_NOTE, "%s%d: Vxn_Send: tx ring full",
+ dp->drvName, dp->unit));
+ err = GLD_NORESOURCES;
+ dd->txStopped = TRUE;
+ dp->stats.defer++;
+ goto out;
+ }
+
+ xre = &dp->txRing[dd->txDriverNext];
+
+ /*
+ * Drop packet into ring entry
+ */
+ if (Vxn_EncapTxBuf(dp, mp, xre, &dp->txRingBuf[dd->txDriverNext])
+ != SOLVMXNET_SUCCESS) {
+ err = GLD_FAILURE;
+ dp->stats.errxmt++;
+ goto out;
+ }
+
+ /*
+ * Increment drop pointer
+ */
+ VMXNET_INC(dd->txDriverNext, dd->txRingLength);
+ dd->txNumDeferred++;
+ dp->txPending++;
+
+ /*
+ * Transmit, if number of pending packets > tx cluster length
+ */
+ if (dd->txNumDeferred >= dd->txClusterLength) {
+ dd->txNumDeferred = 0;
+
+ /*
+ * Call hardware transmit
+ */
+ INL(dp, VMXNET_TX_ADDR);
+ }
+
+ /*
+ * Clean up transmit ring. TX completion interrupts are not guaranteed
+ */
+ (void) Vxn_TxComplete(dp, &resched);
+
+out:
+ mutex_exit(&dp->xmitlock);
+ if (resched) {
+ /* Tell GLD to retry any deferred packets */
+ gld_sched(dp->macInfo);
+ }
+ return err;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_TxComplete --
+ * Scan Tx ring for completed transmits. Reclaim Tx buffers.
+ *
+ * Results:
+ * Returns TRUE if it found a completed transmit, FALSE otherwise.
+ * Also sets *reschedp to TRUE if the caller should call gld_sched
+ * to reschedule transmits (once all locks are dropped).
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static boolean_t
+Vxn_TxComplete(vxn_softc_t *dp, boolean_t *reschedp)
+{
+ Vmxnet2_DriverData *dd = dp->driverData;
+ boolean_t found = FALSE;
+ boolean_t needresched = FALSE;
+
+ ASSERT(MUTEX_HELD(&dp->xmitlock));
+
+ while (1) {
+ Vmxnet2_TxRingEntry *xre = &dp->txRing[dd->txDriverCur];
+
+ if (xre->ownership != VMXNET2_OWNERSHIP_DRIVER ||
+ (TX_RINGBUF_MBLK(dp, dd->txDriverCur) == NULL)) {
+ break;
+ }
+
+ found = TRUE;
+ Vxn_FreeTxBuf(dp, dd->txDriverCur);
+
+ dp->txPending--;
+ VMXNET_INC(dd->txDriverCur, dd->txRingLength);
+ if (dd->txStopped) {
+ needresched = TRUE;
+ dd->txStopped = FALSE;
+ }
+ }
+
+ *reschedp = needresched;
+ return found;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_Receive --
+ * Rx handler. First assembles the packets into a chain of mblks,
+ * then drops locks and passes them up the stack to GLD.
+ *
+ * Results:
+ * Returns TRUE if it find a packet ready for processing, FALSE
+ * otherwise.
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static boolean_t
+Vxn_Receive(vxn_softc_t *dp)
+{
+ int ringnext;
+ short pktlen;
+ Vmxnet2_DriverData *dd = dp->driverData;
+ rx_dma_buf_t *rxDesc;
+ rx_dma_buf_t *newRxDesc;
+ mblk_t *mblk;
+ mblk_t *head = NULL;
+ mblk_t **tail = &head;
+ mblk_t *next;
+ boolean_t found = FALSE; /* Did we find at least one packet? */
+
+ ASSERT(MUTEX_HELD(&dp->intrlock));
+
+ /*
+ * Walk receive ring looking for entries with ownership
+ * reverted back to driver
+ */
+ while (1) {
+ Vmxnet2_RxRingEntry *rre;
+ rx_dma_buf_t **rbuf;
+
+ ringnext = dd->rxDriverNext;
+ rre = &dp->rxRing[ringnext];
+ rbuf = &dp->rxRingBuffPtr[ringnext];
+
+ if (rre->ownership != VMXNET2_OWNERSHIP_DRIVER) {
+ break;
+ }
+
+ found = TRUE;
+
+ pktlen = rre->actualLength;
+
+ if (pktlen < (60 - 4)) {
+ /*
+ * Ethernet header vlan tags are 4 bytes. Some vendors generate
+ * 60byte frames including vlan tags. When vlan tag
+ * is stripped, such frames become 60 - 4. (PR106153)
+ */
+ dp->stats.errrcv++;
+ if (pktlen != 0) {
+ DPRINTF(3, (CE_CONT, "%s%d: runt packet\n", dp->drvName, dp->unit));
+ dp->stats.runt++;
+ }
+ } else {
+ /*
+ * Alloc new Rx buffer to replace current one
+ */
+ newRxDesc = Vxn_AllocRxBufFromPool(dp);
+
+ if (newRxDesc) {
+ rxDesc = *rbuf;
+ mblk = rxDesc->mblk;
+
+ *rbuf = newRxDesc;
+ rre->paddr = newRxDesc->dmaDesc.phyBuf + ETHERALIGN;
+ rre->bufferLength = MAXPKTBUF - ETHERALIGN;
+ rre->actualLength = 0;
+
+ /*
+ * Advance write pointer past packet length
+ */
+ mblk->b_wptr = mblk->b_rptr + pktlen;
+
+ /*
+ * Add to end of chain.
+ */
+ mblk->b_next = NULL;
+ *tail = mblk;
+ tail = &mblk->b_next;
+ } else {
+ dp->stats.errrcv++;
+ dp->stats.norcvbuf++;
+ }
+ }
+
+ /* Give the descriptor back to NIC */
+ rre->ownership = VMXNET2_OWNERSHIP_NIC;
+ VMXNET_INC(dd->rxDriverNext, dd->rxRingLength);
+ }
+
+ /*
+ * Walk chain and pass mblks up to gld_recv one by one.
+ */
+ mutex_exit(&dp->intrlock);
+ for (mblk = head; mblk != NULL; mblk = next) {
+ next = mblk->b_next;
+ mblk->b_next = NULL;
+ gld_recv(dp->macInfo, mblk);
+ }
+ mutex_enter(&dp->intrlock);
+
+ return (found);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_Interrupt --
+ * GLD interrupt handler. Scan: Rx ring for received packets, Tx ring for
+ * completed transmits
+ *
+ * Results:
+ * - DDI_INTR_CLAIMED (if we found something to do)
+ * - DDI_INTR_UNCLAIMED (if not)
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static u_int
+Vxn_Interrupt(gld_mac_info_t *macInfo)
+{
+ u_int ret = DDI_INTR_UNCLAIMED;
+ vxn_softc_t *dp = (vxn_softc_t *)macInfo->gldm_private;
+ boolean_t foundRx, foundTx;
+ boolean_t resched = FALSE;
+
+ mutex_enter(&dp->intrlock);
+ dp->inIntr = TRUE;
+
+ if (!dp->nicActive) {
+ goto out;
+ }
+
+ /*
+ * Ack interrupt
+ */
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_INTR_ACK);
+
+ foundRx = Vxn_Receive(dp);
+
+ mutex_enter(&dp->xmitlock);
+ foundTx = Vxn_TxComplete(dp, &resched);
+ mutex_exit(&dp->xmitlock);
+
+ if (foundRx || foundTx) {
+ ret = DDI_INTR_CLAIMED;
+ dp->stats.interrupts++;
+ }
+
+out:
+ dp->inIntr = FALSE;
+ mutex_exit(&dp->intrlock);
+
+ if (resched) {
+ gld_sched(dp->macInfo);
+ }
+
+ return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_ReclaimRxBuf --
+ * Callback handler invoked by freemsg(). Frees Rx buffer memory and mappings
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static void
+Vxn_ReclaimRxBuf(rx_dma_buf_t *rxDesc)
+{
+ Vxn_FreeRxBufToPool(rxDesc);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_FreeRxBuf --
+ * Free allocated Rx buffer
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static void
+Vxn_FreeRxBuf(rx_dma_buf_t *rxDesc)
+{
+ ASSERT(rxDesc);
+
+ if (rxDesc->mblk) {
+ freemsg(rxDesc->mblk);
+ } else {
+ Vxn_FreeDmaMem(&rxDesc->dmaDesc);
+ kmem_free(rxDesc, sizeof(rx_dma_buf_t));
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_AllocRxBuf --
+ * Allocate Rx buffer
+ *
+ * Results:
+ * Pointer to Rx buffer descriptor - on success
+ * NULL - on failure
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static rx_dma_buf_t *
+Vxn_AllocRxBuf(vxn_softc_t *dp, int cansleep)
+{
+ rx_dma_buf_t *rxDesc;
+
+ rxDesc = (rx_dma_buf_t *)kmem_zalloc(sizeof(rx_dma_buf_t),
+ cansleep ? KM_SLEEP : KM_NOSLEEP);
+ if (!rxDesc) {
+ cmn_err(CE_WARN, "%s%d: Vxn_AllocRxBuf: kmem_zalloc failed",
+ dp->drvName, dp->unit);
+ return NULL;
+ }
+
+ rxDesc->softc = dp;
+
+ /*
+ * Alloc dma-able packet memory
+ */
+ if (Vxn_AllocDmaMem(dp, MAXPKTBUF, cansleep, &rxDesc->dmaDesc)
+ != SOLVMXNET_SUCCESS) {
+ kmem_free(rxDesc, sizeof(rx_dma_buf_t));
+ return NULL;
+ }
+
+ /*
+ * Fill in free callback; fired by freemsg()
+ */
+ rxDesc->freeCB.free_func = &Vxn_ReclaimRxBuf;
+ rxDesc->freeCB.free_arg = (caddr_t) rxDesc;
+
+ rxDesc->mblk = NULL;
+ return rxDesc;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_FreeInitBuffers --
+ * Free allocated Tx and Rx buffers
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static void
+Vxn_FreeInitBuffers(vxn_softc_t *dp)
+{
+ int i;
+
+ for (i=0; i<dp->vxnNumRxBufs; i++) {
+ if (dp->rxRingBuffPtr[i]) {
+ Vxn_FreeRxBuf(dp->rxRingBuffPtr[i]);
+ dp->rxRingBuffPtr[i] = NULL;
+ }
+ }
+
+ for (i=0; i<dp->vxnNumTxBufs; i++) {
+ if (TX_RINGBUF_MBLK(dp, i)) {
+ Vxn_FreeTxBuf(dp, i);
+ }
+ }
+
+ /*
+ * Rx pool must get freed last. Rx buffers above will
+ * show up on the pool when freemsg callback fires.
+ */
+ Vxn_FreeRxBufPool(dp);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_AllocRxBufPool --
+ * Allocate pool of rx buffers - 3 * configured Rx buffers
+ *
+ * Results:
+ * SOLVMXNET_SUCCESS/SOLVMXNET_FAILURE
+ *
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_AllocRxBufPool(vxn_softc_t *dp)
+{
+ int i;
+
+ dp->rxFreeBufList = NULL;
+
+ // Allow list to double in size if needed. Any additional buffers
+ // that are allocated on the fly will be freed back to main memory.
+ dp->rxMaxFreeBufs = dp->vxnNumRxBufs * 6;
+
+ for (i = 0; i < dp->vxnNumRxBufs * 3; i++) {
+ rx_dma_buf_t *rxDesc;
+
+ /*
+ * Alloc rx buffer
+ */
+ if (!(rxDesc = Vxn_AllocRxBuf(dp, TRUE))) {
+ cmn_err(CE_WARN, "%s%d: Vxn_AllocRxBufPool: failed to allocate memory",
+ dp->drvName, dp->unit);
+ dp->rxNumFreeBufs = i;
+ return SOLVMXNET_FAILURE;
+ }
+ /*
+ * Add to free list
+ */
+ rxDesc->next = dp->rxFreeBufList;
+ dp->rxFreeBufList = rxDesc;
+ }
+
+ dp->rxNumFreeBufs = i;
+ return SOLVMXNET_SUCCESS;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_FreeRxBufPool --
+ * Free rx buffers pool
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static void
+Vxn_FreeRxBufPool(vxn_softc_t *dp)
+{
+ while (dp->rxFreeBufList) {
+ rx_dma_buf_t *rxDesc = dp->rxFreeBufList;
+
+ /* unlink */
+ dp->rxFreeBufList = rxDesc->next;
+
+ ASSERT(rxDesc->mblk == NULL);
+ Vxn_FreeDmaMem(&rxDesc->dmaDesc);
+ kmem_free(rxDesc, sizeof(rx_dma_buf_t));
+ }
+ dp->rxNumFreeBufs = 0;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_AllocRxBufFromPool --
+ * Allocate Rx buffer from free pool
+ *
+ * Results:
+ * Pointer to Rx buffer descriptor - on success
+ * NULL - on failure
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static rx_dma_buf_t *
+Vxn_AllocRxBufFromPool(vxn_softc_t *dp)
+{
+ rx_dma_buf_t *rxDesc = NULL;
+
+ mutex_enter(&dp->rxlistlock);
+ if (dp->rxFreeBufList) {
+ rxDesc = dp->rxFreeBufList;
+ dp->rxFreeBufList = rxDesc->next;
+ ASSERT(dp->rxNumFreeBufs >= 1);
+ dp->rxNumFreeBufs--;
+ }
+ mutex_exit(&dp->rxlistlock);
+
+ if (!rxDesc) {
+ /*
+ * Try to allocate new descriptor from memory. Can't block here
+ * since we could be being called from interrupt context.
+ */
+ DPRINTF(5, (CE_NOTE, "%s%d: allocating rx buf from memory",
+ dp->drvName, dp->unit));
+ if (!(rxDesc = Vxn_AllocRxBuf(dp, FALSE))) {
+ cmn_err(CE_WARN,
+ "%s%d: Vxn_AllocRxBufFromPool : pool rx alloc failed",
+ dp->drvName, dp->unit);
+ return NULL;
+ }
+ }
+
+ /*
+ * Allocate new message block for this buffer
+ */
+ rxDesc->mblk = desballoc((uchar_t *)rxDesc->dmaDesc.buf + ETHERALIGN,
+ rxDesc->dmaDesc.bufLen - ETHERALIGN,
+ BPRI_MED, &rxDesc->freeCB);
+ if (!rxDesc->mblk) {
+ cmn_err(CE_WARN, "%s%d: Vxn_AllocRxBufFromPool : desballoc failed",
+ dp->drvName, dp->unit);
+
+ /* put back on free list */
+ Vxn_FreeRxBufToPool(rxDesc);
+ return NULL;
+ }
+
+ return rxDesc;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_FreeRxBufToPool --
+ * Return rx buffer to free pool
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static void
+Vxn_FreeRxBufToPool(rx_dma_buf_t *rxDesc)
+{
+ vxn_softc_t *dp = rxDesc->softc;
+
+ rxDesc->mblk = NULL;
+
+ /*
+ * Insert on free list, or free if the list is full
+ */
+ mutex_enter(&dp->rxlistlock);
+ if (dp->rxNumFreeBufs >= dp->rxMaxFreeBufs) {
+ DPRINTF(5, (CE_NOTE, "%s%d: freeing rx buf to memory",
+ dp->drvName, dp->unit));
+ Vxn_FreeRxBuf(rxDesc);
+ } else {
+ rxDesc->next = dp->rxFreeBufList;
+ dp->rxFreeBufList = rxDesc;
+ dp->rxNumFreeBufs++;
+ }
+ mutex_exit(&dp->rxlistlock);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_AllocInitBuffers --
+ * Allocated Rx buffers and init ring entries
+ *
+ * Results:
+ * SOLVMXNET_SUCCESS - on success
+ * SOLVMXNET_FAILURE - on failure
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_AllocInitBuffers(vxn_softc_t *dp)
+{
+ Vmxnet2_DriverData *dd;
+ uint32_t i, offset;
+
+ dd = dp->driverData;
+ offset = sizeof(*dd);
+
+ /*
+ * Init shared structures
+ */
+ dd->rxRingLength = dp->vxnNumRxBufs;
+ dd->rxRingOffset = offset;
+ dp->rxRing = (Vmxnet2_RxRingEntry *)((uintptr_t)dd + offset);
+ offset += dp->vxnNumRxBufs * sizeof(Vmxnet2_RxRingEntry);
+
+ dd->rxRingLength2 = 1;
+ dd->rxRingOffset2 = offset;
+ offset += sizeof(Vmxnet2_RxRingEntry);
+
+ dd->txRingLength = dp->vxnNumTxBufs;
+ dd->txRingOffset = offset;
+ dp->txRing = (Vmxnet2_TxRingEntry *)((uintptr_t)dd + offset);
+ offset += dp->vxnNumTxBufs * sizeof(Vmxnet2_TxRingEntry);
+
+ /*
+ * Alloc Rx buffers pool
+ */
+ if ( Vxn_AllocRxBufPool(dp) != SOLVMXNET_SUCCESS) {
+ cmn_err(CE_WARN, "%s%d: Vxn_AllocInitBuffers: failed to alloc buf pool",
+ dp->drvName, dp->unit);
+ return SOLVMXNET_FAILURE;
+ }
+
+ /*
+ * Allocate receive buffers
+ */
+ for (i = 0; i < dp->vxnNumRxBufs; i++) {
+ rx_dma_buf_t *rxDesc;
+ Vmxnet2_RxRingEntry *rre = &dp->rxRing[i];
+
+ if (!(rxDesc = Vxn_AllocRxBufFromPool(dp))) {
+ cmn_err(CE_WARN, "%s%d: Vxn_AllocInitBuffers: "
+ "failed to alloc buf from pool", dp->drvName, dp->unit);
+ goto err;
+ }
+
+ /*
+ * Init ring entries
+ */
+ rre->paddr = rxDesc->dmaDesc.phyBuf + ETHERALIGN;
+ rre->bufferLength = MAXPKTBUF - ETHERALIGN;
+ rre->actualLength = 0;
+ dp->rxRingBuffPtr[i] = rxDesc;
+ rre->ownership = VMXNET2_OWNERSHIP_NIC;
+ }
+
+ dp->txDmaHdl = NULL;
+
+ /*
+ * Dummy recvRing2 tacked on to the end, with a single unusable entry
+ */
+ dp->rxRing[i].paddr = 0;
+ dp->rxRing[i].bufferLength = 0;
+ dp->rxRing[i].actualLength = 0;
+ dp->rxRingBuffPtr[i] = NULL;
+ dp->rxRing[i].ownership = VMXNET2_OWNERSHIP_DRIVER;
+
+ dd->rxDriverNext = 0;
+
+ /*
+ * Give xmit ring ownership to DRIVER
+ */
+ for (i = 0; i < dp->vxnNumTxBufs; i++) {
+ dp->txRing[i].ownership = VMXNET2_OWNERSHIP_DRIVER;
+ dp->txRingBuf[i].mblk = NULL;
+ dp->txRingBuf[i].dmaMem.buf = NULL;
+ dp->txRing[i].sg.sg[0].addrHi = 0;
+ }
+
+ dd->txDriverCur = dd->txDriverNext = 0;
+ dd->txStopped = FALSE;
+
+ return SOLVMXNET_SUCCESS;
+
+err:
+ for (i=0; i<dp->vxnNumRxBufs; i++) {
+ if (dp->rxRingBuffPtr[i]) {
+ Vxn_FreeRxBuf(dp->rxRingBuffPtr[i]);
+ dp->rxRingBuffPtr[i] = NULL;
+ }
+ }
+
+ Vxn_FreeRxBufPool(dp);
+ return SOLVMXNET_FAILURE;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_FreeDmaMem --
+ * Free allocated dma memory
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static void
+Vxn_FreeDmaMem(dma_buf_t *dma)
+{
+ ddi_dma_unbind_handle(dma->dmaHdl);
+ ddi_dma_mem_free(&dma->dataAccHdl);
+ ddi_dma_free_handle(&dma->dmaHdl);
+
+ dma->buf = NULL;
+ dma->phyBuf = NULL;
+ dma->bufLen = 0;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_AllocDmaMem --
+ * Allocate dma-able memory and fill passed in dma descriptor pointer
+ * if successful
+ *
+ * Results:
+ * SOLVMXNET_SUCCESS on success
+ * SOLVMXNET_FAILURE on failure
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_AllocDmaMem(vxn_softc_t *dp, int size, int cansleep, dma_buf_t *dma)
+{
+ /*
+ * Allocate handle
+ */
+ if (ddi_dma_alloc_handle(dp->dip, &vxn_dma_attrs,
+ cansleep ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT,
+ NULL, &dma->dmaHdl) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "%s%d: Vxn_AllocDmaMem: failed to allocate handle",
+ dp->drvName, dp->unit);
+ return SOLVMXNET_FAILURE;
+ }
+
+ /*
+ * Allocate memory
+ */
+ if (ddi_dma_mem_alloc(dma->dmaHdl, size, &vxn_buf_attrs, DDI_DMA_CONSISTENT,
+ cansleep ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT, NULL,
+ &dma->buf, &dma->bufLen, &dma->dataAccHdl)
+ != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "%s%d: Vxn_AllocDmaMem: "
+ "ddi_dma_mem_alloc %d bytes failed",
+ dp->drvName, dp->unit, size);
+ ddi_dma_free_handle(&dma->dmaHdl);
+ return SOLVMXNET_FAILURE;
+ }
+
+ /*
+ * Mapin memory
+ */
+ if (ddi_dma_addr_bind_handle(dma->dmaHdl, NULL, dma->buf, dma->bufLen,
+ DDI_DMA_RDWR | DDI_DMA_STREAMING,
+ cansleep ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT,
+ NULL, &dma->cookie, &dma->cookieCount)
+ != DDI_DMA_MAPPED) {
+ cmn_err(CE_WARN, "%s%d: Vxn_AllocDmaMem: failed to bind handle",
+ dp->drvName, dp->unit);
+ ddi_dma_mem_free(&dma->dataAccHdl);
+ ddi_dma_free_handle(&dma->dmaHdl);
+ return SOLVMXNET_FAILURE;
+ }
+
+ if (dma->cookieCount != 1) {
+ cmn_err(CE_WARN, "%s%d: Vxn_AllocDmaMem: too many DMA cookies",
+ dp->drvName, dp->unit);
+ Vxn_FreeDmaMem(dma);
+ return SOLVMXNET_FAILURE;
+ }
+
+ /*
+ * Save physical address (for easy use)
+ */
+ dma->phyBuf = dma->cookie.dmac_address;
+
+ return SOLVMXNET_SUCCESS;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_FreeDriverData --
+ * Free driver data structures and Tx Rx buffers
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static void
+Vxn_FreeDriverData(vxn_softc_t *dp)
+{
+ Vxn_FreeInitBuffers(dp);
+ Vxn_FreeDmaMem(&dp->driverDataDmaMem);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_AllocDriverData --
+ * Allocate driver data structures and Tx Rx buffers on init
+ *
+ * Results:
+ * SOLVMXNET_SUCCESS on success
+ * SOLVMXNET_FAILURE on failure
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_AllocDriverData(vxn_softc_t *dp)
+{
+ uint32_t r, driverDataSize;
+
+ /*
+ * Get configured receive buffers
+ */
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_GET_NUM_RX_BUFFERS);
+ r = INL(dp, VMXNET_COMMAND_ADDR);
+ if (r == 0 || r > MAX_NUM_RECV_BUFFERS) {
+ r = DEFAULT_NUM_RECV_BUFFERS;
+ }
+ dp->vxnNumRxBufs = r;
+
+ /*
+ * Get configured transmit buffers
+ */
+ OUTL(dp, VMXNET_COMMAND_ADDR, VMXNET_CMD_GET_NUM_TX_BUFFERS);
+ r = INL(dp, VMXNET_COMMAND_ADDR);
+ if (r == 0 || r > MAX_NUM_XMIT_BUFFERS) {
+ r = DEFAULT_NUM_XMIT_BUFFERS;
+ }
+ dp->vxnNumTxBufs = r;
+
+ /*
+ * Calculate shared data size and allocate memory for it
+ */
+ driverDataSize =
+ sizeof(Vmxnet2_DriverData) +
+ /* numRecvBuffers + 1 for the dummy recvRing2 (used only by Windows) */
+ (dp->vxnNumRxBufs + 1) * sizeof(Vmxnet2_RxRingEntry) +
+ dp->vxnNumTxBufs * sizeof(Vmxnet2_TxRingEntry);
+
+ if (Vxn_AllocDmaMem(dp, driverDataSize, TRUE, &dp->driverDataDmaMem)
+ != SOLVMXNET_SUCCESS) {
+ return SOLVMXNET_FAILURE;
+ }
+
+ /*
+ * Clear memory (bzero isn't resolved by module loader for some reason)
+ */
+ ASSERT(dp->driverDataDmaMem.buf && dp->driverDataDmaMem.bufLen);
+ Vxn_Memset(dp->driverDataDmaMem.buf, 0, dp->driverDataDmaMem.bufLen);
+
+ dp->driverData = (Vmxnet2_DriverData *)dp->driverDataDmaMem.buf;
+ dp->driverDataPhy = (void *)(uintptr_t)dp->driverDataDmaMem.phyBuf;
+
+ /* So that the vmkernel can check it is compatible */
+ dp->driverData->magic = VMXNET2_MAGIC;
+ dp->driverData->length = driverDataSize;
+
+ /*
+ * Alloc rx/tx buffers, init ring, register with hardware etc.
+ */
+ if (Vxn_AllocInitBuffers(dp) != SOLVMXNET_SUCCESS) {
+ Vxn_FreeDmaMem(&dp->driverDataDmaMem);
+ return SOLVMXNET_FAILURE;
+ }
+
+ DPRINTF(3, (CE_CONT, "%s%d: numRxBufs=(%d*%"FMT64"d) numTxBufs=(%d*%"FMT64"d)"
+ " driverDataSize=%d driverDataPhy=0x%p\n",
+ dp->drvName, dp->unit,
+ dp->vxnNumRxBufs, (uint64_t)sizeof(Vmxnet2_RxRingEntry),
+ dp->vxnNumTxBufs, (uint64_t)sizeof(Vmxnet2_TxRingEntry),
+ driverDataSize, dp->driverDataPhy));
+
+ return SOLVMXNET_SUCCESS;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_Attach --
+ * Probe and attach driver to stack
+ *
+ * Results:
+ * DDI_SUCCESS
+ * DDI_FAILURE
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_Attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ int i, ret, len, unit;
+ const char *drvName;
+ ddi_acc_handle_t confHdl;
+ uint16_t vid, did;
+ uint8_t revid;
+ struct pci_phys_spec *regs;
+ caddr_t vxnIOp;
+ ddi_acc_handle_t vxnIOHdl;
+ uint32_t vLow, vHigh;
+ gld_mac_info_t *macInfo;
+ vxn_softc_t *dp;
+ boolean_t morphed = FALSE;
+ uint_t regSpaceSize;
+ uint_t chip;
+ uint_t vxnIOSize;
+
+ if (cmd != DDI_ATTACH) {
+ return DDI_FAILURE;
+ }
+
+ unit = ddi_get_instance(dip);
+ drvName = ddi_driver_name(dip);
+
+ /*
+ * Check if chip is supported.
+ */
+ if (pci_config_setup(dip, &confHdl) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "%s%d: pci_config_setup() failed", drvName, unit);
+ return DDI_FAILURE;
+ }
+
+ vid = pci_config_get16(confHdl, PCI_CONF_VENID);
+ did = pci_config_get16(confHdl, PCI_CONF_DEVID);
+ revid = pci_config_get8(confHdl, PCI_CONF_REVID);
+
+ if (vid == PCI_VENDOR_ID_VMWARE && did == PCI_DEVICE_ID_VMWARE_NET) {
+ /* Found vmxnet */
+ chip = VMXNET_CHIP;
+ }
+ else if (vid == PCI_VENDOR_ID_AMD && did == PCI_DEVICE_ID_AMD_VLANCE) {
+ /* Found vlance (maybe a vmxnet disguise) */
+ chip = LANCE_CHIP;
+ }
+ else {
+ /* Not Found */
+ DPRINTF(3, (CE_WARN, "%s: Vxn_Attach: wrong PCI venid/devid (0x%x, 0x%x)",
+ drvName, vid, did));
+ goto err;
+ }
+
+ DPRINTF(3, (CE_CONT, "%s%d: (vid: 0x%04x, did: 0x%04x, revid: 0x%02x)\n",
+ drvName, unit, vid, did, revid));
+
+ /*
+ * Get device properties
+ */
+ regs = NULL;
+ len = 0;
+ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+ "reg", (caddr_t)®s, &len) != DDI_PROP_SUCCESS) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Attach: failed to get reg property",
+ drvName, unit);
+ goto err;
+ }
+
+ ASSERT(regs != NULL && len > 0);
+
+ /*
+ * Search device properties for IO-space
+ */
+ for (i = 0; i <len / sizeof(struct pci_phys_spec); i++) {
+ if ((regs[i].pci_phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_IO) {
+ regSpaceSize = regs[i].pci_size_low;
+ DPRINTF(5, (CE_CONT, "%s%d: Vxn_Attach: regSpaceSize=%d\n",
+ drvName, unit, regSpaceSize));
+ kmem_free(regs, len);
+ goto map_space_found;
+ }
+ }
+
+ cmn_err(CE_WARN, "%s%d: Vxn_Attach: failed to find IO space", drvName, unit);
+ kmem_free(regs, len);
+ goto err;
+
+map_space_found:
+
+ /*
+ * Ensure we can access registers through IO space.
+ */
+ ret = pci_config_get16(confHdl, PCI_CONF_COMM);
+ ret |= PCI_COMM_IO | PCI_COMM_ME;
+ pci_config_put16(confHdl, PCI_CONF_COMM, ret);
+
+ if (ddi_regs_map_setup(dip, i, (caddr_t *)&vxnIOp, 0, 0, &dev_attr,
+ &vxnIOHdl) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Attach: ddi_regs_map_setup failed",
+ drvName, unit);
+ goto err;
+ }
+
+ if (chip == VMXNET_CHIP) {
+ vxnIOSize = VMXNET_CHIP_IO_RESV_SIZE;
+ }
+ else {
+ /*
+ * Since this is a vlance adapter we can only use it if
+ * its I/0 space is big enough for the adapter to be
+ * capable of morphing. This is the first requirement
+ * for this adapter to potentially be morphable. The
+ * layout of a morphable LANCE adapter is
+ *
+ * I/O space:
+ *
+ * |------------------|
+ * | LANCE IO PORTS |
+ * |------------------|
+ * | MORPH PORT |
+ * |------------------|
+ * | VMXNET IO PORTS |
+ * |------------------|
+ *
+ * VLance has 8 ports of size 4 bytes, the morph port is 4 bytes, and
+ * Vmxnet has 10 ports of size 4 bytes.
+ *
+ * We shift up the ioaddr with the size of the LANCE I/O space since
+ * we want to access the vmxnet ports. We also shift the ioaddr up by
+ * the MORPH_PORT_SIZE so other port access can be independent of
+ * whether we are Vmxnet or a morphed VLance. This means that when
+ * we want to access the MORPH port we need to subtract the size
+ * from ioaddr to get to it.
+ */
+ vxnIOp += LANCE_CHIP_IO_RESV_SIZE + MORPH_PORT_SIZE;
+ vxnIOSize = LANCE_CHIP_IO_RESV_SIZE + MORPH_PORT_SIZE +
+ VMXNET_CHIP_IO_RESV_SIZE;
+ }
+
+ /*
+ * Do not attempt to morph non-morphable AMD PCnet
+ */
+ if (vxnIOSize > regSpaceSize) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Attach: "
+ "vlance device is not supported by this driver", drvName, unit);
+ goto err_free_regs_map;
+ }
+
+ /*
+ * Morph, if we found a vlance adapter
+ */
+ if (chip == LANCE_CHIP) {
+ uint16_t magic;
+
+ /* Read morph port to verify that we can morph the adapter */
+ magic = ddi_get16(vxnIOHdl, (uint16_t *)(vxnIOp - MORPH_PORT_SIZE));
+ if (magic != LANCE_CHIP && magic != VMXNET_CHIP) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Attach: Invalid magic, read: 0x%08X",
+ drvName, unit, magic);
+ goto err_free_regs_map;
+ }
+
+ /* Morph */
+ ddi_put16(vxnIOHdl, (uint16_t *)(vxnIOp - MORPH_PORT_SIZE), VMXNET_CHIP);
+ morphed = TRUE;
+
+ /* Verify that we morphed correctly */
+ magic = ddi_get16(vxnIOHdl, (uint16_t *)(vxnIOp - MORPH_PORT_SIZE));
+ if (magic != VMXNET_CHIP) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Attach: Couldn't morph adapter."
+ " Invalid magic, read:: 0x%08X", drvName, unit, magic);
+ goto err_morph_back;
+ }
+ }
+
+ /*
+ * Check the version number of the device implementation
+ */
+ vLow = (uint32_t)ddi_get32(vxnIOHdl,
+ (uint32_t *)(vxnIOp+VMXNET_LOW_VERSION));
+ vHigh = (uint32_t)ddi_get32(vxnIOHdl,
+ (uint32_t *)(vxnIOp+VMXNET_HIGH_VERSION));
+
+ if ((vLow & 0xffff0000) != (VMXNET2_MAGIC & 0xffff0000) ||
+ ((VMXNET2_MAGIC < vLow) || (VMXNET2_MAGIC > vHigh))) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Attach: driver version 0x%08X doesn't "
+ "match device 0x%08X:0x%08X",
+ drvName, unit, VMXNET2_MAGIC, vLow, vHigh);
+ goto err_version_mismatch;
+ }
+
+ /*
+ * Alloc soft state
+ */
+ macInfo = gld_mac_alloc(dip);
+ if (!macInfo) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Attach: gld_mac_alloc failed",
+ drvName, unit);
+ goto err_gld_mac_alloc;
+ }
+
+ dp = (vxn_softc_t *) kmem_zalloc(sizeof(vxn_softc_t), KM_SLEEP);
+ ASSERT(dp);
+
+ /*
+ * Get interrupt cookie
+ */
+ if (ddi_get_iblock_cookie(dip, 0, &dp->iblockCookie) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Attach: ddi_get_iblock_cookie failed",
+ drvName, unit);
+ goto err_get_iblock_cookie;
+ }
+
+ strncpy(dp->drvName, drvName, SOLVMXNET_MAXNAME);
+ dp->unit = unit;
+ dp->dip = dip;
+ dp->macInfo = macInfo;
+ dp->confHdl = confHdl;
+ dp->vxnIOHdl = vxnIOHdl;
+ dp->vxnIOp = vxnIOp;
+ dp->morphed = morphed;
+ dp->nicActive = FALSE;
+ dp->txPending = 0;
+ dp->maxTxFrags = 1;
+
+ /*
+ * Initialize mutexes
+ */
+ mutex_init(&dp->intrlock, NULL, MUTEX_DRIVER, (void *)dp->iblockCookie);
+ mutex_init(&dp->xmitlock, NULL, MUTEX_DRIVER, (void *)dp->iblockCookie);
+ mutex_init(&dp->rxlistlock, NULL, MUTEX_DRIVER, (void *)dp->iblockCookie);
+
+ /*
+ * Allocate and initialize our private and shared data structures
+ */
+ if (Vxn_AllocDriverData(dp) != SOLVMXNET_SUCCESS) {
+ goto err_alloc_driverdata;
+ }
+
+ /*
+ * Read the MAC address from the device
+ */
+ for (i = 0; i < 6; i++) {
+ dp->devAddr.ether_addr_octet[i] =
+ (uint8_t)ddi_get8(vxnIOHdl, (uint8_t *)(vxnIOp + VMXNET_MAC_ADDR + i));
+ }
+ macInfo->gldm_vendor_addr = dp->devAddr.ether_addr_octet;
+ macInfo->gldm_broadcast_addr = etherbroadcastaddr.ether_addr_octet;
+
+ DPRINTF(3, (CE_CONT,
+ "MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dp->devAddr.ether_addr_octet[0],
+ dp->devAddr.ether_addr_octet[1],
+ dp->devAddr.ether_addr_octet[2],
+ dp->devAddr.ether_addr_octet[3],
+ dp->devAddr.ether_addr_octet[4],
+ dp->devAddr.ether_addr_octet[5]));
+
+ /*
+ * Configure GLD entry points
+ */
+ macInfo->gldm_devinfo = dip;
+ macInfo->gldm_private = (caddr_t)dp;
+ macInfo->gldm_cookie = dp->iblockCookie;
+ macInfo->gldm_reset = Vxn_Reset;
+ macInfo->gldm_start = Vxn_Start;
+ macInfo->gldm_stop = Vxn_Stop;
+ macInfo->gldm_set_mac_addr = Vxn_SetMacAddress;
+ macInfo->gldm_send = Vxn_Send;
+ macInfo->gldm_set_promiscuous = Vxn_SetPromiscuous;
+ macInfo->gldm_get_stats = Vxn_GetStats;
+ macInfo->gldm_ioctl = NULL;
+ macInfo->gldm_set_multicast= Vxn_SetMulticast;
+ macInfo->gldm_intr = Vxn_Interrupt;
+ macInfo->gldm_mctl = NULL;
+
+ macInfo->gldm_ident = (char *)ddi_driver_name(dip);
+ macInfo->gldm_type = DL_ETHER;
+ macInfo->gldm_minpkt = 0;
+ macInfo->gldm_maxpkt = ETHERMTU;
+ macInfo->gldm_addrlen = ETHERADDRL;
+ macInfo->gldm_saplen = -2;
+ macInfo->gldm_ppa = unit;
+
+ /*
+ * Register with GLD (Generic Lan Driver) framework
+ */
+ if (gld_register(dip,
+ (char *)ddi_driver_name(dip), macInfo) != DDI_SUCCESS) {
+ goto err_gld_register;
+ }
+
+ /*
+ * Add interrupt to system.
+ */
+ if (ddi_add_intr(dip, 0, NULL, NULL, gld_intr,
+ (caddr_t)macInfo) != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "%s%d: ddi_add_intr failed", drvName, unit);
+ goto err_ddi_add_intr;
+ }
+
+ /*
+ * Add to list of interfaces.
+ */
+ mutex_enter(&vxnListLock);
+ dp->next = &vxnList;
+ dp->prev = vxnList.prev;
+ vxnList.prev->next = dp;
+ vxnList.prev = dp;
+ mutex_exit(&vxnListLock);
+
+ /*
+ * Success
+ */
+ return DDI_SUCCESS;
+
+err_ddi_add_intr:
+ gld_unregister(macInfo);
+
+err_gld_register:
+ Vxn_FreeDriverData(dp);
+
+err_alloc_driverdata:
+ mutex_destroy(&dp->intrlock);
+ mutex_destroy(&dp->xmitlock);
+
+err_get_iblock_cookie:
+ kmem_free(dp, sizeof(*dp));
+ gld_mac_free(macInfo);
+
+err_gld_mac_alloc:
+err_version_mismatch:
+err_morph_back:
+ if (morphed) {
+ ddi_put16(vxnIOHdl, (uint16_t *)(vxnIOp - MORPH_PORT_SIZE), LANCE_CHIP);
+ }
+
+err_free_regs_map:
+ ddi_regs_map_free(&vxnIOHdl);
+
+err:
+ pci_config_teardown(&confHdl);
+ return DDI_FAILURE;
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Vxn_Detach --
+ * Called on module unload
+ *
+ * Results:
+ * DDI_SUCCESS
+ * DDI_FAILURE
+ *
+ * Side effects:
+ * None
+ *-----------------------------------------------------------------------------
+ */
+static int
+Vxn_Detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ gld_mac_info_t *macInfo;
+ vxn_softc_t *dp;
+
+ macInfo = (gld_mac_info_t *)ddi_get_driver_private(dip);
+ dp = (vxn_softc_t *)macInfo->gldm_private;
+
+ if (cmd == DDI_DETACH) {
+ /*
+ * Tear down interrupt
+ */
+ ddi_remove_intr(dip, 0, macInfo->gldm_cookie);
+ gld_unregister(macInfo);
+
+ /*
+ * Quiesce hardware
+ */
+ Vxn_Stop(macInfo);
+
+ /*
+ * Free driver-data, tx/rx buffers etc
+ */
+ Vxn_FreeDriverData(dp);
+
+ /*
+ * Destroy locks
+ */
+ mutex_destroy(&dp->intrlock);
+ mutex_destroy(&dp->xmitlock);
+
+ /*
+ * Unmorph
+ */
+ if (dp->morphed) {
+ uint16_t magic;
+
+ /* Verify that we had morphed earlier */
+ magic = ddi_get16(dp->vxnIOHdl,
+ (uint16_t *)(dp->vxnIOp - MORPH_PORT_SIZE));
+ if (magic != VMXNET_CHIP) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Detach: Adapter not morphed"
+ " magic=0x%08X", dp->drvName, dp->unit, magic);
+ }
+ else {
+ /* Unmorph */
+ ddi_put16(dp->vxnIOHdl,
+ (uint16_t *)(dp->vxnIOp - MORPH_PORT_SIZE), LANCE_CHIP);
+
+ /* Verify */
+ magic = ddi_get16(dp->vxnIOHdl,
+ (uint16_t *)(dp->vxnIOp - MORPH_PORT_SIZE));
+ if (magic != LANCE_CHIP) {
+ cmn_err(CE_WARN, "%s%d: Vxn_Detach: Unable to unmorph adapter"
+ " magic=0x%08X", dp->drvName, dp->unit, magic);
+ }
+ }
+ }
+
+ /*
+ * Release resister mappings
+ */
+ ddi_regs_map_free(&dp->vxnIOHdl);
+ pci_config_teardown(&dp->confHdl);
+
+ /*
+ * Remove from list of interfaces.
+ */
+ mutex_enter(&vxnListLock);
+ ASSERT(dp != &vxnList);
+ dp->prev->next = dp->next;
+ dp->next->prev = dp->prev;
+ mutex_exit(&vxnListLock);
+
+ /*
+ * Release memory
+ */
+ kmem_free(dp, sizeof(*dp));
+ gld_mac_free(macInfo);
+
+ return DDI_SUCCESS;
+ }
+ else {
+ return DDI_FAILURE;
+ }
+}
+
+static struct module_info vxnminfo = {
+ 0, /* mi_idnum */
+ "vmxnet", /* mi_idname */
+ 0, /* mi_minpsz */
+ ETHERMTU, /* mi_maxpsz */
+ QHIWATER, /* mi_hiwat */
+ 1, /* mi_lowat */
+};
+
+static struct qinit vxnrinit = {
+ NULL, /* qi_putp */
+ gld_rsrv, /* qi_srvp */
+ gld_open, /* qi_qopen */
+ gld_close, /* qi_qclose */
+ NULL, /* qi_qadmin */
+ &vxnminfo, /* qi_minfo */
+ NULL /* qi_mstat */
+};
+
+static struct qinit vxnwinit = {
+ gld_wput, /* qi_putp */
+ gld_wsrv, /* qi_srvp */
+ NULL, /* qi_qopen */
+ NULL, /* qi_qclose */
+ NULL, /* qi_qadmin */
+ &vxnminfo, /* qi_minfo */
+ NULL /* qi_mstat */
+};
+
+static struct streamtab vxn_info = {
+ &vxnrinit, /* st_rdinit */
+ &vxnwinit, /* st_wrinit */
+ NULL, /* st_muxrinit */
+ NULL /* st_muxwrinit */
+};
+
+static struct cb_ops cb_vxn_ops = {
+ nulldev, /* cb_open */
+ nulldev, /* cb_close */
+ nodev, /* cb_strategy */
+ nodev, /* cb_print */
+ nodev, /* cb_dump */
+ nodev, /* cb_read */
+ nodev, /* cb_write */
+ nodev, /* cb_ioctl */
+ nodev, /* cb_devmap */
+ nodev, /* cb_mmap */
+ nodev, /* cb_segmap */
+ nochpoll, /* cb_chpoll */
+ ddi_prop_op, /* cb_prop_op */
+ &vxn_info, /* cb_stream */
+ D_NEW|D_MP /* cb_flag */
+};
+
+static struct dev_ops vxn_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* devo_refcnt */
+ gld_getinfo, /* devo_getinfo */
+ nulldev, /* devo_identify */
+ nulldev, /* devo_probe */
+ Vxn_Attach, /* devo_attach */
+ Vxn_Detach, /* devo_detach */
+ nodev, /* devo_reset */
+ &cb_vxn_ops, /* devo_cb_ops */
+ NULL, /* devo_bus_ops */
+ ddi_power /* devo_power */
+};
+
+static struct modldrv modldrv = {
+ &mod_driverops,
+ ident,
+ &vxn_ops,
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, {&modldrv, NULL,}
+};
+
+
+/*
+ * Module load entry point
+ */
+int
+_init(void)
+{
+ int err;
+
+ DPRINTF(5, (CE_CONT, "vxn: _init:\n"));
+ /* Initialize interface list */
+ vxnList.next = vxnList.prev = &vxnList;
+ mutex_init(&vxnListLock, NULL, MUTEX_DRIVER, NULL);
+ if ((err = mod_install(&modlinkage)) != 0) {
+ mutex_destroy(&vxnListLock);
+ }
+ return err;
+}
+
+/*
+ * Module unload entry point
+ */
+int
+_fini(void)
+{
+ int err;
+
+ DPRINTF(5, (CE_CONT, "vxn: _fini:\n"));
+ if ((err = mod_remove(&modlinkage)) == 0) {
+ mutex_destroy(&vxnListLock);
+ }
+ return err;
+}
+
+/*
+ * Module info entry point
+ */
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+#ifndef _VMXNET2_DEF_H_
+#define _VMXNET2_DEF_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#include "net_sg.h"
+#include "vmxnet_def.h"
+
+
+/*
+ * Magic number that identifies this version of the vmxnet protocol.
+ */
+#define VMXNET2_MAGIC 0xbabe864f
+
+/* size of the rx ring */
+#define VMXNET2_MAX_NUM_RX_BUFFERS 128
+#define VMXNET2_DEFAULT_NUM_RX_BUFFERS 100
+
+
+/* size of the rx ring when enhanced vmxnet is used */
+#define ENHANCED_VMXNET2_MAX_NUM_RX_BUFFERS 512
+#define ENHANCED_VMXNET2_DEFAULT_NUM_RX_BUFFERS 150
+
+/* size of the 2nd rx ring */
+#define VMXNET2_MAX_NUM_RX_BUFFERS2 2048
+#define VMXNET2_DEFAULT_NUM_RX_BUFFERS2 512
+
+/* size of the tx ring */
+#define VMXNET2_MAX_NUM_TX_BUFFERS 128
+#define VMXNET2_DEFAULT_NUM_TX_BUFFERS 100
+
+/* size of the tx ring when tso/jf is used */
+#define VMXNET2_MAX_NUM_TX_BUFFERS_TSO 512
+#define VMXNET2_DEFAULT_NUM_TX_BUFFERS_TSO 256
+
+enum {
+ VMXNET2_OWNERSHIP_DRIVER,
+ VMXNET2_OWNERSHIP_DRIVER_PENDING,
+ VMXNET2_OWNERSHIP_NIC,
+ VMXNET2_OWNERSHIP_NIC_PENDING,
+ VMXNET2_OWNERSHIP_NIC_FRAG,
+ VMXNET2_OWNERSHIP_DRIVER_FRAG,
+};
+
+#define VMXNET2_SG_DEFAULT_LENGTH 6
+
+typedef struct Vmxnet2_SG_Array {
+ uint16 addrType;
+ uint16 length;
+ NetSG_Elem sg[VMXNET2_SG_DEFAULT_LENGTH];
+} Vmxnet2_SG_Array;
+
+typedef struct Vmxnet2_RxRingEntry {
+ uint64 paddr; /* Physical address of the packet data. */
+ uint32 bufferLength; /* The length of the data at paddr. */
+ uint32 actualLength; /* The actual length of the received data. */
+ uint16 ownership; /* Who owns the packet. */
+ uint16 flags; /* Flags as defined below. */
+ uint32 index; /*
+ * Currently:
+ *
+ * This is being used as an packet index to
+ * rx buffers.
+ *
+ * Originally:
+ *
+ * was void* driverData ("Driver specific data.")
+ * which was used for sk_buf**s in Linux and
+ * VmxnetRxBuff*s in Windows. It could not be
+ * here because the structure needs to be the
+ * same size between architectures, and it was
+ * not used on the device side, anyway. Look
+ * for its replacement in
+ * Vmxnet_Private.rxRingBuffPtr on Linux and
+ * VmxnetAdapter.rxRingBuffPtr on Windows.
+ */
+} Vmxnet2_RxRingEntry;
+
+/*
+ * Vmxnet2_RxRingEntry flags:
+ *
+ * VMXNET2_RX_HW_XSUM_OK The hardware verified the TCP/UDP checksum.
+ * VMXNET2_RX_WITH_FRAG More data is in the 2nd ring
+ * VMXNET2_RX_FRAG_EOP This is the last frag, the only valid flag for
+ * 2nd ring entry
+ *
+ */
+#define VMXNET2_RX_HW_XSUM_OK 0x01
+#define VMXNET2_RX_WITH_FRAG 0x02
+#define VMXNET2_RX_FRAG_EOP 0x04
+
+typedef struct Vmxnet2_TxRingEntry {
+ uint16 flags; /* Flags as defined below. */
+ uint16 ownership; /* Who owns this packet. */
+ uint32 extra; /*
+ * was void* driverData ("Driver specific data.")
+ * which was used for sk_buf*s in Linux and
+ * VmxnetTxInfo*s in Windows. It could not be
+ * here because the structure needs to be the
+ * same size between architectures, and it was
+ * not used on the device side, anyway. Look
+ * for its replacement in
+ * Vmxnet_Private.txRingBuffPtr on Linux and
+ * VmxnetAdapter.txRingBuffPtr on Windows.
+ */
+ uint32 tsoMss; /* TSO pkt MSS */
+ Vmxnet2_SG_Array sg; /* Packet data. */
+} Vmxnet2_TxRingEntry;
+
+/*
+ * Vmxnet2_TxRingEntry flags:
+ *
+ * VMXNET2_TX_CAN_KEEP The implementation can return the tx ring entry
+ * to the driver when it is ready as opposed to
+ * before the transmit call from the driver completes.
+ * VMXNET2_TX_RING_LOW The driver's transmit ring buffer is low on free
+ * slots.
+ * VMXNET2_TX_HW_XSUM The hardware should perform the TCP/UDP checksum
+ * VMXNET2_TX_TSO The hardware should do TCP segmentation.
+ * VMXNET2_TX_PINNED_BUFFER The driver used one of the preallocated vmkernel
+ * buffers *and* it has been pinned with Net_PinTxBuffers.
+ * VMXNET2_TX_MORE This is *not* the last tx entry for the pkt.
+ * All flags except VMXNET2_TX_MORE are ignored
+ * for the subsequent tx entries.
+ */
+#define VMXNET2_TX_CAN_KEEP 0x0001
+#define VMXNET2_TX_RING_LOW 0x0002
+#define VMXNET2_TX_HW_XSUM 0x0004
+#define VMXNET2_TX_TSO 0x0008
+#define VMXNET2_TX_PINNED_BUFFER 0x0010
+#define VMXNET2_TX_MORE 0x0020
+
+/*
+ * Structure used by implementations. This structure allows the inline
+ * functions below to be used.
+ */
+typedef struct Vmxnet2_RxRingInfo {
+ Vmxnet2_RxRingEntry *base; /* starting addr of the ring */
+ uint32 nicNext; /* next entry to use in the ring */
+ uint32 ringLength; /* # of entries in the ring */
+ PA startPA; /* PA of the starting addr of the ring */
+#ifdef VMX86_DEBUG
+ const char *name;
+#endif
+} Vmxnet2_RxRingInfo;
+
+typedef struct Vmxnet2_TxRingInfo {
+ Vmxnet2_TxRingEntry *base; /* starting addr of the ring */
+ uint32 nicNext; /* next entry to use in the ring */
+ uint32 ringLength; /* # of entries in the ring */
+ PA startPA; /* PA of the starting addr of the ring */
+#ifdef VMX86_DEBUG
+ const char *name;
+#endif
+} Vmxnet2_TxRingInfo;
+
+typedef struct Vmxnet2_ImplData {
+ Vmxnet2_RxRingInfo rxRing;
+ Vmxnet2_RxRingInfo rxRing2;
+ Vmxnet2_TxRingInfo txRing;
+
+ struct PhysMem_Token *ddPhysMemToken;
+} Vmxnet2_ImplData;
+
+/*
+ * Used internally for performance studies. By default this will be off so there
+ * should be no compatibilty or other interferences.
+ */
+
+/* #define ENABLE_VMXNET2_PROFILING */
+
+
+#ifdef ENABLE_VMXNET2_PROFILING
+typedef struct Vmxnet2_VmmStats {
+ uint64 vIntTSC; /* the time that virtual int was posted */
+ uint64 actionsCount; /* Number of actions received */
+ uint64 numWasteActions; /* Number of non-productive actions */
+} Vmxnet2_VmmStats;
+#endif
+
+typedef struct Vmxnet2_DriverStats {
+ uint32 transmits; /* # of times that the drivers transmit function */
+ /* is called. The driver could transmit more */
+ /* than one packet per call. */
+ uint32 pktsTransmitted; /* # of packets transmitted. */
+ uint32 noCopyTransmits; /* # of packets that are transmitted without */
+ /* copying any data. */
+ uint32 copyTransmits; /* # of packets that are transmittted by copying */
+ /* the data into a buffer. */
+ uint32 maxTxsPending; /* Max # of transmits outstanding. */
+ uint32 txStopped; /* # of times that transmits got stopped because */
+ /* the tx ring was full. */
+ uint32 txRingOverflow; /* # of times that transmits got deferred bc */
+ /* the tx ring was full. This must be >= */
+ /* txStopped since there will be one */
+ /* txStopped when the ring fills up and then */
+ /* one txsRingOverflow for each packet that */
+ /* that gets deferred until there is space. */
+ uint32 interrupts; /* # of times interrupted. */
+ uint32 pktsReceived; /* # of packets received. */
+ uint32 rxBuffersLow; /* # of times that the driver was low on */
+ /* receive buffers. */
+#ifdef ENABLE_VMXNET2_PROFILING
+ Vmxnet2_VmmStats vmmStats; /* vmm related stats for perf study */
+#endif
+} Vmxnet2_DriverStats;
+
+/*
+ * Shared data structure between the vm, the vmm, and the vmkernel.
+ * This structure was originally arranged to try to group common data
+ * on 32-byte cache lines, but bit rot and the fact that we no longer
+ * run on many CPUs with that cacheline size killed that optimization.
+ * vmxnet3 should target 128 byte sizes and alignments to optimize for
+ * the 64 byte cacheline pairs on P4.
+ */
+typedef struct Vmxnet2_DriverData {
+ /*
+ * Magic must be first.
+ */
+ Vmxnet_DDMagic magic;
+
+ /*
+ * Receive fields.
+ */
+ uint32 rxRingLength; /* Length of the receive ring. */
+ uint32 rxDriverNext; /* Index of the next packet that will */
+ /* be filled in by the impl */
+
+ uint32 rxRingLength2; /* Length of the 2nd receive ring. */
+ uint32 rxDriverNext2; /* Index of the next packet that will */
+ /* be filled in by the impl */
+
+ uint32 notUsed1; /* was "irq" */
+
+ /*
+ * Interface flags and multicast filter.
+ */
+ uint32 ifflags;
+ uint32 LADRF[VMXNET_MAX_LADRF];
+
+ /*
+ * Transmit fields
+ */
+ uint32 txDontClusterSize; /* All packets <= this will be transmitted */
+ /* immediately, regardless of clustering */
+ /* settings [was fill[1]] */
+ uint32 txRingLength; /* Length of the transmit ring. */
+ uint32 txDriverCur; /* Index of the next packet to be */
+ /* returned by the implementation.*/
+ uint32 txDriverNext; /* Index of the entry in the ring */
+ /* buffer to use for the next packet.*/
+ uint32 txStopped; /* The driver has stopped transmitting */
+ /* because its ring buffer is full.*/
+ uint32 txClusterLength; /* Maximum number of packets to */
+ /* put in the ring buffer before */
+ /* asking the implementation to */
+ /* transmit the packets in the buffer.*/
+ uint32 txNumDeferred; /* Number of packets that have been */
+ /* queued in the ring buffer since */
+ /* the last time the implementation */
+ /* was asked to transmit. */
+ uint32 notUsed3; /* This field is deprecated but still used */
+ /* as minXmitPhysLength on the escher branch. */
+ /* It cannot be used for other purposes */
+ /* until escher vms no longer are allowed */
+ /* to install this driver. */
+
+ uint32 totalRxBuffers; /* used by esx for max rx buffers */
+ uint64 rxBufferPhysStart; /* used by esx for pinng rx buffers */
+ /*
+ * Extra fields for future expansion.
+ */
+ uint32 extra[2];
+
+ uint16 maxFrags; /* # of frags the driver can handle */
+ uint16 featureCtl; /* for driver to enable some feature */
+
+ /*
+ * The following fields are used to save the nicNext indexes part
+ * of implData in the vmkernel when disconnecting the adapter, we
+ * need them when we reconnect. This mechanism is used for
+ * checkpointing as well.
+ */
+ uint32 savedRxNICNext;
+ uint32 savedRxNICNext2;
+ uint32 savedTxNICNext;
+
+ /*
+ * Fields used during initialization or debugging.
+ */
+ uint32 length;
+ uint32 rxRingOffset;
+ uint32 rxRingOffset2;
+ uint32 txRingOffset;
+ uint32 debugLevel;
+ uint32 txBufferPhysStart;
+ uint32 txBufferPhysLength;
+ uint32 txPktMaxSize;
+
+ /*
+ * Driver statistics.
+ */
+ Vmxnet2_DriverStats stats;
+} Vmxnet2_DriverData;
+
+/*
+ * Shared between VMM and Vmkernel part of vmxnet2 to optimize action posting
+ * VMM writes 1 (don't post) or 0 (okay to post) and vmk reads this.
+ */
+typedef struct VmxnetVMKShared {
+ uint32 dontPostActions;
+} VmxnetVMKShared;
+
+/*
+ * Inline functions used to assist the implementation of the vmxnet interface.
+ */
+
+/*
+ * Get the next empty packet out of the receive ring and move to
+ * the next packet.
+ */
+static INLINE Vmxnet2_RxRingEntry *
+Vmxnet2_GetNextRx(Vmxnet2_RxRingInfo *ri, uint16 ownership)
+{
+ Vmxnet2_RxRingEntry *rre = ri->base + ri->nicNext;
+ if (rre->ownership == ownership) {
+ VMXNET_INC(ri->nicNext, ri->ringLength);
+ } else {
+ rre = NULL;
+ }
+
+ return rre;
+}
+
+/*
+ * Return ownership of a packet in the receive ring to the driver.
+ */
+static INLINE void
+Vmxnet2_PutRx(Vmxnet2_RxRingEntry *rre, uint32 pktLength, uint16 ownership)
+{
+ rre->actualLength = pktLength;
+ rre->ownership = ownership;
+}
+
+/*
+ * Get the next pending packet out of the transmit ring.
+ */
+static INLINE Vmxnet2_TxRingEntry *
+Vmxnet2_GetNextTx(Vmxnet2_TxRingInfo *ri)
+{
+ Vmxnet2_TxRingEntry *txre = ri->base + ri->nicNext;
+ if (txre->ownership == VMXNET2_OWNERSHIP_NIC) {
+ return txre;
+ } else {
+ return NULL;
+ }
+}
+
+/*
+ * Move to the next entry in the transmit ring.
+ */
+static INLINE unsigned int
+Vmxnet2_IncNextTx(Vmxnet2_TxRingInfo *ri)
+{
+ unsigned int prev = ri->nicNext;
+ Vmxnet2_TxRingEntry *txre = ri->base + ri->nicNext;
+
+ txre->ownership = VMXNET2_OWNERSHIP_NIC_PENDING;
+
+ VMXNET_INC(ri->nicNext, ri->ringLength);
+ return prev;
+}
+
+/*
+ * Get the indicated entry from transmit ring.
+ */
+static INLINE Vmxnet2_TxRingEntry *
+Vmxnet2_GetTxEntry(Vmxnet2_TxRingInfo *ri, unsigned int idx)
+{
+ return ri->base + idx;
+}
+
+/*
+ * Get the indicated entry from the given rx ring
+ */
+static INLINE Vmxnet2_RxRingEntry *
+Vmxnet2_GetRxEntry(Vmxnet2_RxRingInfo *ri, unsigned int idx)
+{
+ return ri->base + idx;
+}
+#endif
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1999 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version. You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+#ifndef _VMXNET_DEF_H_
+#define _VMXNET_DEF_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#include "net_sg.h"
+#include "vmnet_def.h"
+
+
+/*
+ * Vmxnet I/O ports, used by both the vmxnet driver and
+ * the device emulation code.
+ */
+
+#define VMXNET_INIT_ADDR 0x00
+#define VMXNET_INIT_LENGTH 0x04
+#define VMXNET_TX_ADDR 0x08
+#define VMXNET_COMMAND_ADDR 0x0c
+#define VMXNET_MAC_ADDR 0x10
+#define VMXNET_LOW_VERSION 0x18
+#define VMXNET_HIGH_VERSION 0x1c
+#define VMXNET_STATUS_ADDR 0x20
+#define VMXNET_TOE_INIT_ADDR 0x24
+#define VMXNET_APROM_ADDR 0x28
+#define VMXNET_INT_ENABLE_ADDR 0x30
+#define VMXNET_WAKE_PKT_PATTERNS 0x34
+
+/*
+ * Vmxnet command register values.
+ */
+#define VMXNET_CMD_INTR_ACK 0x0001
+#define VMXNET_CMD_UPDATE_LADRF 0x0002
+#define VMXNET_CMD_UPDATE_IFF 0x0004
+#define VMXNET_CMD_UNUSED 1 0x0008
+#define VMXNET_CMD_UNUSED_2 0x0010
+#define VMXNET_CMD_INTR_DISABLE 0x0020
+#define VMXNET_CMD_INTR_ENABLE 0x0040
+#define VMXNET_CMD_UNUSED_3 0x0080
+#define VMXNET_CMD_CHECK_TX_DONE 0x0100
+#define VMXNET_CMD_GET_NUM_RX_BUFFERS 0x0200
+#define VMXNET_CMD_GET_NUM_TX_BUFFERS 0x0400
+#define VMXNET_CMD_PIN_TX_BUFFERS 0x0800
+#define VMXNET_CMD_GET_CAPABILITIES 0x1000
+#define VMXNET_CMD_GET_FEATURES 0x2000
+#define VMXNET_CMD_SET_POWER_FULL 0x4000
+#define VMXNET_CMD_SET_POWER_LOW 0x8000
+
+/*
+ * Vmxnet status register values.
+ */
+#define VMXNET_STATUS_CONNECTED 0x0001
+#define VMXNET_STATUS_ENABLED 0x0002
+#define VMXNET_STATUS_TX_PINNED 0x0004
+
+/*
+ * Values for the interface flags.
+ */
+#define VMXNET_IFF_PROMISC 0x01
+#define VMXNET_IFF_BROADCAST 0x02
+#define VMXNET_IFF_MULTICAST 0x04
+#define VMXNET_IFF_DIRECTED 0x08
+
+/*
+ * Length of the multicast address filter.
+ */
+#define VMXNET_MAX_LADRF 2
+
+/*
+ * Size of Vmxnet APROM.
+ */
+#define VMXNET_APROM_SIZE 6
+
+/*
+ * An invalid ring index.
+ */
+#define VMXNET_INVALID_RING_INDEX (-1)
+
+/*
+ * Features that are implemented by the driver. These are driver
+ * specific so not all features will be listed here. In addition not all
+ * drivers have to pay attention to these feature flags.
+ *
+ * VMXNET_FEATURE_ZERO_COPY_TX The driver won't do any copies as long as
+ * the packet length is >
+ * Vmxnet_DriverData.minTxPhysLength.
+ *
+ * VMXNET_FEATURE_TSO The driver will use the TSO capabilities
+ * of the underlying hardware if available
+ * and enabled.
+ *
+ * VMXNET_FEATURE_JUMBO_FRAME The driver can send/rcv jumbo frame
+ *
+ * VMXNET_FEATURE_LPD The backend can deliver large pkts
+ */
+#define VMXNET_FEATURE_ZERO_COPY_TX 0x01
+#define VMXNET_FEATURE_TSO 0x02
+#define VMXNET_FEATURE_JUMBO_FRAME 0x04
+#define VMXNET_FEATURE_LPD 0x08
+
+/*
+ * Define the set of capabilities required by each feature above
+ */
+#define VMXNET_FEATURE_ZERO_COPY_TX_CAPS VMXNET_CAP_SG
+#define VMXNET_FEATURE_TSO_CAPS VMXNET_CAP_TSO
+#define VMXNET_HIGHEST_FEATURE_BIT VMXNET_FEATURE_TSO
+
+#define VMXNET_INC(val, max) \
+ val++; \
+ if (UNLIKELY(val == max)) { \
+ val = 0; \
+ }
+
+/*
+ * code that just wants to switch on the different versions of the
+ * guest<->implementation protocol can cast driver data to this.
+ */
+typedef uint32 Vmxnet_DDMagic;
+
+/*
+ * Wake packet pattern commands sent through VMXNET_WAKE_PKT_PATTERNS port
+ */
+
+#define VMXNET_PM_OPCODE_START 3 /* args: cnt of wake packet patterns */
+#define VMXNET_PM_OPCODE_LEN 2 /* args: index of wake packet pattern */
+ /* number of pattern byte values */
+#define VMXNET_PM_OPCODE_DATA 1 /* args: index of wake packet pattern */
+ /* offset in pattern byte values list */
+ /* packet byte offset */
+ /* packet byte value */
+#define VMXNET_PM_OPCODE_END 0 /* args: <none> */
+
+typedef union Vmxnet_WakePktCmd {
+ uint32 pktData : 32;
+ struct {
+ unsigned cmd : 2; /* wake packet pattern cmd [from list above] */
+ unsigned cnt : 3; /* cnt wk pkt pttrns 1..MAX_NUM_FILTER_PTTRNS */
+ unsigned ind : 3; /* ind wk pkt pttrn 0..MAX_NUM_FILTER_PTTRNS-1 */
+ unsigned lenOff : 8; /* num pttrn byte vals 1..MAX_PKT_FILTER_SIZE */
+ /* OR offset in pattern byte values list */
+ /* 0..MAX_PKT_FILTER_SIZE-1 */
+ unsigned byteOff : 8; /* pkt byte offset 0..MAX_PKT_FILTER_SIZE-1 */
+ unsigned byteVal : 8; /* packet byte value 0..255 */
+ } pktPttrn;
+} Vmxnet_WakePktCmd;
+
+#endif /* _VMXNET_DEF_H_ */
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+SUBDIRS =
+SUBDIRS += vmtoolsd
+SUBDIRS += plugins
+
+install-exec-local:
+ mkdir -p $(DESTDIR)/etc/vmware-tools
+ ln -sf `dirname $(VMSVC_PLUGIN_INSTALLDIR)` $(DESTDIR)/etc/vmware-tools/plugins
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+SUBDIRS =
+SUBDIRS += guestInfo
+SUBDIRS += hgfsServer
+SUBDIRS += powerOps
+if HAVE_X11
+ SUBDIRS += resolutionSet
+endif
+SUBDIRS += timeSync
+SUBDIRS += vix
+if HAVE_X11
+ SUBDIRS += vixUser
+endif
+SUBDIRS += vmbackup
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libguestInfo.la
+
+libguestInfo_la_CPPFLAGS =
+libguestInfo_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
+
+libguestInfo_la_LDFLAGS =
+libguestInfo_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libguestInfo_la_LIBADD =
+libguestInfo_la_LIBADD += @VMTOOLS_LIBS@
+libguestInfo_la_LIBADD += @PROCPS_LIBS@
+libguestInfo_la_LIBADD += @XDR_LIBS@
+
+libguestInfo_la_SOURCES =
+libguestInfo_la_SOURCES += guestInfoServer.c
+libguestInfo_la_SOURCES += perfMonLinux.c
+
+install-exec-local:
+ mkdir -p $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+ cp -L $(builddir)/.libs/libguestInfo.so $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file guestInfoInt.h
+ *
+ * Declares internal functions of the guestInfo plugin.
+ */
+
+#include "guestInfo.h"
+#define G_LOG_DOMAIN "guestinfo"
+
+Bool
+GuestInfo_PerfMon(struct GuestMemInfo *vmStats);
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * guestInfoServer.c --
+ *
+ * This is the implementation of the common code in the guest tools
+ * to send out guest information to the host. The guest info server
+ * runs in the context of the tools daemon's event loop and periodically
+ * gathers all guest information and sends updates to the host if required.
+ * This file implements the platform independent framework for this.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+
+#include "vmware.h"
+#include "buildNumber.h"
+#include "conf.h"
+#include "debug.h"
+#include "dynxdr.h"
+#include "hostinfo.h"
+#include "guestInfoInt.h"
+#include "guest_msg_def.h" // For GUESTMSG_MAX_IN_SIZE
+#include "netutil.h"
+#include "rpcChannel.h"
+#include "rpcvmx.h"
+#include "str.h"
+#include "system.h"
+#include "util.h"
+#include "vm_app.h"
+#include "vmtools.h"
+#include "vmtoolsApp.h"
+#include "xdrutil.h"
+
+#if !defined(__APPLE__)
+#include "embed_version.h"
+#include "vmtoolsd_version.h"
+VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
+#endif
+
+
+#define GUESTINFO_DEFAULT_DELIMITER ' '
+
+/*
+ * Stores information about all guest information sent to the vmx.
+ */
+
+typedef struct _GuestInfoCache{
+ char value[INFO_MAX][MAX_VALUE_LEN]; /* Stores values of all key-value pairs. */
+ GuestNicList nicInfo;
+ GuestDiskInfo diskInfo;
+} GuestInfoCache;
+
+
+/*
+ * Local variables.
+ */
+static gboolean gDisableQueryDiskInfo = FALSE;
+
+/* Local cache of the guest information that was last sent to vmx. */
+static GuestInfoCache gInfoCache;
+
+/*
+ * A boolean flag that specifies whether the state of the VM was
+ * changed since the last time guest info was sent to the VMX.
+ * Tools daemon sets it to TRUE after the VM was resumed.
+ */
+
+static Bool vmResumed;
+
+static Bool GuestInfoUpdateVmdb(ToolsAppCtx *ctx, GuestInfoType infoType, void *info);
+static Bool SetGuestInfo(ToolsAppCtx *ctx, GuestInfoType key,
+ const char *value, char delimiter);
+static Bool NicInfoChanged(GuestNicList *nicInfo);
+static Bool DiskInfoChanged(PGuestDiskInfo diskInfo);
+static void GuestInfoClearCache(void);
+static int PrintNicInfo(GuestNicList *nicInfo, int (*PrintFunc)(const char *, ...));
+
+/**
+ * Cleanup internal data on shutdown.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx Unused.
+ * @param[in] data Unused.
+ */
+
+static void
+GuestInfoServerShutdown(gpointer src,
+ ToolsAppCtx *ctx,
+ gpointer data)
+{
+ GuestInfoClearCache();
+}
+
+
+/**
+ * Reset callback - sets the internal flag that says we should purge all
+ * caches.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx Unused.
+ * @param[in] data Unused.
+ */
+
+static void
+GuestInfoServerReset(gpointer src,
+ ToolsAppCtx *ctx,
+ gpointer data)
+{
+ vmResumed = TRUE;
+}
+
+
+/**
+ * Send the guest uptime through the backdoor, if @a set is TRUE.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The application context.
+ * @param[in] set Whether capabilities are being set.
+ * @param[in] data Unused.
+ *
+ * @return NULL
+ */
+
+static GArray *
+GuestInfoServerSendUptime(gpointer src,
+ ToolsAppCtx *ctx,
+ gboolean set,
+ gpointer data)
+{
+ if (set) {
+ gchar *uptime = g_strdup_printf("%"FMT64"u", System_Uptime());
+ g_debug("Setting guest uptime to '%s'\n", uptime);
+ GuestInfoUpdateVmdb(ctx, INFO_UPTIME, uptime);
+ g_free(uptime);
+ }
+ return NULL;
+}
+
+
+/**
+ * Responds to a "broadcastIP" Set_Option command, by sending the primary IP
+ * back to the VMX.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The application context.
+ * @param[in] option Option name.
+ * @param[in] value Option value.
+ * @param[in] data Unused.
+ */
+
+static gboolean
+GuestInfoServerSetOption(gpointer src,
+ ToolsAppCtx *ctx,
+ const gchar *option,
+ const gchar *value,
+ gpointer data)
+{
+ char *ip;
+ Bool ret = FALSE;
+
+ if (strcmp(option, TOOLSOPTION_BROADCASTIP) != 0) {
+ goto exit;
+ }
+
+ if (strcmp(value, "0") == 0) {
+ ret = TRUE;
+ goto exit;
+ }
+
+ if (strcmp(value, "1") != 0) {
+ goto exit;
+ }
+
+ ip = NetUtil_GetPrimaryIP();
+
+ if (ip != NULL) {
+ gchar *msg;
+ msg = g_strdup_printf("info-set guestinfo.ip %s", ip);
+ ret = RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL);
+ vm_free(ip);
+ g_free(msg);
+ }
+
+exit:
+ return (gboolean) ret;
+}
+
+
+/**
+ * Periodically collects all the desired guest information and updates VMDB.
+ *
+ * @param[in] data The application context.
+ *
+ * @return TRUE.
+ */
+
+static gboolean
+GuestInfoGather(gpointer data)
+{
+ char name[255];
+ char osNameFull[MAX_VALUE_LEN];
+ char osName[MAX_VALUE_LEN];
+ GuestNicList nicInfo;
+ GuestDiskInfo diskInfo;
+#if defined(_WIN32) || defined(linux)
+ GuestMemInfo vmStats = {0};
+#endif
+ ToolsAppCtx *ctx = data;
+
+ g_debug("Entered guest info gather.\n");
+
+ memset(&nicInfo, 0, sizeof nicInfo);
+
+ /* Send tools version. */
+ if (!GuestInfoUpdateVmdb(ctx, INFO_BUILD_NUMBER, BUILD_NUMBER)) {
+ /*
+ * An older vmx talking to new tools wont be able to handle
+ * this message. Continue, if thats the case.
+ */
+
+ g_warning("Failed to update VMDB with tools version.\n");
+ }
+
+ /* Gather all the relevant guest information. */
+ if (!Hostinfo_GetOSName(sizeof osNameFull, sizeof osName, osNameFull,
+ osName)) {
+ g_warning("Failed to get OS info.\n");
+ } else {
+ if (!GuestInfoUpdateVmdb(ctx, INFO_OS_NAME_FULL, osNameFull)) {
+ g_warning("Failed to update VMDB\n");
+ }
+ if (!GuestInfoUpdateVmdb(ctx, INFO_OS_NAME, osName)) {
+ g_warning("Failed to update VMDB\n");
+ }
+ }
+
+ if (!gDisableQueryDiskInfo) {
+ if (!GuestInfo_GetDiskInfo(&diskInfo)) {
+ g_warning("Failed to get disk info.\n");
+ } else {
+ if (!GuestInfoUpdateVmdb(ctx, INFO_DISK_FREE_SPACE, &diskInfo)) {
+ g_warning("Failed to update VMDB\n.");
+ }
+ }
+ /* Free memory allocated in GuestInfoGetDiskInfo. */
+ if (diskInfo.partitionList != NULL) {
+ vm_free(diskInfo.partitionList);
+ diskInfo.partitionList = NULL;
+ }
+ }
+
+ if (!GuestInfo_GetFqdn(sizeof name, name)) {
+ g_warning("Failed to get netbios name.\n");
+ } else if (!GuestInfoUpdateVmdb(ctx, INFO_DNS_NAME, name)) {
+ g_warning("Failed to update VMDB.\n");
+ }
+
+ /* Get NIC information. */
+ if (!GuestInfo_GetNicInfo(&nicInfo)) {
+ g_warning("Failed to get nic info.\n");
+ } else if (NicInfoChanged(&nicInfo)) {
+ if (GuestInfoUpdateVmdb(ctx, INFO_IPADDRESS, &nicInfo)) {
+ /*
+ * Update the cache. Release the memory previously used by the cache,
+ * and copy the new information into the cache.
+ */
+ VMX_XDR_FREE(xdr_GuestNicList, &gInfoCache.nicInfo);
+ gInfoCache.nicInfo = nicInfo;
+ } else {
+ g_warning("Failed to update VMDB.\n");
+ }
+ } else {
+ g_debug("Nic info not changed.\n");
+ VMX_XDR_FREE(xdr_GuestNicList, &nicInfo);
+ }
+
+ /* Send the uptime to VMX so that it can detect soft resets. */
+ GuestInfoServerSendUptime(NULL, ctx, TRUE, NULL);
+
+#if defined(_WIN32) || defined(linux)
+ /* Send the vmstats to the VMX. */
+
+ if (!GuestInfo_PerfMon(&vmStats)) {
+ g_warning("Failed to get vmstats.\n");
+ } else {
+ vmStats.version = 1;
+ if (!GuestInfoUpdateVmdb(ctx, INFO_MEMORY, &vmStats)) {
+ g_warning("Failed to send vmstats.\n");
+ }
+ }
+#endif
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GuestInfoConvertNicInfoToNicInfoV1 --
+ *
+ * Convert the new dynamic nicInfoNew to fixed size struct GuestNicInfoV1.
+ *
+ * Results:
+ * TRUE if successfully converted
+ * FALSE otherwise
+ *
+ * Side effects:
+ * If number of NICs or number of IP addresses on any of the NICs
+ * exceeding MAX_NICS and MAX_IPS respectively, the extra ones
+ * are truncated, on successful return.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Bool
+GuestInfoConvertNicInfoToNicInfoV1(GuestNicList *info, // IN
+ GuestNicInfoV1 *infoV1) // OUT
+{
+ uint32 maxNics;
+ u_int i;
+
+ if ((NULL == info) ||
+ (NULL == infoV1)) {
+ return FALSE;
+ }
+
+ maxNics = MIN(info->nics.nics_len, MAX_NICS);
+ infoV1->numNicEntries = maxNics;
+ if (maxNics < info->nics.nics_len) {
+ g_debug("Truncating NIC list for backwards compatibility.\n");
+ }
+
+ XDRUTIL_FOREACH(i, info, nics) {
+ u_int j;
+ uint32 maxIPs;
+ GuestNic *nic = XDRUTIL_GETITEM(info, nics, i);
+
+ Str_Strcpy(infoV1->nicList[i].macAddress,
+ nic->macAddress,
+ sizeof infoV1->nicList[i].macAddress);
+
+ maxIPs = MIN(nic->ips.ips_len, MAX_IPS);
+ infoV1->nicList[i].numIPs = 0;
+
+ XDRUTIL_FOREACH(j, nic, ips) {
+ VmIpAddress *ip = XDRUTIL_GETITEM(nic, ips, j);
+
+ if (strlen(ip->ipAddress) < sizeof infoV1->nicList[i].ipAddress[j]) {
+ Str_Strcpy(infoV1->nicList[i].ipAddress[j],
+ ip->ipAddress,
+ sizeof infoV1->nicList[i].ipAddress[j]);
+ infoV1->nicList[i].numIPs++;
+ if (infoV1->nicList[i].numIPs == maxIPs) {
+ break;
+ }
+ } else {
+ g_debug("Ignoring IPV6 address for compatibility.\n");
+ }
+ }
+
+ if (infoV1->nicList[i].numIPs != nic->ips.ips_len) {
+ g_debug("Some IP addresses were ignored for compatibility.\n");
+ }
+ if (i == maxNics) {
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * GuestInfoUpdateVmdb --
+ *
+ * Update VMDB with new guest information.
+ * This is the only function that should need to change when the VMDB pipe
+ * is implemented. Since we dont currently have a VMDB instance in the guest
+ * the function updates the VMDB instance on the host. Updates are sent only
+ * if the values have changed.
+ *
+ * Result
+ * TRUE on success, FALSE on failure.
+ *
+ * Side-effects
+ * VMDB is updated if the given value has changed.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+GuestInfoUpdateVmdb(ToolsAppCtx *ctx, // IN: Application context
+ GuestInfoType infoType, // IN: guest information type
+ void *info) // IN: type specific information
+{
+ ASSERT(info);
+ g_debug("Entered update vmdb: %d.\n", infoType);
+
+ if (vmResumed) {
+ vmResumed = FALSE;
+ GuestInfoClearCache();
+ }
+
+ switch (infoType) {
+ case INFO_DNS_NAME:
+ case INFO_BUILD_NUMBER:
+ case INFO_OS_NAME:
+ case INFO_OS_NAME_FULL:
+ case INFO_UPTIME:
+ /*
+ * This is one of our key value pairs. Update it if it has changed.
+ * Above fall-through is intentional.
+ */
+
+ if (strcmp(gInfoCache.value[infoType], (char *)info) == 0) {
+ /* The value has not changed */
+ g_debug("Value unchanged for infotype %d.\n", infoType);
+ break;
+ }
+
+ if (!SetGuestInfo(ctx, infoType, (char *)info, 0)) {
+ g_warning("Failed to update key/value pair for type %d.\n", infoType);
+ return FALSE;
+ }
+
+ /* Update the value in the cache as well. */
+ Str_Strcpy(gInfoCache.value[infoType], (char *)info, MAX_VALUE_LEN);
+ break;
+
+ case INFO_IPADDRESS:
+ {
+ static Bool isCmdV1 = FALSE;
+ char *reply = NULL;
+ size_t replyLen;
+ Bool status;
+
+ if (FALSE == isCmdV1) {
+ /* 13 = max size of string representation of an int + 3 spaces. */
+ char request[sizeof GUEST_INFO_COMMAND + 13];
+ GuestNicProto message;
+ XDR xdrs;
+
+ if (DynXdr_Create(&xdrs) == NULL) {
+ return FALSE;
+ }
+
+ /* Add the RPC preamble: message name, and type. */
+ Str_Sprintf(request, sizeof request, "%s %d ",
+ GUEST_INFO_COMMAND, INFO_IPADDRESS_V2);
+
+ message.ver = NIC_INFO_V2;
+ message.GuestNicProto_u.nicsV2 = info;
+
+ /* Write preamble and serialized nic info to XDR stream. */
+ if (!DynXdr_AppendRaw(&xdrs, request, strlen(request)) ||
+ !xdr_GuestNicProto(&xdrs, &message)) {
+ g_warning("Error serializing nic info v2 data.");
+ DynXdr_Destroy(&xdrs, TRUE);
+ return FALSE;
+ }
+
+ status = RpcChannel_Send(ctx->rpc,
+ DynXdr_Get(&xdrs),
+ xdr_getpos(&xdrs),
+ &reply,
+ &replyLen);
+ DynXdr_Destroy(&xdrs, TRUE);
+ if (!status) {
+ g_warning("Failed to send V2 nic info message.\n");
+ }
+
+ if (g_key_file_get_boolean(ctx->config, "guestinfo", "printNicInfo", NULL)) {
+ PrintNicInfo((GuestNicList *) info,
+ (int (*)(const char *fmt, ...)) RpcVMX_Log);
+ }
+ } else {
+ status = FALSE;
+ }
+ if (!status) {
+ /*
+ * Could be that we are talking to the old protocol that GuestNicInfo is
+ * still fixed size. Another try to send the fixed sized Nic info.
+ */
+ char request[sizeof (GuestNicInfoV1) + sizeof GUEST_INFO_COMMAND +
+ 2 + /* 2 bytes are for digits of infotype. */
+ 3 * sizeof (char)]; /* 3 spaces */
+ GuestNicInfoV1 nicInfo;
+
+ vm_free(reply);
+ reply = NULL;
+
+ Str_Sprintf(request,
+ sizeof request,
+ "%s %d ",
+ GUEST_INFO_COMMAND,
+ INFO_IPADDRESS);
+ if (GuestInfoConvertNicInfoToNicInfoV1(info, &nicInfo)) {
+ memcpy(request + strlen(request),
+ &nicInfo,
+ sizeof(GuestNicInfoV1));
+
+ g_debug("Sending nic info message.\n");
+ /* Send all the information in the message. */
+ status = RpcChannel_Send(ctx->rpc,
+ request,
+ sizeof request,
+ &reply,
+ &replyLen);
+
+ g_debug("Just sent fixed sized nic info message.\n");
+ if (!status) {
+ g_debug("Failed to update fixed sized nic information\n");
+ vm_free(reply);
+ return FALSE;
+ }
+ isCmdV1 = TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ g_debug("Updated new NIC information\n");
+ vm_free(reply);
+ reply = NULL;
+ }
+ break;
+
+ case INFO_MEMORY:
+ {
+ char request[sizeof(GuestMemInfo) + sizeof GUEST_INFO_COMMAND +
+ 2 + /* 2 bytes are for digits of infotype. */
+ 3 * sizeof (char)]; /* 3 spaces */
+ Bool status;
+
+ g_debug("Sending GuestMemInfo message.\n");
+ Str_Sprintf(request,
+ sizeof request,
+ "%s %d ",
+ GUEST_INFO_COMMAND,
+ INFO_MEMORY);
+ memcpy(request + strlen(request),
+ info, sizeof(GuestMemInfo));
+
+ /* Send all the information in the message. */
+ status = RpcChannel_Send(ctx->rpc, request, sizeof(request), NULL, NULL);
+ if (!status) {
+ g_warning("Error sending GuestMemInfo.\n");
+ return FALSE;
+ }
+ g_debug("GuestMemInfo sent successfully.\n");
+ break;
+ }
+
+ case INFO_DISK_FREE_SPACE:
+ {
+ /*
+ * 2 accounts for the digits of infotype and 3 for the three
+ * spaces.
+ */
+ unsigned int requestSize = sizeof GUEST_INFO_COMMAND + 2 + 3 * sizeof (char);
+ uint8 partitionCount;
+ size_t offset;
+ char *request;
+ char *reply;
+ size_t replyLen;
+ Bool status;
+ PGuestDiskInfo pdi = (PGuestDiskInfo)info;
+ int j = 0;
+
+ if (!DiskInfoChanged(pdi)) {
+ g_debug("Disk info not changed.\n");
+ break;
+ }
+
+ requestSize += sizeof pdi->numEntries +
+ sizeof *pdi->partitionList * pdi->numEntries;
+ request = (char *)calloc(requestSize, sizeof (char));
+ if (request == NULL) {
+ g_warning("Could not allocate memory for request.\n");
+ break;
+ }
+
+ Str_Sprintf(request, requestSize, "%s %d ", GUEST_INFO_COMMAND,
+ INFO_DISK_FREE_SPACE);
+
+ /* partitionCount is a uint8 and cannot be larger than UCHAR_MAX. */
+ if (pdi->numEntries > UCHAR_MAX) {
+ g_warning("Too many partitions.\n");
+ vm_free(request);
+ return FALSE;
+ }
+ partitionCount = pdi->numEntries;
+
+ offset = strlen(request);
+
+ /*
+ * Construct the disk information message to send to the host. This
+ * contains a single byte indicating the number partitions followed by
+ * the PartitionEntry structure for each one.
+ *
+ * Note that the use of a uint8 to specify the partitionCount is the
+ * result of a bug (see bug 117224) but should not cause a problem
+ * since UCHAR_MAX is 255. Also note that PartitionEntry is packed so
+ * it's safe to send it from 64-bit Tools to a 32-bit VMX, etc.
+ */
+ memcpy(request + offset, &partitionCount, sizeof partitionCount);
+ memcpy(request + offset + sizeof partitionCount, pdi->partitionList,
+ sizeof *pdi->partitionList * pdi->numEntries);
+
+ g_debug("sizeof request is %d\n", requestSize);
+ status = RpcChannel_Send(ctx->rpc, request, requestSize, &reply, &replyLen);
+
+ if (!status || (strncmp(reply, "", 1) != 0)) {
+ g_warning("Failed to update disk information.\n");
+ vm_free(request);
+ vm_free(reply);
+ return FALSE;
+ }
+
+ g_debug("Updated disk info information\n");
+ vm_free(reply);
+ vm_free(request);
+
+ /* Free any memory previously allocated in the cache. */
+ if (gInfoCache.diskInfo.partitionList != NULL) {
+ vm_free(gInfoCache.diskInfo.partitionList);
+ gInfoCache.diskInfo.partitionList = NULL;
+ }
+ gInfoCache.diskInfo.numEntries = pdi->numEntries;
+ gInfoCache.diskInfo.partitionList = calloc(pdi->numEntries,
+ sizeof(PartitionEntry));
+ if (gInfoCache.diskInfo.partitionList == NULL) {
+ g_warning("Could not allocate memory for the disk info cache.\n");
+ return FALSE;
+ }
+
+ for (j = 0; j < pdi->numEntries; j++) {
+ gInfoCache.diskInfo.partitionList[j] = pdi->partitionList[j];
+ }
+ break;
+ }
+ default:
+ g_error("Invalid info type: %d\n", infoType);
+ break;
+ }
+
+ g_debug("Returning after updating guest information\n");
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SetGuestInfo --
+ *
+ * Ask Vmx to write some information about the guest into VMDB.
+ *
+ * Results:
+ *
+ * TRUE/FALSE depending on whether the RPCI succeeded or failed.
+ *
+ * Side effects:
+ *
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Bool
+SetGuestInfo(ToolsAppCtx *ctx, // IN: application context
+ GuestInfoType key, // IN: the VMDB key to set
+ const char *value, // IN:
+ char delimiter) // IN: delimiting character for the rpc
+ // message. 0 indicates default.
+{
+ Bool status;
+ char *reply;
+ gchar *msg;
+ size_t replyLen;
+
+ ASSERT(key);
+ ASSERT(value);
+
+ if (!delimiter) {
+ delimiter = GUESTINFO_DEFAULT_DELIMITER;
+ }
+
+ msg = g_strdup_printf("%s %c%d%c%s", GUEST_INFO_COMMAND,
+ delimiter, key, delimiter, value);
+
+ status = RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, &reply, &replyLen);
+ g_free(msg);
+
+ if (!status) {
+ g_warning("Error sending rpc message: %s\n", reply ? reply : "NULL");
+ vm_free(reply);
+ return FALSE;
+ }
+
+ /* The reply indicates whether the key,value pair was updated in VMDB. */
+ status = (strncmp(reply, "", 1) == 0);
+ vm_free(reply);
+ return status;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * GuestInfoFindMacAddress --
+ *
+ * Locates a NIC with the given MAC address in the NIC list.
+ *
+ * Return value:
+ * If there is an entry in nicInfo which corresponds to this MAC address,
+ * it is returned. If not NULL is returned.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+GuestNic *
+GuestInfoFindMacAddress(GuestNicList *nicInfo, // IN/OUT
+ const char *macAddress) // IN
+{
+ u_int i;
+
+ for (i = 0; i < nicInfo->nics.nics_len; i++) {
+ GuestNic *nic = &nicInfo->nics.nics_val[i];
+ if (strncmp(nic->macAddress, macAddress, NICINFO_MAC_LEN) == 0) {
+ return nic;
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * NicInfoChanged --
+ *
+ * Checks whether Nic information just obtained is different from
+ * the information last sent to VMDB.
+ *
+ * Results:
+ *
+ * TRUE if the NIC info has changed, FALSE otherwise
+ *
+ * Side effects:
+ *
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Bool
+NicInfoChanged(GuestNicList *nicInfo) // IN
+{
+ u_int i;
+ GuestNicList *cachedNicInfo = &gInfoCache.nicInfo;
+
+ if (cachedNicInfo->nics.nics_len != nicInfo->nics.nics_len) {
+ g_debug("Number of nics has changed\n");
+ return TRUE;
+ }
+
+ for (i = 0; i < cachedNicInfo->nics.nics_len; i++) {
+ u_int j;
+ GuestNic *cachedNic = &cachedNicInfo->nics.nics_val[i];
+ GuestNic *matchedNic;
+
+ /* Find the corresponding nic in the new nic info. */
+ matchedNic = GuestInfoFindMacAddress(nicInfo, cachedNic->macAddress);
+
+ if (NULL == matchedNic) {
+ /* This mac address has been deleted. */
+ return TRUE;
+ }
+
+ if (matchedNic->ips.ips_len != cachedNic->ips.ips_len) {
+ g_debug("Count of ip addresses for mac %d\n",
+ matchedNic->ips.ips_len);
+ return TRUE;
+ }
+
+ /* Which IP addresses have been modified for this NIC? */
+ for (j = 0; j < cachedNic->ips.ips_len; j++) {
+ VmIpAddress *cachedIp = &cachedNic->ips.ips_val[j];
+ Bool foundIP = FALSE;
+ u_int k;
+
+ for (k = 0; k < matchedNic->ips.ips_len; k++) {
+ VmIpAddress *matchedIp = &matchedNic->ips.ips_val[k];
+ if (0 == strncmp(cachedIp->ipAddress,
+ matchedIp->ipAddress,
+ NICINFO_MAX_IP_LEN)) {
+ foundIP = TRUE;
+ break;
+ }
+ }
+
+ if (FALSE == foundIP) {
+ /* This ip address couldn't be found and has been modified. */
+ g_debug("MAC address %s, ipaddress %s deleted\n",
+ cachedNic->macAddress,
+ cachedIp->ipAddress);
+ return TRUE;
+ }
+
+ }
+
+ }
+
+ return FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * PrintNicInfo --
+ *
+ * Print NIC info struct using the specified print function.
+ *
+ * Results:
+ * Sum of return values of print function (for printf, this will be the
+ * number of characters printed).
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+PrintNicInfo(GuestNicList *nicInfo, // IN
+ int (*PrintFunc)(const char *, ...)) // IN
+{
+ int ret = 0;
+ u_int i = 0;
+
+ ret += PrintFunc("NicInfo: count: %ud\n", nicInfo->nics.nics_len);
+ for (i = 0; i < nicInfo->nics.nics_len; i++) {
+ u_int j;
+ GuestNic *nic = &nicInfo->nics.nics_val[i];
+
+ ret += PrintFunc("NicInfo: nic [%d/%d] mac: %s",
+ i+1,
+ nicInfo->nics.nics_len,
+ nic->macAddress);
+
+ for (j = 0; j < nic->ips.ips_len; j++) {
+ VmIpAddress *ipAddress = &nic->ips.ips_val[j];
+
+ ret += PrintFunc("NicInfo: nic [%d/%d] IP [%d/%d]: %s",
+ i+1,
+ nicInfo->nics.nics_len,
+ j+1,
+ nic->ips.ips_len,
+ ipAddress->ipAddress);
+ }
+ }
+
+ return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DiskInfoChanged --
+ *
+ * Checks whether disk info information just obtained is different from
+ * the information last sent to VMDB.
+ *
+ * Results:
+ *
+ * TRUE if the disk info has changed, FALSE otherwise.
+ *
+ * Side effects:
+ *
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Bool
+DiskInfoChanged(PGuestDiskInfo diskInfo) // IN:
+{
+ int index;
+ char *name;
+ int i;
+ int matchedPartition;
+ PGuestDiskInfo cachedDiskInfo;
+
+ cachedDiskInfo = &gInfoCache.diskInfo;
+
+ if (cachedDiskInfo->numEntries != diskInfo->numEntries) {
+ g_debug("Number of disks has changed\n");
+ return TRUE;
+ }
+
+ /* Have any disks been modified? */
+ for (index = 0; index < cachedDiskInfo->numEntries; index++) {
+ name = cachedDiskInfo->partitionList[index].name;
+
+ /* Find the corresponding partition in the new partition info. */
+ for (i = 0; i < diskInfo->numEntries; i++) {
+ if (!strncmp(diskInfo->partitionList[i].name, name, PARTITION_NAME_SIZE)) {
+ break;
+ }
+ }
+
+ matchedPartition = i;
+ if (matchedPartition == diskInfo->numEntries) {
+ /* This partition has been deleted. */
+ g_debug("Partition %s deleted\n", name);
+ return TRUE;
+ } else {
+ /* Compare the free space. */
+ if (diskInfo->partitionList[matchedPartition].freeBytes !=
+ cachedDiskInfo->partitionList[index].freeBytes) {
+ g_debug("Free space changed\n");
+ return TRUE;
+ }
+ if (diskInfo->partitionList[matchedPartition].totalBytes !=
+ cachedDiskInfo->partitionList[index].totalBytes) {
+ g_debug("Total space changed\n");
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GuestInfoClearCache --
+ *
+ * Clears the cached guest info data.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * gInfoCache is cleared.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GuestInfoClearCache(void)
+{
+ int i;
+
+ for (i = 0; i < INFO_MAX; i++) {
+ gInfoCache.value[i][0] = 0;
+ }
+
+ VMX_XDR_FREE(xdr_GuestNicList, &gInfoCache.nicInfo);
+ memset(&gInfoCache.nicInfo, 0, sizeof gInfoCache.nicInfo);
+}
+
+
+/**
+ * Plugin entry point. Initializes internal plugin state.
+ *
+ * @param[in] ctx The app context.
+ *
+ * @return The registration data.
+ */
+
+TOOLS_MODULE_EXPORT ToolsPluginData *
+ToolsOnLoad(ToolsAppCtx *ctx)
+{
+ static ToolsPluginData regData = {
+ "guestInfo",
+ NULL,
+ NULL
+ };
+
+ GSource *src;
+
+ ToolsPluginSignalCb sigs[] = {
+ { TOOLS_CORE_SIG_CAPABILITIES, GuestInfoServerSendUptime, NULL },
+ { TOOLS_CORE_SIG_RESET, GuestInfoServerReset, NULL },
+ { TOOLS_CORE_SIG_SET_OPTION, GuestInfoServerSetOption, NULL },
+ { TOOLS_CORE_SIG_SHUTDOWN, GuestInfoServerShutdown, NULL }
+ };
+ ToolsAppReg regs[] = {
+ { TOOLS_APP_SIGNALS, VMTools_WrapArray(sigs, sizeof *sigs, ARRAYSIZE(sigs)) }
+ };
+
+ regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs));
+
+ memset(&gInfoCache, 0, sizeof gInfoCache);
+ vmResumed = FALSE;
+
+ gDisableQueryDiskInfo = g_key_file_get_boolean(ctx->config,
+ "guestinfo",
+ CONFNAME_DISABLEQUERYDISKINFO,
+ NULL);
+
+ /* Add the first timer event. */
+ src = g_timeout_source_new(GUESTINFO_TIME_INTERVAL_MSEC * 10);
+ VMTOOLSAPP_ATTACH_SOURCE(ctx, src, GuestInfoGather, ctx, NULL);
+ g_source_unref(src);
+
+ return ®Data;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * This file gathers the virtual memory stats from Linux guest to be
+ * passed on to the vmx.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <string.h>
+
+#include "vmware.h"
+#include "guestInfo.h"
+#include "strutil.h"
+#include "debug.h"
+
+#ifndef NO_PROCPS
+#include "vm_procps.h"
+static void GuestInfoMonitorGetStat(GuestMemInfo *vmStats);
+static Bool GuestInfoMonitorReadMeminfo(GuestMemInfo *vmStats);
+#endif
+
+#define LINUX_MEMINFO_FLAGS (MEMINFO_MEMTOTAL | MEMINFO_MEMFREE | MEMINFO_MEMBUFF |\
+ MEMINFO_MEMCACHE | MEMINFO_MEMACTIVE | MEMINFO_MEMINACTIVE |\
+ MEMINFO_SWAPINRATE | MEMINFO_SWAPOUTRATE |\
+ MEMINFO_IOINRATE | MEMINFO_IOOUTRATE)
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GuestInfo_PerfMon --
+ *
+ * Gather performance stats.
+ *
+ * Results:
+ * Gathered stats. Returns FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Bool
+GuestInfo_PerfMon(GuestMemInfo *vmStats) // OUT: filled vmstats
+{
+#ifndef NO_PROCPS
+ ASSERT(vmStats);
+ GuestInfoMonitorGetStat(vmStats);
+ if (GuestInfoMonitorReadMeminfo(vmStats)) {
+ vmStats->flags = LINUX_MEMINFO_FLAGS;
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+
+#ifndef NO_PROCPS
+/*
+ *----------------------------------------------------------------------
+ *
+ * GuestInfoMonitorGetStat --
+ *
+ * Calls getstat() to gather memory stats.
+ *
+ * Results:
+ * Gathered stats in vmStats.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GuestInfoMonitorGetStat(GuestMemInfo *vmStats) // OUT: filled vmstats
+{
+ uint32 hz = Hertz;
+ uint32 dummy;
+ jiff cpuUse[2];
+ jiff cpuNic[2];
+ jiff cpuSys[2];
+ jiff cpuIdl[2];
+ jiff cpuIow[2];
+ jiff cpuXxx[2];
+ jiff cpuYyy[2];
+ jiff cpuZzz[2];
+ jiff cpuTotal;
+ jiff cpuHalf;
+ unsigned long pageIn[2];
+ unsigned long pageOut[2];
+ unsigned long swapIn[2];
+ unsigned long swapOut[2];
+ unsigned int dummy2[2];
+ unsigned long kb_per_page = sysconf(_SC_PAGESIZE) / 1024ul;
+
+ meminfo();
+ getstat(cpuUse, cpuNic, cpuSys, cpuIdl, cpuIow, cpuXxx, cpuYyy, cpuZzz,
+ pageIn, pageOut, swapIn, swapOut, dummy2, dummy2, &dummy, &dummy,
+ &dummy, &dummy);
+
+ cpuTotal = *cpuUse + *cpuNic + *cpuSys + *cpuXxx +
+ *cpuYyy + *cpuIdl + *cpuIow + *cpuZzz;
+ cpuHalf = cpuTotal / 2UL;
+
+ vmStats->memFree = kb_main_free;
+ vmStats->memBuff = kb_main_buffers;
+ vmStats->memCache = kb_main_cached,
+ vmStats->memInactive = kb_inactive;
+ vmStats->memActive = kb_active;
+
+ vmStats->swapInRate = (uint64)((*swapIn * kb_per_page * hz + cpuHalf) / cpuTotal);
+ vmStats->swapOutRate = (uint64)((*swapOut * kb_per_page * hz + cpuHalf) / cpuTotal);
+ vmStats->ioInRate = (uint64)((*pageIn * kb_per_page * hz + cpuHalf) / cpuTotal);
+ vmStats->ioOutRate = (uint64)((*pageOut * kb_per_page * hz + cpuHalf) / cpuTotal);
+
+
+ Debug("GuestInfoMonitorGetStat: GuestMemInfo: total: %"FMT64"u free: %"FMT64"u"\
+ "buff: %"FMT64"u cache: %"FMT64"u swapin: %"FMT64"u swapout: %"FMT64"u ioin:"\
+ "%"FMT64"u ioout: %"FMT64"u inactive: %"FMT64"u active: %"FMT64"u"\
+ "hugetotal: %"FMT64"u hugefree: %"FMT64"u\n", vmStats->memTotal,
+ vmStats->memFree, vmStats->memBuff, vmStats->memCache, vmStats->swapInRate,
+ vmStats->swapOutRate, vmStats->ioInRate, vmStats->ioOutRate,
+ vmStats->memInactive, vmStats->memActive, vmStats->hugePagesTotal,
+ vmStats->hugePagesFree);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GuestInfoMonitorReadMeminfo --
+ *
+ * Reads /proc/meminfo to gather phsycial memory and huge page stats.
+ *
+ * Results:
+ * Read /proc/meminfo for total physical memory and huge pages info.
+ * Returns FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Bool
+GuestInfoMonitorReadMeminfo(GuestMemInfo *vmStats) // OUT: filled vmstats
+{
+ char buf[512];
+ uint64 value;
+ FILE *fp;
+
+ /* Get the total memory, and huge page info from /proc/meminfo. */
+ fp = fopen("/proc/meminfo", "r");
+ if (!fp) {
+ Log("GuestInfoMonitorReadMeminfo: Error opening /proc/meminfo.\n");
+ return FALSE;
+ }
+
+ while(!feof(fp)) {
+ if (fscanf(fp, "%s %"FMT64"u", buf, &value) != 2) {
+ continue;
+ }
+ if (StrUtil_StartsWith(buf, "MemTotal")) {
+ vmStats->memTotal = value;
+ }
+ if (StrUtil_StartsWith(buf, "HugePages_Total")) {
+ vmStats->hugePagesTotal = value;
+ vmStats->flags |= MEMINFO_HUGEPAGESTOTAL;
+ }
+ if (StrUtil_StartsWith(buf, "HugePages_Free")) {
+ vmStats->hugePagesFree = value;
+ vmStats->flags |= MEMINFO_HUGEPAGESFREE;
+ }
+ }
+ fclose(fp);
+
+ Debug("GuestInfoMonitorReadMeminfo: GuestMemInfo: total: %"FMT64"u free: %"FMT64"u"\
+ "buff: %"FMT64"u cache: %"FMT64"u swapin: %"FMT64"u swapout: %"FMT64"u ioin:"\
+ "%"FMT64"u ioout: %"FMT64"u inactive: %"FMT64"u active: %"FMT64"u"\
+ "hugetotal: %"FMT64"u hugefree: %"FMT64"u\n", vmStats->memTotal,
+ vmStats->memFree, vmStats->memBuff, vmStats->memCache, vmStats->swapInRate,
+ vmStats->swapOutRate, vmStats->ioInRate, vmStats->ioOutRate,
+ vmStats->memInactive, vmStats->memActive, vmStats->hugePagesTotal,
+ vmStats->hugePagesFree);
+
+ return TRUE;
+}
+#endif
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libhgfsServer.la
+
+libhgfsServer_la_CPPFLAGS =
+libhgfsServer_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
+
+libhgfsServer_la_LDFLAGS =
+libhgfsServer_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libhgfsServer_la_LIBADD =
+libhgfsServer_la_LIBADD += @VMTOOLS_LIBS@
+libhgfsServer_la_LIBADD += $(top_builddir)/lib/hgfsServer/libHgfsServer.la
+libhgfsServer_la_LIBADD += $(top_builddir)/lib/hgfsServerPolicyGuest/libHgfsServerPolicyGuest.la
+
+libhgfsServer_la_SOURCES =
+libhgfsServer_la_SOURCES += hgfsPlugin.c
+
+install-exec-local:
+ mkdir -p $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+ cp -L $(builddir)/.libs/libhgfsServer.so $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+if HAVE_X11
+ mkdir -p $(DESTDIR)$(VMUSR_PLUGIN_INSTALLDIR)
+ cp -L $(builddir)/.libs/libhgfsServer.so $(DESTDIR)$(VMUSR_PLUGIN_INSTALLDIR)
+endif
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file hgfsPlugin.c
+ *
+ * Functionality to utilize the hgfs server in bora/lib as a tools plugin.
+ */
+
+#include <string.h>
+
+#define G_LOG_DOMAIN "hgfsd"
+#include "vmtoolsApp.h"
+
+#include "hgfs.h"
+#include "hgfsServerPolicy.h"
+#include "hgfsServer.h"
+#include "hgfsServerManager.h"
+#include "vm_app.h"
+#include "vm_assert.h"
+#include "vmtools.h"
+
+#if !defined(__APPLE__)
+#include "embed_version.h"
+#include "vmtoolsd_version.h"
+VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
+#endif
+
+
+/**
+ * Handles hgfs requests.
+ *
+ * @param[in] data RPC request data.
+ *
+ * @return TRUE on success, FALSE on error.
+ */
+
+static Bool
+HgfsServerRpcInDispatch(RpcInData *data)
+{
+ size_t packetSize;
+ static char packet[HGFS_LARGE_PACKET_MAX];
+
+
+ ASSERT(data->clientData == NULL);
+
+ if (data->argsSize == 0) {
+ return RPCIN_SETRETVALS(data, "1 argument required", FALSE);
+ }
+
+ packetSize = data->argsSize - 1;
+ HgfsServer_DispatchPacket(data->args + 1, packet, &packetSize);
+
+ data->result = packet;
+ data->resultLen = packetSize;
+ return TRUE;
+}
+
+
+/**
+ * Sends the HGFS capability to the VMX.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The app context.
+ * @param[in] set Whether setting or unsetting the capability.
+ * @param[in] data Unused.
+ *
+ * @return NULL. The function sends the capability directly.
+ */
+
+static GArray *
+HgfsServerCapReg(gpointer src,
+ ToolsAppCtx *ctx,
+ gboolean set,
+ gpointer data)
+{
+ gchar *msg;
+ const char *appName = NULL;
+
+ if (strcmp(ctx->name, VMTOOLS_GUEST_SERVICE) == 0) {
+ appName = TOOLS_DAEMON_NAME;
+ } else if (strcmp(ctx->name, VMTOOLS_USER_SERVICE) == 0) {
+ appName = TOOLS_DND_NAME;
+ } else {
+ g_error("Shouldn't reach this.\n");
+ }
+
+ msg = g_strdup_printf("tools.capability.hgfs_server %s %d",
+ appName,
+ set ? 1 : 0);
+
+ /*
+ * Prior to WS55, the VMX did not know about the "hgfs_server"
+ * capability. This doesn't mean that the HGFS server wasn't needed, it's
+ * just that the capability was introduced in CS 225439 so that the VMX
+ * could decide which HGFS server to communicate with.
+ *
+ * Long story short, we shouldn't care if this function fails.
+ */
+ if (!RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
+ g_warning("Setting HGFS server capability failed!\n");
+ }
+
+ g_free(msg);
+ return NULL;
+}
+
+
+/**
+ * Returns the registration data for the HGFS server.
+ *
+ * @param[in] ctx The application context.
+ *
+ * @return The registration data.
+ */
+
+TOOLS_MODULE_EXPORT ToolsPluginData *
+ToolsOnLoad(ToolsAppCtx *ctx)
+{
+ static ToolsPluginData regData = {
+ "hgfsServer",
+ NULL,
+ NULL
+ };
+
+ /*
+ * Passing NULL here is safe because the shares maintained by the guest
+ * policy server never change, invalidating the need for an invalidate
+ * function.
+ */
+ if (!HgfsServerPolicy_Init(NULL)) {
+ g_warning("HgfsServerPolicy_Init() failed, aborting HGFS server init.\n");
+ return NULL;
+ }
+
+ if (!HgfsServer_InitState()) {
+ g_warning("HgfsServer_InitState() failed, aborting HGFS server init.\n");
+ HgfsServerPolicy_Cleanup();
+ return NULL;
+ }
+
+ {
+ RpcChannelCallback rpcs[] = {
+ { HGFS_SYNC_REQREP_CMD, HgfsServerRpcInDispatch, NULL, NULL, NULL, 0 }
+ };
+ ToolsPluginSignalCb sigs[] = {
+ { TOOLS_CORE_SIG_CAPABILITIES, HgfsServerCapReg, ®Data }
+ };
+ ToolsAppReg regs[] = {
+ { TOOLS_APP_GUESTRPC, VMTools_WrapArray(rpcs, sizeof *rpcs, ARRAYSIZE(rpcs)) },
+ { TOOLS_APP_SIGNALS, VMTools_WrapArray(sigs, sizeof *sigs, ARRAYSIZE(sigs)) }
+ };
+
+ regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs));
+ }
+
+ return ®Data;
+}
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libpowerOps.la
+
+libpowerOps_la_CPPFLAGS =
+libpowerOps_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
+
+libpowerOps_la_LDFLAGS =
+libpowerOps_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libpowerOps_la_LIBADD =
+libpowerOps_la_LIBADD += @VMTOOLS_LIBS@
+
+libpowerOps_la_SOURCES =
+libpowerOps_la_SOURCES += powerOps.c
+
+install-exec-local:
+ mkdir -p $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+ cp -L $(builddir)/.libs/libpowerOps.so $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file powerOps.c
+ *
+ * Plugin that handles power operation events from the VMX.
+ */
+
+#define G_LOG_DOMAIN "powerops"
+
+#include "vm_assert.h"
+#include "vm_basic_defs.h"
+#include "vmtoolsApp.h"
+
+#include "conf.h"
+#include "procMgr.h"
+#include "system.h"
+#include "vm_app.h"
+#include "vmtools.h"
+
+#if defined(G_PLATFORM_WIN32)
+# define INVALID_PID NULL
+#else
+# define INVALID_PID (GPid) -1
+#endif
+
+#if !defined(__APPLE__)
+#include "embed_version.h"
+#include "vmtoolsd_version.h"
+VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
+#endif
+
+static const char *stateChgConfNames[] = {
+ NULL,
+ CONFNAME_POWEROFFSCRIPT,
+ CONFNAME_POWEROFFSCRIPT,
+ CONFNAME_POWERONSCRIPT,
+ CONFNAME_RESUMESCRIPT,
+ CONFNAME_SUSPENDSCRIPT,
+};
+
+
+/** Internal plugin state. */
+typedef struct PowerOpState {
+ GuestOsState stateChgInProgress;
+ GuestOsState lastFailedStateChg;
+#if defined(G_PLATFORM_WIN32)
+ ProcMgr_AsyncProc *pid;
+#else
+ GPid pid;
+#endif
+ ToolsAppCtx *ctx;
+} PowerOpState;
+
+
+/**
+ * Returns the capabilities of the power ops plugin.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The application context.
+ * @param[in] set Whether capabilities are being set.
+ * @param[in] data Unused.
+ *
+ * @return List of capabilities.
+ */
+
+static GArray *
+PowerOpsCapabilityCb(gpointer src,
+ ToolsAppCtx *ctx,
+ gboolean set,
+ gpointer data)
+{
+ const ToolsAppCapability caps[] = {
+ { TOOLS_CAP_OLD_NOVAL, "statechange", 0, 1 },
+ { TOOLS_CAP_OLD_NOVAL, "softpowerop_retry", 0, 1 },
+ };
+
+ return VMTools_WrapArray(caps, sizeof *caps, ARRAYSIZE(caps));
+}
+
+
+/**
+ * Clean up internal state on shutdown.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx Unused.
+ * @param[in] plugin Plugin registration data.
+ */
+
+static void
+PowerOpsShutdown(gpointer src,
+ ToolsAppCtx *ctx,
+ ToolsPluginData *plugin)
+{
+ PowerOpState *state = plugin->_private;
+ g_free(state);
+}
+
+
+/**
+ * Called when a state change script is done running. Sends the state change
+ * status to the VMX.
+ *
+ * @note This may halt/reboot the VM. Also the VMX may suspend the VM upon
+ * receipt of a positive status.
+ *
+ * @param[in] state Plugin state.
+ * @param[in] success Whether the script was successful.
+ */
+
+static void
+PowerOpsStateChangeDone(PowerOpState *state,
+ gboolean success)
+{
+ gchar *msg;
+
+ g_debug("State change complete, success = %d.\n", success);
+
+ /*
+ * We execute the requested action if the script succeeded, or if the
+ * same action was tried before but didn't finish due to a script failure.
+ * See bug 168568 for discussion.
+ */
+ if (success || state->lastFailedStateChg == state->stateChgInProgress) {
+ success = TRUE;
+ state->lastFailedStateChg = GUESTOS_STATECHANGE_NONE;
+ }
+
+ if (!success) {
+ state->lastFailedStateChg = state->stateChgInProgress;
+ }
+
+ /* Send the status message to the VMX. */
+ msg = g_strdup_printf("tools.os.statechange.status %d %d",
+ success,
+ state->stateChgInProgress);
+ if (!RpcChannel_Send(state->ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
+ g_warning("Unable to send the status RPC.");
+ }
+
+ g_free(msg);
+
+ /* Finally, perform the requested operation. */
+ if (success) {
+ if (state->stateChgInProgress == GUESTOS_STATECHANGE_REBOOT) {
+ g_debug("Initiating reboot.\n");
+ System_Shutdown(TRUE);
+ } else if (state->stateChgInProgress == GUESTOS_STATECHANGE_HALT) {
+ g_debug("Initiating halt.\n");
+ System_Shutdown(FALSE);
+ }
+ }
+
+ state->stateChgInProgress = GUESTOS_STATECHANGE_NONE;
+}
+
+
+#if defined(G_PLATFORM_WIN32)
+/**
+ * Callback for when the script process finishes on Win32 systems.
+ *
+ * @param[in] _state Plugin state.
+ *
+ * @return TRUE if the process is not finished yet.
+ */
+
+static gboolean
+PowerOpsScriptCallback(gpointer _state)
+{
+ PowerOpState *state = _state;
+
+ g_assert(state->pid != INVALID_PID);
+
+ if (!ProcMgr_IsAsyncProcRunning(state->pid)) {
+ int exitcode;
+ gboolean success;
+
+ success = (ProcMgr_GetExitCode(state->pid, &exitcode) == 0 &&
+ exitcode == 0);
+ g_debug("Script exit code: %d, success = %d\n", exitcode, success);
+ PowerOpsStateChangeDone(state, success);
+ ProcMgr_Free(state->pid);
+ state->pid = INVALID_PID;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
+ * Starts a process using the ProcMgr library. For some reason the glib
+ * spawn functions are a pain to use under Windows, and ProcMgr works
+ * fine since we can use the "selectable" handle to monitor the child
+ * process.
+ *
+ * XXX: as soon as I figure out what's wrong with the "gspawn-win32-helper"
+ * process and why it's not working, this should probably be merged with the
+ * POSIX code below.
+ *
+ * @param[in] state Plugin state.
+ * @param[in] script Path to the script to be run.
+ *
+ * @return Whether started the process successfully.
+ */
+
+static gboolean
+PowerOpsRunScript(PowerOpState *state,
+ gchar *script)
+{
+ gchar *quoted = NULL;
+ ProcMgr_ProcArgs procArgs;
+
+ /*
+ * Pass the CREATE_NO_WINDOW flag to CreateProcess so that the
+ * cmd.exe window will not be visible to the user in the guest.
+ */
+ memset(&procArgs, 0, sizeof procArgs);
+ procArgs.bInheritHandles = TRUE;
+ procArgs.dwCreationFlags = CREATE_NO_WINDOW;
+
+ /* Quote the path if it's not yet quoted. */
+ if (script[0] != '"') {
+ quoted = g_strdup_printf("\"%s\"", script);
+ }
+
+ g_debug("Executing script: %s\n", (quoted != NULL) ? quoted : script);
+ state->pid = ProcMgr_ExecAsync((quoted != NULL) ? quoted : script, &procArgs);
+ g_free(quoted);
+
+ if (state->pid != NULL) {
+ HANDLE h = ProcMgr_GetAsyncProcSelectable(state->pid);
+ GSource *watch = VMTools_NewHandleSource(h);
+ VMTOOLSAPP_ATTACH_SOURCE(state->ctx, watch, PowerOpsScriptCallback, state, NULL);
+ g_source_unref(watch);
+ return TRUE;
+ } else {
+ g_warning("Failed to start script: out of memory?\n");
+ return FALSE;
+ }
+}
+
+#else
+
+/**
+ * Callback for when the script process finishes on POSIX systems.
+ *
+ * @param[in] pid Child pid.
+ * @param[in] status Exit status of script.
+ * @param[in] _state Plugin state.
+ *
+ * @return FALSE.
+ */
+
+static gboolean
+PowerOpsScriptCallback(GPid pid,
+ gint status,
+ gpointer _state)
+{
+ PowerOpState *state = _state;
+
+ g_assert(state->pid != INVALID_PID);
+
+ PowerOpsStateChangeDone(_state, status == 0);
+ g_spawn_close_pid(state->pid);
+ state->pid = INVALID_PID;
+ return FALSE;
+}
+
+
+/**
+ * Starts a process using glib. This works better in the non-Windows case,
+ * since glib provides a nice API for monitoring when a process exits
+ * (instead of having to poll the process every once in a while when using
+ * ProcMgr.)
+ *
+ * @param[in] state Plugin state.
+ * @param[in] script Path to the script to be run.
+ *
+ * @return Whether started the process successfully.
+ */
+
+static gboolean
+PowerOpsRunScript(PowerOpState *state,
+ gchar *script)
+{
+ gchar *argv[2];
+ GSource *watch;
+ GError *err = NULL;
+
+ argv[0] = g_filename_from_utf8(script, -1, NULL, NULL, &err);
+ if (err != NULL) {
+ g_error("Conversion error: %s\n", err->message);
+ }
+ argv[1] = NULL;
+
+ if (!g_spawn_async(NULL,
+ argv,
+ NULL,
+ G_SPAWN_DO_NOT_REAP_CHILD |
+ G_SPAWN_STDOUT_TO_DEV_NULL |
+ G_SPAWN_STDERR_TO_DEV_NULL,
+ NULL,
+ NULL,
+ &state->pid,
+ &err)) {
+ g_warning("Error starting script: %s\n", err->message);
+ g_clear_error(&err);
+ g_free(argv[0]);
+ return FALSE;
+ }
+
+ /* Setup a watch for when the child is done. */
+ watch = g_child_watch_source_new(state->pid);
+ VMTOOLSAPP_ATTACH_SOURCE(state->ctx, watch, PowerOpsScriptCallback, state, NULL);
+ g_source_unref(watch);
+ g_free(argv[0]);
+ return TRUE;
+}
+#endif
+
+
+/**
+ * Handler for commands which invoke state change scripts. Runs the configured
+ * script for the power operation signaled by the host.
+ *
+ * @param[in] data RPC data.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+PowerOpsStateChange(RpcInData *data)
+{
+ size_t i;
+ PowerOpState *state = data->clientData;
+
+ if (state->pid != INVALID_PID) {
+ g_debug("State change already in progress.\n");
+ return RPCIN_SETRETVALS(data, "State change already in progress", FALSE);
+ }
+
+ g_debug("State change: %s\n", data->name);
+
+ for (i = 0; i < ARRAYSIZE(stateChangeCmdTable); i++) {
+ if (strcmp(data->name, stateChangeCmdTable[i].tcloCmd) == 0) {
+ gchar *script;
+ const char *result;
+ Bool ret;
+
+ state->stateChgInProgress = stateChangeCmdTable[i].id;
+
+ script = g_key_file_get_string(state->ctx->config,
+ "powerops",
+ stateChgConfNames[stateChangeCmdTable[i].id],
+ NULL);
+
+ if (script == NULL) {
+ /* Use default script if not set in config file. */
+ char *dfltPath;
+ const char *dfltScript;
+
+ dfltScript = GuestApp_GetDefaultScript(stateChangeCmdTable[i].name);
+ if (dfltScript == NULL) {
+ g_debug("No default script to run for state change %s.\n",
+ stateChangeCmdTable[i].name);
+ PowerOpsStateChangeDone(state, TRUE);
+ return RPCIN_SETRETVALS(data, "", TRUE);
+ }
+ dfltPath = GuestApp_GetInstallPath();
+ g_assert(dfltPath != NULL);
+ script = g_strdup_printf("%s%c%s", dfltPath, DIRSEPC, dfltScript);
+ vm_free(dfltPath);
+ } else if (strlen(script) == 0) {
+ g_debug("No script to run for state change %s.\n",
+ stateChangeCmdTable[i].name);
+ g_free(script);
+ PowerOpsStateChangeDone(state, TRUE);
+ return RPCIN_SETRETVALS(data, "", TRUE);
+ }
+
+ if (PowerOpsRunScript(state, script)) {
+ result = "";
+ ret = TRUE;
+ } else {
+ PowerOpsStateChangeDone(state, FALSE);
+ result = "Error starting script";
+ ret = FALSE;
+ }
+
+ g_free(script);
+ return RPCIN_SETRETVALS(data, result, ret);
+ }
+ }
+
+ g_warning("Invalid state change command.\n");
+ return RPCIN_SETRETVALS(data, "Invalid state change command", FALSE);
+}
+
+
+/**
+ * Plugin entry point. Returns the registration data.
+ *
+ * @param[in] ctx Unused.
+ *
+ * @return The registration data.
+ */
+
+TOOLS_MODULE_EXPORT ToolsPluginData *
+ToolsOnLoad(ToolsAppCtx *ctx)
+{
+ static ToolsPluginData regData = {
+ "powerops",
+ NULL,
+ NULL
+ };
+
+ size_t i;
+ PowerOpState *state;
+
+ ToolsPluginSignalCb sigs[] = {
+ { TOOLS_CORE_SIG_CAPABILITIES, PowerOpsCapabilityCb, NULL },
+ { TOOLS_CORE_SIG_SHUTDOWN, PowerOpsShutdown, ®Data }
+ };
+ ToolsAppReg regs[] = {
+ { TOOLS_APP_GUESTRPC, NULL },
+ { TOOLS_APP_SIGNALS, VMTools_WrapArray(sigs, sizeof *sigs, ARRAYSIZE(sigs)) }
+ };
+
+ state = g_malloc0(sizeof *state);
+ state->ctx = ctx;
+ state->pid = INVALID_PID;
+
+ regs[0].data = g_array_sized_new(FALSE,
+ TRUE,
+ sizeof (RpcChannelCallback),
+ ARRAYSIZE(stateChangeCmdTable));
+
+ for (i = 0; i < ARRAYSIZE(stateChangeCmdTable); i++) {
+ RpcChannelCallback *cb = &g_array_index(regs[0].data, RpcChannelCallback, i);
+ cb->name = stateChangeCmdTable[i].tcloCmd;
+ cb->callback = PowerOpsStateChange;
+ cb->clientData = state;
+ }
+
+ regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs));
+ regData._private = state;
+ return ®Data;
+}
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libresolutionSet.la
+
+libresolutionSet_la_CPPFLAGS =
+libresolutionSet_la_CPPFLAGS += @GTK_CPPFLAGS@
+libresolutionSet_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
+libresolutionSet_la_CPPFLAGS += -DRESOLUTION_X11
+
+libresolutionSet_la_LDFLAGS =
+libresolutionSet_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libresolutionSet_la_LIBADD =
+libresolutionSet_la_LIBADD += @COMMON_XLIBS@
+libresolutionSet_la_LIBADD += @GTK_LIBS@
+libresolutionSet_la_LIBADD += @VMTOOLS_LIBS@
+
+libresolutionSet_la_SOURCES =
+libresolutionSet_la_SOURCES += libvmwarectrl.c
+libresolutionSet_la_SOURCES += resolutionSet.c
+libresolutionSet_la_SOURCES += resolutionX11.c
+
+install-exec-local:
+ mkdir -p $(DESTDIR)$(VMUSR_PLUGIN_INSTALLDIR)
+ cp -L $(builddir)/.libs/libresolutionSet.so $(DESTDIR)$(VMUSR_PLUGIN_INSTALLDIR)
+
--- /dev/null
+/*
+ * Copyright 2006 by VMware, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * libvmwarectrl.c --
+ *
+ * The VMWARE_CTRL client library.
+ */
+
+
+#define NEED_EVENTS
+#define NEED_REPLIES
+#include <X11/Xlibint.h>
+#include "libvmwarectrl.h"
+#include "vmwarectrlproto.h"
+#include <X11/extensions/Xext.h>
+#include <X11/extensions/extutil.h>
+
+
+/*
+ * Static data and functions.
+ */
+
+static XExtensionInfo _vmwarectrl_info_data;
+static XExtensionInfo *vmwarectrl_info = &_vmwarectrl_info_data;
+static char *vmwarectrl_extension_name = VMWARE_CTRL_PROTOCOL_NAME;
+
+#define VMwareCtrlCheckExtension(dpy, i, val) \
+ XextCheckExtension(dpy, i, vmwarectrl_extension_name, val)
+
+static int close_display(Display *dpy, XExtCodes *codes);
+
+static /* const */ XExtensionHooks vmwarectrl_extension_hooks = {
+ NULL, /* create_gc */
+ NULL, /* copy_gc */
+ NULL, /* flush_gc */
+ NULL, /* free_gc */
+ NULL, /* create_font */
+ NULL, /* free_font */
+ close_display, /* close_display */
+ NULL, /* wire_to_event */
+ NULL, /* event_to_wire */
+ NULL, /* error */
+ NULL, /* error_string */
+};
+
+static XEXT_GENERATE_CLOSE_DISPLAY (close_display, vmwarectrl_info)
+
+static XEXT_GENERATE_FIND_DISPLAY (find_display, vmwarectrl_info,
+ vmwarectrl_extension_name,
+ &vmwarectrl_extension_hooks,
+ 0, NULL)
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrl_QueryExtension --
+ *
+ * Standard QueryExtension implementation. Not very interesting for
+ * VMWARE_CTRL as it doesn't define any events or errors.
+ *
+ * Results:
+ * True if information is successfully retrieved. False otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+VMwareCtrl_QueryExtension(Display *dpy, // IN:
+ int *event_basep, // OUT:
+ int *error_basep) // OUT:
+{
+ XExtDisplayInfo *info = find_display(dpy);
+
+ if (XextHasExtension(info)) {
+ *event_basep = info->codes->first_event;
+ *error_basep = info->codes->first_error;
+ return True;
+ } else {
+ return False;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrl_QueryVersion --
+ *
+ * Send the QueryVersion command to the driver and return the results.
+ *
+ * Results:
+ * True if information is successfully retrieved. False otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+VMwareCtrl_QueryVersion(Display *dpy, // IN:
+ int *majorVersion, // OUT:
+ int *minorVersion) // OUT:
+{
+ xVMwareCtrlQueryVersionReply rep;
+ xVMwareCtrlQueryVersionReq *req;
+ XExtDisplayInfo *info = find_display(dpy);
+ Bool ret = False;
+
+ VMwareCtrlCheckExtension(dpy, info, False);
+ LockDisplay(dpy);
+
+ GetReq(VMwareCtrlQueryVersion, req);
+ req->reqType = info->codes->major_opcode;
+ req->VMwareCtrlReqType = X_VMwareCtrlQueryVersion;
+
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ goto exit;
+ }
+ *majorVersion = rep.majorVersion;
+ *minorVersion = rep.minorVersion;
+
+ ret = True;
+
+exit:
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrl_SetRes --
+ *
+ * Send the SetRes command to the driver.
+ *
+ * Results:
+ * True if the resolution was set. False otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+VMwareCtrl_SetRes(Display *dpy, // IN:
+ int screen, // IN:
+ int x, // IN:
+ int y) // IN:
+{
+ xVMwareCtrlSetResReply rep;
+ xVMwareCtrlSetResReq *req;
+ XExtDisplayInfo *info = find_display(dpy);
+ Bool ret = False;
+
+ VMwareCtrlCheckExtension(dpy, info, False);
+ LockDisplay(dpy);
+
+ GetReq(VMwareCtrlSetRes, req);
+ req->reqType = info->codes->major_opcode;
+ req->VMwareCtrlReqType = X_VMwareCtrlSetRes;
+ req->screen = screen;
+ req->x = x;
+ req->y = y;
+
+ if (!_XReply(dpy, (xReply *)&rep,
+ (SIZEOF(xVMwareCtrlSetResReply) - SIZEOF(xReply)) >> 2,
+ xFalse)) {
+ goto exit;
+ }
+
+ ret = True;
+
+exit:
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrl_SetTopology --
+ *
+ * Send the SetTopology command to the driver.
+ *
+ * Solaris 10 uses a different Xinerama standard than expected here. As a
+ * result, topology set is not supported and this function is excluded from
+ * Solaris builds.
+ *
+ * Results:
+ * True if the resolution and xinerama topology were set. False otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#ifndef NO_MULTIMON
+Bool
+VMwareCtrl_SetTopology(Display *dpy, // IN:
+ int screen, // IN:
+ xXineramaScreenInfo extents[], // IN:
+ int number) // IN:
+{
+ xVMwareCtrlSetTopologyReply rep;
+ xVMwareCtrlSetTopologyReq *req;
+ XExtDisplayInfo *info = find_display(dpy);
+ Bool ret = False;
+ long len;
+
+ VMwareCtrlCheckExtension(dpy, info, False);
+ LockDisplay(dpy);
+
+ GetReq(VMwareCtrlSetTopology, req);
+ req->reqType = info->codes->major_opcode;
+ req->VMwareCtrlReqType = X_VMwareCtrlSetTopology;
+ req->screen = screen;
+ req->number = number;
+
+ len = ((long) number) << 1;
+ SetReqLen(req, len, len);
+ len <<= 2;
+ _XSend(dpy, (char *)extents, len);
+
+ if (!_XReply(dpy, (xReply *)&rep,
+ (SIZEOF(xVMwareCtrlSetTopologyReply) - SIZEOF(xReply)) >> 2,
+ xFalse)) {
+ goto exit;
+ }
+
+ ret = True;
+
+exit:
+ UnlockDisplay(dpy);
+ SyncHandle();
+
+ return ret;
+}
+#endif
--- /dev/null
+/*
+ * Copyright 2006 by VMware, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * libvmwarectrl.c --
+ *
+ * The VMWARE_CTRL client library.
+ */
+
+
+#ifndef _LIB_VMWARE_CTRL_H_
+#define _LIB_VMWARE_CTRL_H_
+
+#include <X11/X.h>
+#include <X11/Xmd.h>
+#ifndef NO_MULTIMON
+#include <X11/extensions/panoramiXproto.h>
+#endif
+
+Bool VMwareCtrl_QueryExtension(Display *dpy, int *event_basep, int *error_basep);
+Bool VMwareCtrl_QueryVersion(Display *dpy, int *majorVersion, int *minorVersion);
+Bool VMwareCtrl_SetRes(Display *dpy, int screen, int x, int y);
+#ifndef NO_MULTIMON
+Bool VMwareCtrl_SetTopology(Display *dpy, int screen, xXineramaScreenInfo[], int number);
+#endif
+
+#endif /* _LIB_VMWARE_CTRL_H_ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file resolutionInt.h --
+ *
+ * Internal header file for lib/resolution.
+ */
+
+#ifndef _LIB_RESOLUTIONINT_H_
+#define _LIB_RESOLUTIONINT_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#include "resolution.h"
+#include "vm_app.h"
+
+/*
+ * Data types
+ */
+
+
+/*
+ * Describes internal state of the resolution library. I.e., tracks whether
+ * a capability is supported, enabled, etc.
+ */
+typedef struct {
+ Bool initialized; // TRUE if successfully initialized.
+ Bool canSetResolution; // TRUE if back-end supports Resolution_Set.
+ Bool canSetTopology; // TRUE if back-end supports DisplayTopology_Set.
+} ResolutionInfoType;
+
+
+/*
+ * Describes the size and offset of a display. An array of these
+ * structures describes the entire topology of the guest desktop
+ */
+typedef struct {
+ int x;
+ int y;
+ int width;
+ int height;
+} DisplayTopologyInfo;
+
+
+/*
+ * Global variables
+ */
+
+extern ResolutionInfoType resolutionInfo;
+
+/*
+ * Global functions
+ */
+
+/* Functions defined by back-end. */
+Bool ResolutionBackendInit(InitHandle handle);
+InitHandle ResolutionToolkitInit(void);
+void ResolutionBackendCleanup(void);
+Bool ResolutionSetResolution(uint32 width, uint32 height);
+Bool ResolutionSetTopology(unsigned int ndisplays, DisplayTopologyInfo displays[]);
+
+
+#endif // ifndef _LIB_RESOLUTIONINT_H_
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file resolution.c --
+ *
+ * Set of functions to handle guest screen resizing for vmware-{user,guestd}.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vmware.h"
+#include "vm_app.h"
+#include "debug.h"
+#include "rpcout.h"
+#include "str.h"
+#include "strutil.h"
+
+#include "resolutionInt.h"
+
+#include "vmtools.h"
+#include "vmtoolsApp.h"
+#include "xdrutil.h"
+
+/*
+ * Internal global variables
+ */
+
+/**
+ * Describes current state of the library.
+ */
+ResolutionInfoType resolutionInfo;
+
+/*
+ * Local function prototypes
+ */
+
+static Bool ResolutionResolutionSetCB(RpcInData *data);
+static Bool ResolutionDisplayTopologySetCB(RpcInData *data);
+
+/*
+ * Global function definitions
+ */
+
+/**
+ *
+ * Initialize the guest resolution library.
+ *
+ * @param[in] handle Back-end specific handle, if needed. E.g., in the X11
+ case, this refers to the X11 display handle.
+ * @return TRUE on success, FALSE on failure
+ */
+
+static Bool
+ResolutionInit(InitHandle handle)
+{
+ // Shorter-named convenience alias. I expect this to be optimized out.
+ ResolutionInfoType *resInfo = &resolutionInfo;
+
+ ASSERT(resInfo->initialized == FALSE);
+
+ if (!ResolutionBackendInit(handle)) {
+ return FALSE;
+ }
+
+ resInfo->initialized = TRUE;
+
+ return TRUE;
+}
+
+
+/**
+ *
+ * Shutdown the plugin, free resources, etc.
+ * Resolution_* calls will fail until user next calls ResolutionInit().
+ */
+
+static void
+ResolutionCleanup(void)
+{
+ ResolutionInfoType *resInfo = &resolutionInfo;
+
+ if (!resInfo->initialized) {
+ return;
+ }
+
+ ResolutionBackendCleanup();
+}
+
+
+/**
+ *
+ * Handler for TCLO 'Resolution_Set'.
+ *
+ * Routine unmarshals RPC arguments and passes over to back-end ResolutionSet().
+ *
+ * @param[in] data RPC data
+ * @return TRUE if we can reply, FALSE otherwise.
+ */
+
+static Bool
+ResolutionResolutionSetCB(RpcInData *data)
+{
+ uint32 width = 0 ;
+ uint32 height = 0;
+ unsigned int index = 0;
+ Bool retval = FALSE;
+
+ /* parse the width and height */
+ if (!StrUtil_GetNextUintToken(&width, &index, data->args, " ")) {
+ goto invalid_arguments;
+ }
+ if (!StrUtil_GetNextUintToken(&height, &index, data->args, "")) {
+ goto invalid_arguments;
+ }
+
+ retval = ResolutionSetResolution(width, height);
+
+invalid_arguments:
+ return RPCIN_SETRETVALS(data, retval ? "" : "Invalid arguments", retval);
+}
+
+
+/**
+ *
+ * Handler for TCLO 'DisplayTopology_Set'.
+ *
+ * Routine unmarshals RPC arguments and passes over to back-end TopologySet().
+ *
+ * @param[in] data RPC data
+ * @return TRUE if we can reply, FALSE otherwise.
+ */
+
+static Bool
+ResolutionDisplayTopologySetCB(RpcInData *data)
+{
+ DisplayTopologyInfo *displays = NULL;
+ unsigned int count, i;
+ Bool success = FALSE;
+ const char *p;
+
+ /*
+ * The argument string will look something like:
+ * <count> [ , <x> <y> <w> <h> ] * count.
+ *
+ * e.g.
+ * 3 , 0 0 640 480 , 640 0 800 600 , 0 480 640 480
+ */
+
+ if (sscanf(data->args, "%u", &count) != 1) {
+ return RPCIN_SETRETVALS(data,
+ "Invalid arguments. Expected \"count\"",
+ FALSE);
+ }
+
+ displays = malloc(sizeof *displays * count);
+ if (!displays) {
+ RPCIN_SETRETVALS(data,
+ "Failed to alloc buffer for display info",
+ FALSE);
+ goto out;
+ }
+
+ for (p = data->args, i = 0; i < count; i++) {
+ p = strchr(p, ',');
+ if (!p) {
+ RPCIN_SETRETVALS(data,
+ "Expected comma separated display list",
+ FALSE);
+ goto out;
+ }
+ p++; /* Skip past the , */
+
+ if (sscanf(p, " %d %d %d %d ", &displays[i].x,
+ &displays[i].y, &displays[i].width, &displays[i].height) != 4) {
+ RPCIN_SETRETVALS(data,
+ "Expected x, y, w, h in display entry",
+ FALSE);
+ goto out;
+ }
+ }
+
+ success = ResolutionSetTopology(count, displays);
+
+ RPCIN_SETRETVALS(data, success ? "" : "ResolutionSetTopology failed", success);
+
+out:
+ free(displays);
+ return success;
+}
+
+
+/**
+ * Cleanup internal data on shutdown.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx Unused.
+ * @param[in] data Unused.
+ */
+
+static void
+ResolutionSetShutdown(gpointer src,
+ ToolsAppCtx *ctx,
+ gpointer data)
+{
+ ResolutionCleanup();
+}
+
+
+/**
+ * Sends the resolution_server capability to the VMX.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The app context.
+ * @param[in] plugin Plugin registration data.
+ * @param[in] set Whether setting or unsetting the capability.
+ *
+ * @return NULL. The function sends the capability directly.
+ */
+
+static void
+ResolutionServerCapReg(ToolsAppCtx *ctx,
+ gint set)
+{
+ gchar *msg;
+ const char *appName = NULL;
+
+ if (strcmp(ctx->name, VMTOOLS_GUEST_SERVICE) == 0) {
+ appName = TOOLS_DAEMON_NAME;
+ } else if (strcmp(ctx->name, VMTOOLS_USER_SERVICE) == 0) {
+ appName = TOOLS_DND_NAME;
+ } else {
+ NOT_REACHED();
+ }
+
+ msg = g_strdup_printf("tools.capability.resolution_server %s %d",
+ appName,
+ set);
+
+ if (!RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
+ g_warning("Setting resolution_server capability failed!\n");
+ }
+
+ g_free(msg);
+}
+
+
+/**
+ * Returns the list of the plugin's capabilities.
+ *
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The app context.
+ * @param[in] set Whether setting or unsetting the capability.
+ * @param[in] data Unused.
+ *
+ * @return A list of capabilities.
+ */
+
+static GArray *
+ResolutionSetCapabilities(gpointer src,
+ ToolsAppCtx *ctx,
+ gboolean set,
+ gpointer data)
+{
+ enum {
+ RES_SET_IDX = 0,
+ DPY_TOPO_SET_IDX = 1,
+ DPY_GLOBAL_OFFSET_IDX = 2
+ };
+
+ ToolsAppCapability caps[] = {
+ { TOOLS_CAP_OLD, "resolution_set", 0, 0 },
+ { TOOLS_CAP_OLD, "display_topology_set", 0, 0 },
+ { TOOLS_CAP_OLD, "display_global_offset", 0, 0 }
+ };
+
+ ResolutionInfoType *resInfo = &resolutionInfo;
+ int resServerCap = 0;
+
+ if (set) {
+ if (!resInfo->initialized) {
+ return FALSE;
+ }
+
+ if (resInfo->canSetResolution) {
+ caps[RES_SET_IDX].value = 1;
+ resServerCap = 1;
+ }
+
+ if (resInfo->canSetTopology) {
+ caps[DPY_TOPO_SET_IDX].value = 2;
+ caps[DPY_GLOBAL_OFFSET_IDX].value = 1;
+ }
+ }
+
+ ResolutionServerCapReg(ctx, resServerCap);
+
+ return VMTools_WrapArray(caps, sizeof *caps, ARRAYSIZE(caps));
+}
+
+
+/**
+ * Plugin entry point. Initializes internal plugin state.
+ *
+ * @param[in] ctx The app context.
+ *
+ * @return The registration data.
+ */
+
+TOOLS_MODULE_EXPORT ToolsPluginData *
+ToolsOnLoad(ToolsAppCtx *ctx)
+{
+ InitHandle handle;
+
+ static ToolsPluginData regData = {
+ "resolutionSet",
+ NULL,
+ NULL
+ };
+
+ ToolsPluginSignalCb sigs[] = {
+ { TOOLS_CORE_SIG_CAPABILITIES, ResolutionSetCapabilities, ®Data },
+ { TOOLS_CORE_SIG_SHUTDOWN, ResolutionSetShutdown, ®Data }
+ };
+ ToolsAppReg regs[] = {
+ { TOOLS_APP_GUESTRPC, NULL },
+ { TOOLS_APP_SIGNALS, VMTools_WrapArray(sigs, sizeof *sigs, ARRAYSIZE(sigs)) }
+ };
+
+ ResolutionInfoType *resInfo = &resolutionInfo;
+
+ resInfo->initialized = FALSE;
+
+ /*
+ * XXX move to some shared lib or plugin
+ */
+ handle = ResolutionToolkitInit();
+
+ ResolutionInit(handle);
+
+ /*
+ * Add one or both of the callbacks based on capabilities.
+ */
+ if (resInfo->canSetResolution || resInfo->canSetTopology) {
+ int index = 0;
+ RpcChannelCallback rpcs[2];
+
+ memset(rpcs, '\0', sizeof rpcs);
+
+ if (resInfo->canSetResolution) {
+ rpcs[index].name = "Resolution_Set";
+ rpcs[index].callback = ResolutionResolutionSetCB;
+ index++;
+ }
+
+ if (resInfo->canSetTopology) {
+ rpcs[index].name = "DisplayTopology_Set";
+ rpcs[index].callback = ResolutionDisplayTopologySetCB;
+ index++;
+ }
+
+ regs[0].data = VMTools_WrapArray(rpcs, sizeof *rpcs, index);
+ regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs));
+ }
+
+ return ®Data;
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * @file resolutionX11.c
+ *
+ * X11 backend for resolutionSet plugin.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.h>
+#ifndef NO_MULTIMON
+#include <X11/extensions/Xinerama.h>
+#endif
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
+#undef Bool
+
+#include "vmware.h"
+
+#include "resolution.h"
+#include "resolutionInt.h"
+
+#include "debug.h"
+#include "fileIO.h"
+#include "libvmwarectrl.h"
+#include "str.h"
+#include "strutil.h"
+
+#define VMWAREDRV_PATH_64 "/usr/X11R6/lib64/modules/drivers/vmware_drv.o"
+#define VMWAREDRV_PATH "/usr/X11R6/lib/modules/drivers/vmware_drv.o"
+#define VERSION_STRING "VMware Guest X Server"
+
+
+/**
+ * Describes the state of the X11 back-end of lib/resolution.
+ */
+typedef struct {
+ Display *display; // X11 connection / display context
+ Window rootWindow; // points to display's root window
+ Bool canUseVMwareCtrl;
+ // TRUE if VMwareCtrl extension available
+ Bool canUseVMwareCtrlTopologySet;
+ // TRUE if VMwareCtrl extension supports topology set
+} ResolutionInfoX11Type;
+
+
+/*
+ * Global variables
+ */
+
+ResolutionInfoX11Type resolutionInfoX11;
+
+/*
+ * Local function prototypes
+ */
+
+static Bool ResolutionCanSet(void);
+static Bool TopologyCanSet(void);
+static Bool SelectResolution(uint32 width, uint32 height);
+
+
+/*
+ * Global function definitions
+ */
+
+
+/**
+ * X11 back-end initializer. Records caller's X11 display, then determines
+ * which capabilities are available.
+ *
+ * @param[in] handle User's X11 display
+ * @return TRUE on success, FALSE on failure.
+ */
+
+Bool
+ResolutionBackendInit(InitHandle handle)
+{
+ ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
+ ResolutionInfoType *resInfo = &resolutionInfo;
+ int dummy1;
+ int dummy2;
+
+ memset(resInfoX, 0, sizeof *resInfoX);
+
+ resInfoX->display = handle;
+
+ if (resInfoX->display == NULL) {
+ Warning("%s: Called with invalid X display!\n", __func__);
+ return FALSE;
+ }
+
+ resInfoX->display = handle;
+ resInfoX->rootWindow = DefaultRootWindow(resInfoX->display);
+ resInfoX->canUseVMwareCtrl = VMwareCtrl_QueryVersion(resInfoX->display, &dummy1,
+ &dummy2);
+ resInfoX->canUseVMwareCtrlTopologySet = FALSE;
+
+ resInfo->canSetResolution = ResolutionCanSet();
+ resInfo->canSetTopology = TopologyCanSet();
+
+ return TRUE;
+}
+
+
+/**
+ * Stub implementation of ResolutionBackendCleanup for the X11 back-end.
+ */
+
+void
+ResolutionBackendCleanup(void)
+{
+ return;
+}
+
+
+/**
+ * Given a width and height, define a custom resolution (if VMwareCtrl is
+ * available), then issue a change resolution request via XRandR.
+ *
+ * This is called as a result of the Resolution_Set request from the vmx.
+ *
+ * @param[in] width requested width
+ * @param[in] height requested height
+ * @return TRUE if we are able to set to the exact size requested, FALSE otherwise.
+ */
+
+Bool
+ResolutionSetResolution(uint32 width,
+ uint32 height)
+{
+ ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
+ ASSERT(resolutionInfo.canSetResolution);
+
+ if (resInfoX->canUseVMwareCtrl) {
+ /*
+ * If so, use the VMWARE_CTRL extension to provide a custom resolution
+ * which we'll find as an exact match from XRRConfigSizes() (unless
+ * the resolution is too large).
+ *
+ * As such, we don't care if this succeeds or fails, we'll make a best
+ * effort attempt to change resolution anyway.
+ */
+ VMwareCtrl_SetRes(resInfoX->display, DefaultScreen(resInfoX->display),
+ width, height);
+ }
+
+ return SelectResolution(width, height);
+}
+
+
+/**
+ * Employs the Xinerama extension to declare a new display topology.
+ *
+ * @note Solaris 10 uses a different Xinerama standard than expected here. As a
+ * result, topology set is not supported and this function is excluded from
+ * Solaris builds. With Solaris 10 shipping X.org, perhaps we should revisit
+ * this decision.
+ *
+ * @param[in] ndisplays number of elements in topology
+ * @param[in] topology array of display geometries
+ * @return TRUE if operation succeeded, FALSE otherwise.
+ */
+
+Bool
+ResolutionSetTopology(unsigned int ndisplays,
+ DisplayTopologyInfo *topology)
+{
+#ifdef NO_MULTIMON
+ return FALSE;
+#else
+ ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
+ Bool success = FALSE;
+ unsigned int i;
+ xXineramaScreenInfo *displays = NULL;
+ short maxX = 0;
+ short maxY = 0;
+ int minX = 0;
+ int minY = 0;
+
+ ASSERT(resolutionInfo.canSetTopology);
+
+ /*
+ * Allocate xXineramaScreenInfo array & translate from DisplayTopologyInfo.
+ * Iterate over displays looking for minimum, maximum dimensions.
+ * Warn if min isn't at (0,0).
+ * Transform to (0,0).
+ * Call out to VMwareCtrl_SetTopology.
+ * Set new jumbotron resolution.
+ */
+
+ displays = malloc(sizeof *displays * ndisplays);
+ if (!displays) {
+ goto out;
+ }
+
+ for (i = 0; i < ndisplays; i++) {
+ displays[i].x_org = topology[i].x;
+ displays[i].y_org = topology[i].y;
+ displays[i].width = topology[i].width;
+ displays[i].height = topology[i].height;
+
+ maxX = MAX(maxX, displays[i].x_org + displays[i].width);
+ maxY = MAX(maxY, displays[i].y_org + displays[i].height);
+ minX = MIN(minX, displays[i].x_org);
+ minY = MIN(minY, displays[i].y_org);
+ }
+
+ if (minX != 0 || minY != 0) {
+ Warning("The bounding box of the display topology does not have an "
+ "origin of (0,0)\n");
+ }
+
+ /*
+ * Transform the topology so that the bounding box has an origin of (0,0). Since the
+ * host is already supposed to pass a normalized topology, this should not have any
+ * effect.
+ */
+ for (i = 0; i < ndisplays; i++) {
+ displays[i].x_org -= minX;
+ displays[i].y_org -= minY;
+ }
+
+ if (!VMwareCtrl_SetTopology(resInfoX->display, DefaultScreen(resInfoX->display), displays,
+ ndisplays)) {
+ Debug("Failed to set topology in the driver.\n");
+ goto out;
+ }
+
+ if (!SelectResolution(maxX - minX, maxY - minY)) {
+ Debug("Failed to set new resolution.\n");
+ goto out;
+ }
+
+ success = TRUE;
+
+out:
+ free(displays);
+ return success;
+#endif
+}
+
+
+/*
+ * Local function definitions
+ */
+
+
+/**
+ * Is the VMware SVGA driver a high enough version to support resolution
+ * changing? We check by searching the driver binary for a known version
+ * string.
+ *
+ * @return TRUE if the driver version is high enough, FALSE otherwise.
+ */
+
+static Bool
+ResolutionCanSet(void)
+{
+ ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
+ FileIODescriptor fd;
+ FileIOResult res;
+ int64 filePos = 0;
+ Bool keepSearching = TRUE;
+ Bool found = FALSE;
+ char buf[sizeof VERSION_STRING + 10]; // size of VERSION_STRING plus some extra for the version number
+ const char versionString[] = VERSION_STRING;
+ size_t bytesRead;
+ int32 major, minor, level;
+ unsigned int tokPos;
+
+ /* See if the randr X module is loaded */
+ if (!XRRQueryVersion(resInfoX->display, &major, &minor) ) {
+ return FALSE;
+ }
+
+ /* See if the VMWARE_CTRL extension is supported */
+ if (resInfoX->canUseVMwareCtrl) {
+ return TRUE;
+ }
+
+ /*
+ * XXX: This check does not work with XOrg 6.9/7.0 for two reasons: Both
+ * versions now use .so for the driver extension and 7.0 moves the drivers
+ * to a completely different directory. As long as we ship a driver for
+ * 6.9/7.0, we can instead just use the VMWARE_CTRL check.
+ */
+ buf[sizeof buf - 1] = '\0';
+ FileIO_Invalidate(&fd);
+ res = FileIO_Open(&fd, VMWAREDRV_PATH_64, FILEIO_ACCESS_READ, FILEIO_OPEN);
+ if (res != FILEIO_SUCCESS) {
+ res = FileIO_Open(&fd, VMWAREDRV_PATH, FILEIO_ACCESS_READ, FILEIO_OPEN);
+ }
+ if (res == FILEIO_SUCCESS) {
+ /*
+ * One of the opens succeeded, so start searching thru the file.
+ */
+ while (keepSearching) {
+ res = FileIO_Read(&fd, buf, sizeof buf - 1, &bytesRead);
+ if (res != FILEIO_SUCCESS || bytesRead < sizeof buf -1 ) {
+ keepSearching = FALSE;
+ } else {
+ if (Str_Strncmp(versionString, buf, sizeof versionString - 1) == 0) {
+ keepSearching = FALSE;
+ found = TRUE;
+ }
+ }
+ filePos = FileIO_Seek(&fd, filePos+1, FILEIO_SEEK_BEGIN);
+ if (filePos == -1) {
+ keepSearching = FALSE;
+ }
+ }
+ FileIO_Close(&fd);
+ if (found) {
+ /*
+ * We NUL-terminated buf earlier, but Coverity really wants it to
+ * be NUL-terminated after the call to FileIO_Read (because
+ * FileIO_Read doesn't NUL-terminate). So we'll do it again.
+ */
+ buf[sizeof buf - 1] = '\0';
+
+ /*
+ * Try and parse the major, minor and level versions
+ */
+ tokPos = sizeof versionString - 1;
+ if (!StrUtil_GetNextIntToken(&major, &tokPos, buf, ".- ")) {
+ return FALSE;
+ }
+ if (!StrUtil_GetNextIntToken(&minor, &tokPos, buf, ".- ")) {
+ return FALSE;
+ }
+ if (!StrUtil_GetNextIntToken(&level, &tokPos, buf, ".- ")) {
+ return FALSE;
+ }
+
+ return ((major > 10) || (major == 10 && minor >= 11));
+ }
+ }
+ return FALSE;
+}
+
+
+/**
+ * Tests whether or not we can change display topology.
+ *
+ * @return TRUE if we're able to reset topology, otherwise FALSE.
+ * @note resInfoX->canUseVMwareCtrlTopologySet will be set to TRUE on success.
+ */
+
+static Bool
+TopologyCanSet(void)
+{
+ ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
+#ifdef NO_MULTIMON
+ resInfoX->canUseVMwareCtrlTopologySet = FALSE;
+#else
+ int major;
+ int minor;
+
+ if (resInfoX->canUseVMwareCtrl && XineramaQueryVersion(resInfoX->display, &major,
+ &minor)) {
+ /*
+ * We need both a new enough VMWARE_CTRL and Xinerama for this to work.
+ */
+ resInfoX->canUseVMwareCtrlTopologySet = (major > 0) || (major == 0 && minor >= 2);
+ } else {
+ resInfoX->canUseVMwareCtrlTopologySet = FALSE;
+ }
+#endif
+
+ return resInfoX->canUseVMwareCtrlTopologySet;
+}
+
+
+/**
+ * Given a width and height, find the biggest resolution that will "fit".
+ * This is called as a result of the resolution set request from the vmx.
+ *
+ * @param[in] width
+ * @param[in] height
+ * @return TRUE if we are able to set to the exact size requested, FALSE otherwise.
+ */
+
+Bool
+SelectResolution(uint32 width,
+ uint32 height)
+{
+ ResolutionInfoX11Type *resInfoX = &resolutionInfoX11;
+ XRRScreenConfiguration* xrrConfig;
+ XRRScreenSize *xrrSizes;
+ Rotation xrrCurRotation;
+ uint32 xrrNumSizes;
+ uint32 i;
+ uint32 bestFitIndex = 0;
+ uint64 bestFitSize = 0;
+ uint64 potentialSize;
+
+ xrrConfig = XRRGetScreenInfo(resInfoX->display, resInfoX->rootWindow);
+ xrrSizes = XRRConfigSizes(xrrConfig, &xrrNumSizes);
+ XRRConfigCurrentConfiguration(xrrConfig, &xrrCurRotation);
+
+ /*
+ * Iterate thru the list finding the best fit that is still <= in both width
+ * and height.
+ */
+ for (i = 0; i < xrrNumSizes; i++) {
+ potentialSize = xrrSizes[i].width * xrrSizes[i].height;
+ if (xrrSizes[i].width <= width && xrrSizes[i].height <= height &&
+ potentialSize > bestFitSize ) {
+ bestFitSize = potentialSize;
+ bestFitIndex = i;
+ }
+ }
+
+ if (bestFitSize > 0) {
+ Debug("Setting guest resolution to: %dx%d (requested: %d, %d)\n",
+ xrrSizes[bestFitIndex].width, xrrSizes[bestFitIndex].height, width, height);
+ XRRSetScreenConfig(resInfoX->display, xrrConfig, resInfoX->rootWindow,
+ bestFitIndex, xrrCurRotation, GDK_CURRENT_TIME);
+ } else {
+ Debug("Can't find a suitable guest resolution, ignoring request for %dx%d\n",
+ width, height);
+ }
+
+ XRRFreeScreenConfigInfo(xrrConfig);
+ return xrrSizes[bestFitIndex].width == width &&
+ xrrSizes[bestFitIndex].height == height;
+}
+
+/**
+ * Obtain a "handle", which for X11, is a display pointer.
+ *
+ * @note We will have to move this out of the resolution plugin soon, I am
+ * just landing this here now for convenience as I port resolution set over
+ * to the new service architecture.
+ *
+ * @return X server display
+ */
+
+InitHandle
+ResolutionToolkitInit(void)
+{
+ int argc = 1;
+ char *argv[] = {"", NULL};
+ GtkWidget *wnd;
+ Display *display;
+ gtk_init(&argc, (char ***) &argv);
+ wnd = gtk_invisible_new();
+ display = GDK_WINDOW_XDISPLAY(wnd->window);
+ return (InitHandle) display;
+}
--- /dev/null
+/*
+ * Copyright 2006 by VMware, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * vmwarectrl.h --
+ *
+ * The definitions used by the VMWARE_CTRL protocol extension that
+ * allows X clients to communicate with the driver.
+ */
+
+
+#ifndef _VMWARE_CTRL_H_
+#define _VMWARE_CTRL_H_
+
+#define VMWARE_CTRL_PROTOCOL_NAME "VMWARE_CTRL"
+
+#define VMWARE_CTRL_MAJOR_VERSION 0
+#define VMWARE_CTRL_MINOR_VERSION 2
+
+#define X_VMwareCtrlQueryVersion 0
+#define X_VMwareCtrlSetRes 1
+#define X_VMwareCtrlSetTopology 2
+
+#endif /* _VMWARE_CTRL_H_ */
--- /dev/null
+/*
+ * Copyright 2006 by VMware, Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * vmwarectrlproto.h --
+ *
+ * The description of the VMWARE_CTRL protocol extension that
+ * allows X clients to communicate with the driver.
+ */
+
+#ifndef _VMWARE_CTRL_PROTO_H_
+#define _VMWARE_CTRL_PROTO_H_
+
+
+#include <X11/X.h>
+#include "vmwarectrl.h"
+
+
+/*
+ * Requests and Replies
+ */
+
+/* Version 0.1 definitions. */
+
+typedef struct {
+ CARD8 reqType; /* always X_VMwareCtrlReqCode */
+ CARD8 VMwareCtrlReqType; /* always X_VMwareCtrlQueryVersion */
+ CARD16 length B16;
+ CARD32 majorVersion B32;
+ CARD32 minorVersion B32;
+} xVMwareCtrlQueryVersionReq;
+#define sz_xVMwareCtrlQueryVersionReq 12
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ BYTE pad1;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD32 majorVersion B32;
+ CARD32 minorVersion B32;
+ CARD32 pad2 B32;
+ CARD32 pad3 B32;
+ CARD32 pad4 B32;
+ CARD32 pad5 B32;
+} xVMwareCtrlQueryVersionReply;
+#define sz_xVMwareCtrlQueryVersionReply 32
+
+typedef struct {
+ CARD8 reqType; /* always X_VMwareCtrlReqCode */
+ CARD8 VMwareCtrlReqType; /* always X_VMwareCtrlSetRes */
+ CARD16 length B16;
+ CARD32 screen B32;
+ CARD32 x B32;
+ CARD32 y B32;
+} xVMwareCtrlSetResReq;
+#define sz_xVMwareCtrlSetResReq 16
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ BYTE pad1;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD32 screen B32;
+ CARD32 x B32;
+ CARD32 y B32;
+ CARD32 pad2 B32;
+ CARD32 pad3 B32;
+ CARD32 pad4 B32;
+} xVMwareCtrlSetResReply;
+#define sz_xVMwareCtrlSetResReply 32
+
+/* Version 0.2 definitions. */
+
+typedef struct {
+ CARD8 reqType; /* always X_VMwareCtrlReqCode */
+ CARD8 VMwareCtrlReqType; /* always X_VMwareCtrlSetTopology */
+ CARD16 length B16;
+ CARD32 screen B32;
+ CARD32 number B32;
+ CARD32 pad1 B32;
+} xVMwareCtrlSetTopologyReq;
+#define sz_xVMwareCtrlSetTopologyReq 16
+
+typedef struct {
+ BYTE type; /* X_Reply */
+ BYTE pad1;
+ CARD16 sequenceNumber B16;
+ CARD32 length B32;
+ CARD32 screen B32;
+ CARD32 pad2 B32;
+ CARD32 pad3 B32;
+ CARD32 pad4 B32;
+ CARD32 pad5 B32;
+ CARD32 pad6 B32;
+} xVMwareCtrlSetTopologyReply;
+#define sz_xVMwareCtrlSetTopologyReply 32
+
+#endif /* _VMWARE_CTRL_PROTO_H_ */
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libtimeSync.la
+
+libtimeSync_la_CPPFLAGS =
+libtimeSync_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
+
+libtimeSync_la_LDFLAGS =
+libtimeSync_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libtimeSync_la_LIBADD =
+libtimeSync_la_LIBADD += @VMTOOLS_LIBS@
+
+libtimeSync_la_SOURCES =
+libtimeSync_la_SOURCES += timeSync.c
+
+install-exec-local:
+ mkdir -p $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+ cp -L $(builddir)/.libs/libtimeSync.so $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file timeSync.c
+ *
+ * Plugin to handle time synchronization between the guest and host.
+ */
+
+#define G_LOG_DOMAIN "timeSync"
+
+/* sync the time once a minute */
+#define TIME_SYNC_TIME 60000
+/* only PERCENT_CORRECTION percent is corrected everytime */
+#define PERCENT_CORRECTION 50
+
+
+#include "backdoor.h"
+#include "backdoor_def.h"
+#include "conf.h"
+#include "msg.h"
+#include "strutil.h"
+#include "system.h"
+#include "vm_app.h"
+#include "vmtools.h"
+#include "vmtoolsApp.h"
+
+#if !defined(__APPLE__)
+#include "embed_version.h"
+#include "vmtoolsd_version.h"
+VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
+#endif
+
+
+typedef struct TimeSyncData {
+ gboolean slewCorrection;
+ uint32 slewPercentCorrection;
+ gint timeSyncState;
+ uint32 timeSyncPeriod; /* In milliseconds. */
+ GSource *timer;
+} TimeSyncData;
+
+
+/**
+ * Set the guest OS time to the host OS time.
+ *
+ * @param[in] slewCorrection Is clock slewing enabled?
+ * @param[in] syncOnce Is this function called in a loop?
+ * @param[in] _data Time sync data.
+ *
+ * @return TRUE on success.
+ */
+
+static gboolean
+TimeSyncDoSync(Bool slewCorrection,
+ Bool syncOnce,
+ void *_data)
+{
+ Backdoor_proto bp;
+ int64 maxTimeLag;
+ int64 interruptLag;
+ int64 guestSecs;
+ int64 guestUsecs;
+ int64 hostSecs;
+ int64 hostUsecs;
+ int64 diffSecs;
+ int64 diffUsecs;
+ int64 diff;
+ TimeSyncData *data = _data;
+ Bool timeLagCall = FALSE;
+#ifdef VMX86_DEBUG
+ static int64 lastHostSecs = 0;
+ int64 secs1, usecs1;
+ int64 secs2, usecs2;
+
+ System_GetCurrentTime(&secs1, &usecs1);
+#endif
+
+ g_debug("Synchronizing time.\n");
+
+ /*
+ * We need 3 things from the host, and there exist 3 different versions of
+ * the calls (described further below):
+ * 1) host time
+ * 2) maximum time lag allowed (config option), which is a
+ * threshold that keeps the tools from being over eager about
+ * resetting the time when it is only a little bit off.
+ * 3) interrupt lag
+ *
+ * First 2 versions of the call add interrupt lag to the maximum allowed
+ * time lag, where as in the last call it is returned separately.
+ *
+ * Three versions of the call:
+ *
+ * - BDOOR_CMD_GETTIME: suffers from a 136-year overflow problem that
+ * cannot be corrected without breaking backwards compatibility with
+ * older Tools. So, we have the newer BDOOR_CMD_GETTIMEFULL, which is
+ * overflow safe.
+ *
+ * - BDOOR_CMD_GETTIMEFULL: overcomes the problem above.
+ *
+ * - BDOOR_CMD_GETTIMEFULL_WITH_LAG: Both BDOOR_CMD_GETTIMEFULL and
+ * BDOOR_CMD_GETTIME returns max lag limit as interrupt lag + the maximum
+ * allowed time lag. BDOOR_CMD_GETTIMEFULL_WITH_LAG separates these two
+ * values. This is helpful when synchronizing time backwards by slewing
+ * the clock.
+ *
+ * We use BDOOR_CMD_GETTIMEFULL_WITH_LAG first and fall back to
+ * BDOOR_CMD_GETTIMEFULL or BDOOR_CMD_GETTIME.
+ *
+ * Note that BDOOR_CMD_GETTIMEFULL and BDOOR_CMD_GETTIMEFULL_WITH_LAG will
+ * not touch EAX when it succeeds. So we check for errors by comparing EAX to
+ * BDOOR_MAGIC, which was set by the call to Backdoor() prior to touching the
+ * backdoor port.
+ */
+ bp.in.cx.halfs.low = BDOOR_CMD_GETTIMEFULL_WITH_LAG;
+ Backdoor(&bp);
+ if (bp.out.ax.word == BDOOR_MAGIC) {
+ hostSecs = ((uint64)bp.out.si.word << 32) | bp.out.dx.word;
+ interruptLag = bp.out.di.word;
+ timeLagCall = TRUE;
+ g_debug("Using BDOOR_CMD_GETTIMEFULL_WITH_LAG\n");
+ } else {
+ g_debug("BDOOR_CMD_GETTIMEFULL_WITH_LAG not supported by current host, "
+ "attempting BDOOR_CMD_GETTIMEFULL\n");
+ interruptLag = 0;
+ bp.in.cx.halfs.low = BDOOR_CMD_GETTIMEFULL;
+ Backdoor(&bp);
+ if (bp.out.ax.word == BDOOR_MAGIC) {
+ hostSecs = ((uint64)bp.out.si.word << 32) | bp.out.dx.word;
+ } else {
+ g_debug("BDOOR_CMD_GETTIMEFULL not supported by current host, "
+ "attempting BDOOR_CMD_GETTIME\n");
+ bp.in.cx.halfs.low = BDOOR_CMD_GETTIME;
+ Backdoor(&bp);
+ hostSecs = bp.out.ax.word;
+ }
+ }
+ hostUsecs = bp.out.bx.word;
+ maxTimeLag = bp.out.cx.word;
+
+ if (hostSecs <= 0) {
+ g_warning("Invalid host OS time: %"FMT64"d secs, %"FMT64"d usecs.\n\n",
+ hostSecs, hostUsecs);
+ return FALSE;
+ }
+
+ /* Get the guest OS time */
+ if (!System_GetCurrentTime(&guestSecs, &guestUsecs)) {
+ g_warning("Unable to retrieve the guest OS time: %s.\n\n", Msg_ErrString());
+ return FALSE;
+ }
+
+ diffSecs = hostSecs - guestSecs;
+ diffUsecs = hostUsecs - guestUsecs;
+ if (diffUsecs < 0) {
+ diffSecs -= 1;
+ diffUsecs += 1000000U;
+ }
+ diff = diffSecs * 1000000L + diffUsecs;
+
+#ifdef VMX86_DEBUG
+ g_debug("Daemon: Guest clock lost %.6f secs; limit=%.2f; "
+ "%"FMT64"d secs since last update\n",
+ diff / 1000000.0, maxTimeLag / 1000000.0, hostSecs - lastHostSecs);
+ g_debug("Daemon: %d, %d, %"FMT64"d, %"FMT64"d, %"FMT64"d.\n",
+ syncOnce, slewCorrection, diff, maxTimeLag, interruptLag);
+ lastHostSecs = hostSecs;
+#endif
+
+ if (syncOnce) {
+ /*
+ * Non-loop behavior:
+ *
+ * Perform a step correction if:
+ * 1) The guest OS is behind the host OS by more than maxTimeLag + interruptLag.
+ * 2) The guest OS is ahead of the host OS.
+ */
+ if (diff > maxTimeLag + interruptLag) {
+ System_DisableTimeSlew();
+ if (!System_AddToCurrentTime(diffSecs, diffUsecs)) {
+ g_warning("Unable to set the guest OS time: %s.\n\n", Msg_ErrString());
+ return FALSE;
+ }
+ }
+ } else {
+
+ /*
+ * Loop behavior:
+ *
+ * If guest is behind host by more than maxTimeLag + interruptLag
+ * perform a step correction to the guest clock and ask the monitor
+ * to drop its accumulated catchup (interruptLag).
+ *
+ * Otherwise, perform a slew correction. Adjust the guest's clock
+ * rate to be either faster or slower than nominal real time, such
+ * that we expect to correct correctionPercent percent of the error
+ * during this synchronization cycle.
+ */
+
+ if (diff > maxTimeLag + interruptLag) {
+ System_DisableTimeSlew();
+ if (!System_AddToCurrentTime(diffSecs, diffUsecs)) {
+ g_warning("Unable to set the guest OS time: %s.\n\n", Msg_ErrString());
+ return FALSE;
+ }
+ } else if (slewCorrection && timeLagCall) {
+ int64 slewDiff;
+
+ /* Don't consider interruptLag during clock slewing. */
+ slewDiff = diff - interruptLag;
+
+ /* Correct only data->slewPercentCorrection percent error. */
+ slewDiff = (data->slewPercentCorrection * slewDiff) / 100;
+
+ if (!System_EnableTimeSlew(slewDiff, data->timeSyncPeriod)) {
+ g_warning("Unable to slew the guest OS time: %s.\n\n", Msg_ErrString());
+ return FALSE;
+ }
+ } else {
+ System_DisableTimeSlew();
+ }
+ }
+
+#ifdef VMX86_DEBUG
+ System_GetCurrentTime(&secs2, &usecs2);
+
+ g_debug("Time changed from %"FMT64"d.%"FMT64"d -> %"FMT64"d.%"FMT64"d\n",
+ secs1, usecs1, secs2, usecs2);
+#endif
+
+ /*
+ * If we have stepped the time, ask TimeTracker to reset to normal the rate
+ * of timer interrupts it forwards from the host to the guest.
+ */
+ if (!System_IsTimeSlewEnabled()) {
+ bp.in.cx.halfs.low = BDOOR_CMD_STOPCATCHUP;
+ Backdoor(&bp);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * Run the "time synchronization" loop.
+ *
+ * @param[in] _data Time sync data.
+ *
+ * @return TRUE on success.
+ */
+
+static gboolean
+ToolsDaemonTimeSyncLoop(gpointer _data)
+{
+ TimeSyncData *data = _data;
+
+ g_assert(data != NULL);
+
+ if (!TimeSyncDoSync(data->slewCorrection, FALSE, data)) {
+ g_warning("Unable to synchronize time.\n");
+ if (data->timer != NULL) {
+ g_source_unref(data->timer);
+ data->timer = NULL;
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+#if defined(_WIN32)
+/**
+ * Try to disable the Windows Time Daemon.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+TimeSyncDisableWinTimeDaemon(void)
+{
+ DWORD timeAdjustment;
+ DWORD timeIncrement;
+ DWORD error;
+ BOOL timeAdjustmentDisabled;
+ BOOL success = FALSE;
+
+ /*
+ * We need the SE_SYSTEMTIME_NAME privilege to make the change; get
+ * the privilege now (or bail if we can't).
+ */
+ success = System_SetProcessPrivilege(SE_SYSTEMTIME_NAME, TRUE);
+ if (!success) {
+ return FALSE;
+ }
+
+ /* Actually try to stop the time daemon. */
+ if (GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
+ &timeAdjustmentDisabled)) {
+ g_debug("GetSystemTimeAdjustment() succeeded: timeAdjustment %d,"
+ "timeIncrement %d, timeAdjustmentDisabled %s\n",
+ timeAdjustment, timeIncrement,
+ timeAdjustmentDisabled ? "TRUE" : "FALSE");
+ /*
+ * timeAdjustmentDisabled means the opposite of what you'd think;
+ * if it's TRUE, that means the system may be adjusting the time
+ * on its own using the time daemon. Read MSDN for the details,
+ * and see Bug 24173 for more discussion on this.
+ */
+
+ if (timeAdjustmentDisabled) {
+ /*
+ * MSDN is a bit vague on the semantics of this function, but it
+ * would appear that the timeAdjustment value here is simply the
+ * total amount that the system will add to the clock on each
+ * timer tick, i.e. if you set it to zero the system clock will
+ * not progress at all (and indeed, attempting to set it to zero
+ * results in an ERROR_INVALID_PARAMETER). In order to have time
+ * proceed at the normal rate, this needs to be set to the value
+ * of timeIncrement retrieved from GetSystemTimeAdjustment().
+ */
+ if (!SetSystemTimeAdjustment(timeIncrement, FALSE)) {
+ error = GetLastError();
+ g_debug("SetSystemTimeAdjustment failed: %d\n", error);
+ goto exit;
+ }
+ }
+ } else {
+ error = GetLastError();
+ g_debug("GetSystemTimeAdjustment failed: %d\n", error);
+ goto exit;
+ }
+
+ success = TRUE;
+
+ exit:
+ g_debug("Stopping time daemon %s.\n", success ? "succeeded" : "failed");
+ System_SetProcessPrivilege(SE_SYSTEMTIME_NAME, FALSE);
+ return success;
+}
+#endif
+
+
+/**
+ * Start or stop the "time synchronization" loop. Nothing will be done if
+ * start==TRUE & it's already running or start==FALSE & it's not running.
+ *
+ * @param[in] ctx The application context.
+ * @param[in] data Time sync data.
+ * @param[in] start See above.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+TimeSyncStartStopLoop(ToolsAppCtx *ctx,
+ TimeSyncData *data,
+ gboolean start)
+{
+ g_assert(data != NULL);
+
+ if (start && data->timer == NULL) {
+ g_debug("Starting time sync loop.\n");
+ g_debug("New sync period is %d sec.\n", data->timeSyncPeriod / 1000);
+ if (!ToolsDaemonTimeSyncLoop(data)) {
+ return FALSE;
+ }
+ data->timer = g_timeout_source_new(data->timeSyncPeriod);
+ VMTOOLSAPP_ATTACH_SOURCE(ctx, data->timer, ToolsDaemonTimeSyncLoop, data, NULL);
+
+#if defined(_WIN32)
+ g_debug("Daemon: Attempting to disable Windows Time daemon\n");
+ if (!TimeSyncDisableWinTimeDaemon()) {
+ g_debug("Daemon: Failed to disable Windows Time daemon\n");
+ }
+#endif
+
+ return TRUE;
+ } else if (!start && data->timer != NULL) {
+ g_debug("Stopping time sync loop.\n");
+ System_DisableTimeSlew();
+ g_source_destroy(data->timer);
+ data->timer = NULL;
+
+ return TRUE;
+ }
+
+ /*
+ * No need to start time sync b/c it's already running or no
+ * need to stop it b/c it's not running.
+ */
+ return TRUE;
+}
+
+
+/**
+ * Sync the guest's time with the host's.
+ *
+ * @param[in] data RPC request data.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+TimeSyncTcloHandler(RpcInData *data)
+{
+ Bool slewCorrection = !strcmp(data->args, "1");
+ TimeSyncData *syncData = data->clientData;
+
+ if (!TimeSyncDoSync(slewCorrection, TRUE, syncData)) {
+ return RPCIN_SETRETVALS(data, "Unable to sync time", FALSE);
+ } else {
+ return RPCIN_SETRETVALS(data, "", TRUE);
+ }
+}
+
+
+/**
+ * Handles a "Set_Option" callback. Processes the time sync related options.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The app context.
+ * @param[in] option Option being set.
+ * @param[in] value Option value.
+ * @param[in] plugin Plugin registration data.
+ *
+ * @return TRUE on success.
+ */
+
+static gboolean
+TimeSyncSetOption(gpointer src,
+ ToolsAppCtx *ctx,
+ const gchar *option,
+ const gchar *value,
+ ToolsPluginData *plugin)
+{
+ TimeSyncData *data = plugin->_private;
+ if (strcmp(option, TOOLSOPTION_SYNCTIME) == 0) {
+ gboolean start;
+
+ if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
+ return FALSE;
+ }
+ start = (strcmp(value, "1") == 0);
+
+ /*
+ * Try the one-shot time sync if time sync transitions from
+ * 'off' to 'on'.
+ */
+ if (data->timeSyncState == 0 && start &&
+ g_key_file_get_boolean(ctx->config, "timeSync",
+ TOOLSOPTION_SYNCTIME_ENABLE, NULL)) {
+ TimeSyncDoSync(data->slewCorrection, TRUE, data);
+ }
+ data->timeSyncState = start;
+
+ /* Now start/stop the loop. */
+ if (!TimeSyncStartStopLoop(ctx, data, start)) {
+ return FALSE;
+ }
+ } else if (strcmp(option, TOOLSOPTION_SYNCTIME_SLEWCORRECTION) == 0) {
+ data->slewCorrection = strcmp(value, "0");
+ g_debug("Daemon: Setting slewCorrection, %d.\n", data->slewCorrection);
+ } else if (strcmp(option, TOOLSOPTION_SYNCTIME_PERCENTCORRECTION) == 0) {
+ int32 percent;
+ if (!StrUtil_StrToInt(&percent, value)) {
+ return FALSE;
+ }
+ data->slewPercentCorrection = percent;
+ } else if (strcmp(option, TOOLSOPTION_SYNCTIME_PERIOD) == 0) {
+ uint32 period;
+
+ if (!StrUtil_StrToUint(&period, value)) {
+ return FALSE;
+ }
+
+ /*
+ * If the sync loop is running and the time sync period has changed,
+ * restart the loop with the new period value. If the sync loop is
+ * not running, just remember the new sync period value.
+ */
+ if (period != data->timeSyncPeriod) {
+ data->timeSyncPeriod = (period > 0) ? period * 1000 : TIME_SYNC_TIME;
+
+ if (data->timer != NULL) {
+ TimeSyncStartStopLoop(ctx, data, FALSE);
+ if (!TimeSyncStartStopLoop(ctx, data, TRUE)) {
+ g_warning("Unable to change time sync period.\n");
+ return FALSE;
+ }
+ }
+ }
+ } else {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
+ * Handles a shutdown callback; cleans up internal plugin state.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The app context.
+ * @param[in] plugin Plugin registration data.
+ */
+
+static void
+TimeSyncShutdown(gpointer src,
+ ToolsAppCtx *ctx,
+ ToolsPluginData *plugin)
+{
+ TimeSyncData *data = plugin->_private;
+ if (data->timer != NULL) {
+ g_source_destroy(data->timer);
+ }
+ g_free(data);
+}
+
+
+/**
+ * Plugin entry point. Initializes internal state and returns the registration
+ * data.
+ *
+ * @param[in] ctx The app context.
+ *
+ * @return The registration data.
+ */
+
+TOOLS_MODULE_EXPORT ToolsPluginData *
+ToolsOnLoad(ToolsAppCtx *ctx)
+{
+ static ToolsPluginData regData = {
+ "timeSync",
+ NULL,
+ NULL
+ };
+
+ TimeSyncData *data = g_malloc(sizeof (TimeSyncData));
+ RpcChannelCallback rpcs[] = {
+ { "Time_Synchronize", TimeSyncTcloHandler, data, NULL, NULL, 0 }
+ };
+ ToolsPluginSignalCb sigs[] = {
+ { TOOLS_CORE_SIG_SET_OPTION, TimeSyncSetOption, ®Data },
+ { TOOLS_CORE_SIG_SHUTDOWN, TimeSyncShutdown, ®Data }
+ };
+ ToolsAppReg regs[] = {
+ { TOOLS_APP_GUESTRPC, VMTools_WrapArray(rpcs, sizeof *rpcs, ARRAYSIZE(rpcs)) },
+ { TOOLS_APP_SIGNALS, VMTools_WrapArray(sigs, sizeof *sigs, ARRAYSIZE(sigs)) }
+ };
+
+ data->slewCorrection = TRUE;
+ data->slewPercentCorrection = PERCENT_CORRECTION;
+ data->timeSyncState = -1;
+ data->timeSyncPeriod = TIME_SYNC_TIME;
+ data->timer = NULL;
+
+ regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs));
+ regData._private = data;
+
+ return ®Data;
+}
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libvix.la
+
+libvix_la_CPPFLAGS =
+libvix_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
+
+libvix_la_LDFLAGS =
+libvix_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libvix_la_LIBADD =
+libvix_la_LIBADD += @VIX_LIBADD@
+libvix_la_LIBADD += @VMTOOLS_LIBS@
+libvix_la_LIBADD += ../hgfsServer/libhgfsServer.la
+libvix_la_LIBADD += $(top_builddir)/lib/auth/libAuth.la
+libvix_la_LIBADD += $(top_builddir)/lib/foundryMsg/libFoundryMsg.la
+libvix_la_LIBADD += $(top_builddir)/lib/impersonate/libImpersonate.la
+
+libvix_la_SOURCES =
+libvix_la_SOURCES += foundryToolsDaemon.c
+libvix_la_SOURCES += vixPlugin.c
+libvix_la_SOURCES += $(top_srcdir)/lib/vixTools/vixTools.c
+
+install-exec-local:
+ mkdir -p $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+ cp -L $(builddir)/.libs/libvix.so $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+if HAVE_X11
+ mkdir -p $(DESTDIR)$(VMUSR_PLUGIN_INSTALLDIR)
+ cp -L $(builddir)/.libs/libvix.so $(DESTDIR)$(VMUSR_PLUGIN_INSTALLDIR)
+endif
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file vixPlugin.c
+ *
+ * Tools Service entry point for the VIX plugin.
+ */
+
+#define G_LOG_DOMAIN "vix"
+
+#include <string.h>
+
+#include "vmware.h"
+#include "foundryToolsDaemon.h"
+#include "syncDriver.h"
+#include "vixCommands.h"
+#include "vixPluginInt.h"
+#include "vmtools.h"
+
+#if !defined(__APPLE__)
+#include "embed_version.h"
+#include "vmtoolsd_version.h"
+VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
+#endif
+
+
+/**
+ * Returns the registration data for either the guestd or userd process.
+ *
+ * @param[in] ctx The application context.
+ *
+ * @return The registration data.
+ */
+
+TOOLS_MODULE_EXPORT ToolsPluginData *
+ToolsOnLoad(ToolsAppCtx *ctx)
+{
+ static ToolsPluginData regData = {
+ "vix",
+ NULL,
+ NULL
+ };
+
+ RpcChannelCallback rpcs[] = {
+ { VIX_BACKDOORCOMMAND_RUN_PROGRAM,
+ FoundryToolsDaemonRunProgram, NULL, NULL, NULL, 0 },
+ { VIX_BACKDOORCOMMAND_GET_PROPERTIES,
+ FoundryToolsDaemonGetToolsProperties, NULL, NULL, 0 },
+ { VIX_BACKDOORCOMMAND_CHECK_USER_ACCOUNT,
+ ToolsDaemonTcloCheckUserAccount, NULL, NULL, NULL, 0 },
+ { VIX_BACKDOORCOMMAND_SEND_HGFS_PACKET,
+ ToolsDaemonHgfsImpersonated, NULL, NULL, NULL, 0 },
+ { VIX_BACKDOORCOMMAND_COMMAND,
+ ToolsDaemonTcloReceiveVixCommand, NULL, NULL, 0 },
+ { VIX_BACKDOORCOMMAND_MOUNT_VOLUME_LIST,
+ ToolsDaemonTcloMountHGFS, NULL, NULL, NULL, 0 },
+#if defined(_WIN32) || defined(linux)
+ { VIX_BACKDOORCOMMAND_SYNCDRIVER_FREEZE,
+ ToolsDaemonTcloSyncDriverFreeze, NULL, NULL, NULL, 0 },
+ { VIX_BACKDOORCOMMAND_SYNCDRIVER_THAW,
+ ToolsDaemonTcloSyncDriverThaw, NULL, NULL, NULL, 0 }
+#endif
+ };
+ ToolsAppReg regs[] = {
+ { TOOLS_APP_GUESTRPC, VMTools_WrapArray(rpcs, sizeof *rpcs, ARRAYSIZE(rpcs)) }
+ };
+
+ FoundryToolsDaemon_Initialize(ctx);
+ regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs));
+
+ /*
+ * If running the user daemon or if the sync driver is not active, remove
+ * the last two elements of the RPC registration array, so that the sync
+ * driver RPC commands are ignored.
+ */
+#if defined(_WIN32) || defined(linux)
+ if (strcmp(ctx->name, VMTOOLS_GUEST_SERVICE) != 0 || !SyncDriver_Init()) {
+ g_array_remove_range(regs[0].data, regs[0].data->len - 2, 2);
+ }
+#endif
+
+ return ®Data;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _VIXPLUGININT_H_
+#define _VIXPLUGININT_H_
+
+/**
+ * @file vixPluginInt.h
+ *
+ * Prototypes of VIX RPC handlers found in foundryToolsDaemon.c.
+ */
+
+#define Debug g_debug
+#define Warning g_warning
+
+#include "vmtoolsApp.h"
+
+Bool
+ToolsDaemonTcloCheckUserAccount(RpcInData *data);
+
+Bool
+FoundryToolsDaemonGetToolsProperties(RpcInData *data);
+
+Bool
+ToolsDaemonHgfsImpersonated(RpcInData *data);
+
+Bool
+ToolsDaemonTcloMountHGFS(RpcInData *data);
+
+Bool
+ToolsDaemonTcloReceiveVixCommand(RpcInData *data);
+
+Bool
+FoundryToolsDaemonRunProgram(RpcInData *data);
+
+#if defined(linux) || defined(_WIN32)
+Bool
+ToolsDaemonTcloSyncDriverFreeze(RpcInData *data);
+
+Bool
+ToolsDaemonTcloSyncDriverThaw(RpcInData *data);
+#endif
+
+#endif /* _VIXPLUGININT_H_ */
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libvixUser.la
+
+libvixUser_la_CPPFLAGS =
+libvixUser_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
+
+libvixUser_la_LDFLAGS =
+libvixUser_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libvixUser_la_LIBADD =
+libvixUser_la_LIBADD += @VIX_LIBADD@
+libvixUser_la_LIBADD += @COMMON_XLIBS@
+libvixUser_la_LIBADD += @VMTOOLS_LIBS@
+libvixUser_la_LIBADD += $(top_builddir)/lib/foundryMsg/libFoundryMsg.la
+libvixUser_la_LIBADD += $(top_builddir)/lib/guestApp/libGuestAppX11.la
+
+libvixUser_la_SOURCES =
+libvixUser_la_SOURCES += vixUser.c
+
+install-exec-local:
+ mkdir -p $(DESTDIR)$(VMUSR_PLUGIN_INSTALLDIR)
+ cp -L $(builddir)/.libs/libvixUser.so $(DESTDIR)$(VMUSR_PLUGIN_INSTALLDIR)
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file vixUser.c
+ *
+ * Tools Service entry point for the VIX userd plugin.
+ */
+
+#define G_LOG_DOMAIN "vixUser"
+
+#include <string.h>
+
+#include "vmware.h"
+#include "err.h"
+#include "guestApp.h"
+#include "printer.h"
+#include "str.h"
+#include "strutil.h"
+#include "vixCommands.h"
+#include "vixTools.h"
+#include "vmtools.h"
+#include "vmtoolsApp.h"
+#include "util.h"
+
+#if defined(_WIN32)
+# include "win32u.h"
+#endif
+
+#if !defined(__APPLE__)
+#include "embed_version.h"
+#include "vmtoolsd_version.h"
+VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
+#endif
+
+/*
+ * These constants are a bad hack. I really should generate the result
+ * strings twice, once to compute the length and then allocate the buffer,
+ * and a second time to write the buffer. (XXX: From foundryToolsDaemon.c.)
+ */
+#define DEFAULT_RESULT_MSG_MAX_LENGTH 1024
+
+
+/**
+ * Extract a quoted string from the middle of an argument string.
+ * This is different than normal tokenizing in a few ways:
+ * - Whitespace is a separator outside quotes, but not inside quotes.
+ * - Quotes always come in pairs, so "" is am empty string. An empty
+ * string may appear anywhere in the string, even at the end, so
+ * a string that is "" contains 1 empty string, not 2.
+ * - The string may use whitespace to separate the op-name from the params,
+ * and then quoted params to skip whitespace inside a param.
+ *
+ * XXX: this is copied from foundryToolsDaemon.c. It's easier to copy than
+ * to recompile that file and pull in all its dependencies into this plugin.
+ *
+ * @param[in] args
+ * @param[in] engOfArg
+ *
+ * @return An allocated string.
+ */
+
+static char *
+ToolsDaemonTcloGetQuotedString(const char *args,
+ const char **endOfArg)
+{
+ char *resultStr = NULL;
+ char *endStr;
+ g_debug(">ToolsDaemonTcloGetQuotedString\n");
+
+ while ((*args) && ('\"' != *args)) {
+ args++;
+ }
+ if ('\"' == *args) {
+ args++;
+ }
+
+ resultStr = Util_SafeStrdup(args);
+
+ endStr = resultStr;
+ while (*endStr) {
+ if (('\\' == *endStr) && (*(endStr + 1))) {
+ endStr += 2;
+ } else if ('\"' == *endStr) {
+ *endStr = 0;
+ endStr++;
+ break;
+ } else {
+ endStr++;
+ }
+ }
+
+ if (NULL != endOfArg) {
+ args += (endStr - resultStr);
+ while (' ' == *args) {
+ args++;
+ }
+ *endOfArg = args;
+ }
+
+ g_debug("<ToolsDaemonTcloGetQuotedString\n");
+ return resultStr;
+}
+
+
+/**
+ * This is a wrapper for ToolsDaemonTcloGetQuotedString.
+ * It just decodes the string.
+ *
+ * XXX: this is copied from foundryToolsDaemon.c. It's easier to copy than
+ * to recompile that file and pull in all its dependencies into this plugin.
+ *
+ * @param[in] args
+ * @param[in] engOfArg
+ *
+ * @return An allocated string.
+ */
+
+static char *
+ToolsDaemonTcloGetEncodedQuotedString(const char *args,
+ const char **endOfArg)
+{
+ char *rawResultStr = NULL;
+ char *resultStr = NULL;
+
+ rawResultStr = ToolsDaemonTcloGetQuotedString(args, endOfArg);
+ if (NULL == rawResultStr) {
+ return(NULL);
+ }
+
+ resultStr = VixMsg_DecodeString(rawResultStr);
+ free(rawResultStr);
+
+ return resultStr;
+}
+
+
+/**
+ * Handle the command to open a URL in the guest.
+ *
+ * XXX: This code is copied from foundryToolsDaemon.c. The original code
+ * should be cleaned up when the old service code is phased out.
+ *
+ * @param[in] data RPC request data.
+ *
+ * @return TRUE on success, FALSE on failure.
+ */
+
+static Bool
+VixUserOpenUrl(RpcInData *data)
+{
+ static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
+ VixError err = VIX_OK;
+ char *url = NULL;
+ char *windowState = NULL;
+ char *credentialTypeStr = NULL;
+ char *obfuscatedNamePassword = NULL;
+ uint32 sysError = 0;
+ g_debug(">ToolsDaemonTcloOpenUrl\n");
+
+ /*
+ * Parse the arguments
+ */
+ url = ToolsDaemonTcloGetEncodedQuotedString(data->args, &data->args);
+ windowState = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
+ // These parameters at the end are optional, so they may be NULL.
+ credentialTypeStr = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
+ obfuscatedNamePassword = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
+
+ /*
+ * Validate the arguments.
+ */
+ if ((NULL == url) || (NULL == windowState)) {
+ err = VIX_E_INVALID_ARG;
+ g_debug("Failed to get string args\n");
+ goto abort;
+ }
+
+ g_debug("Opening URL: \"%s\"\n", url);
+
+ /* Actually open the URL. */
+ if (!GuestApp_OpenUrl(url, strcmp(windowState, "maximize") == 0)) {
+ err = VIX_E_FAIL;
+ g_debug("Failed to open the url \"%s\"\n", url);
+ goto abort;
+ }
+
+abort:
+ /*
+ * All Foundry tools commands return results that start with a
+ * foundry error and a guest-OS-specific error.
+ */
+ Str_Sprintf(resultBuffer, sizeof resultBuffer, "%"FMT64"d %d", err, sysError);
+ RPCIN_SETRETVALS(data, resultBuffer, TRUE);
+
+ /*
+ * These were allocated by ToolsDaemonTcloGetQuotedString.
+ */
+ free(url);
+ free(windowState);
+ free(credentialTypeStr);
+ free(obfuscatedNamePassword);
+
+ g_debug("<ToolsDaemonTcloOpenUrl\n");
+ return TRUE;
+}
+
+
+/**
+ * Handles the command to set the printer on the guest.
+ *
+ * XXX: This code is copied from foundryToolsDaemon.c. The original code
+ * should be cleaned up when the old service code is phased out.
+ *
+ * @param[in] data RPC request data.
+ *
+ * @return TRUE on success, FALSE on failure.
+ */
+
+static Bool
+VixUserSetPrinter(RpcInData *data)
+{
+ static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
+#if defined(_WIN32)
+ VixError err = VIX_OK;
+ char *printerName = NULL;
+ char *defaultString = NULL;
+ int defaultInt;
+ DWORD sysError = ERROR_SUCCESS;
+ g_debug(">ToolsDaemonTcloSetPrinter\n");
+
+ /*
+ * Parse the arguments
+ */
+ printerName = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
+ defaultString = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
+
+ /*
+ * Validate the arguments.
+ */
+ if ((NULL == printerName) || (NULL == defaultString)) {
+ err = VIX_E_INVALID_ARG;
+ g_debug("Failed to get string args\n");
+ goto abort;
+ }
+
+ if (!StrUtil_StrToInt(&defaultInt, defaultString)) {
+ err = VIX_E_INVALID_ARG;
+ g_debug("Failed to convert int arg\n");
+ goto abort;
+ }
+
+ g_debug("Setting printer to: \"%s\", %ssetting as default\n",
+ printerName, (defaultInt != 0) ? "" : "not ");
+
+ /* Actually set the printer. */
+ if (!Printer_AddConnection(printerName, &sysError)) {
+ err = VIX_E_FAIL;
+ g_debug("Failed to add printer %s : %d %s\n", printerName, sysError,
+ Err_Errno2String(sysError));
+ goto abort;
+ }
+
+ /* Set this printer as the default if requested. */
+ if (defaultInt != 0) {
+ if (!Win32U_SetDefaultPrinter(printerName)) {
+ /*
+ * We couldn't set this printer as default. Oh well. We'll
+ * still report success or failure based purely on whether
+ * the actual printer add succeeded or not.
+ */
+ g_debug("Unable to set \"%s\" as the default printer\n",
+ printerName);
+ }
+ }
+
+abort:
+ /*
+ * All Foundry tools commands return results that start with a
+ * foundry error and a guest-OS-specific error.
+ */
+ Str_Sprintf(resultBuffer, sizeof resultBuffer, "%"FMT64"d %d", err, sysError);
+ RPCIN_SETRETVALS(data, resultBuffer, TRUE);
+
+ /*
+ * These were allocated by ToolsDaemonTcloGetQuotedString.
+ */
+ free(printerName);
+ free(defaultString);
+
+ g_debug("<ToolsDaemonTcloSetPrinter\n");
+ return TRUE;
+
+#else
+ Str_Sprintf(resultBuffer,
+ sizeof resultBuffer,
+ "%d %d 0",
+ VIX_E_OP_NOT_SUPPORTED_ON_GUEST,
+ Err_Errno());
+ RPCIN_SETRETVALS(data, resultBuffer, TRUE);
+ return TRUE;
+#endif
+}
+
+
+/**
+ * Returns the list of the plugin's capabilities.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The app context.
+ * @param[in] set Unused.
+ * @param[in] data Unused.
+ *
+ * @return A list of capabilities.
+ */
+
+static GArray *
+VixUserCapabilities(gpointer src,
+ ToolsAppCtx *ctx,
+ gboolean set,
+ gpointer data)
+{
+ const ToolsAppCapability caps[] = {
+ { TOOLS_CAP_OLD, "open_url", 0, 1 },
+ { TOOLS_CAP_OLD, "printer_set", 0, 1 }
+ };
+
+ return VMTools_WrapArray(caps, sizeof *caps, ARRAYSIZE(caps));
+}
+
+
+/**
+ * Returns the registration data for either the guestd or userd process.
+ *
+ * @param[in] ctx The application context.
+ *
+ * @return The registration data.
+ */
+
+TOOLS_MODULE_EXPORT ToolsPluginData *
+ToolsOnLoad(ToolsAppCtx *ctx)
+{
+ static ToolsPluginData regData = {
+ "vixUser",
+ NULL,
+ NULL
+ };
+
+ RpcChannelCallback rpcs[] = {
+ { VIX_BACKDOORCOMMAND_OPEN_URL, VixUserOpenUrl, NULL, NULL, NULL, 0 },
+ { VIX_BACKDOORCOMMAND_SET_GUEST_PRINTER, VixUserSetPrinter, NULL, NULL, NULL, 0 }
+ };
+ ToolsPluginSignalCb sigs[] = {
+ { TOOLS_CORE_SIG_CAPABILITIES, VixUserCapabilities, NULL }
+ };
+ ToolsAppReg regs[] = {
+ { TOOLS_APP_GUESTRPC, VMTools_WrapArray(rpcs, sizeof *rpcs, ARRAYSIZE(rpcs)) },
+ { TOOLS_APP_SIGNALS, VMTools_WrapArray(sigs, sizeof *sigs, ARRAYSIZE(sigs)) }
+ };
+
+ regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs));
+
+ return ®Data;
+}
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libvmbackup.la
+
+libvmbackup_la_CPPFLAGS =
+libvmbackup_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
+
+libvmbackup_la_LDFLAGS =
+libvmbackup_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libvmbackup_la_LIBADD =
+libvmbackup_la_LIBADD += @VMTOOLS_LIBS@
+
+libvmbackup_la_SOURCES =
+libvmbackup_la_SOURCES += scriptOps.c
+libvmbackup_la_SOURCES += stateMachine.c
+libvmbackup_la_SOURCES += syncDriverOps.c
+
+install-exec-local:
+ mkdir -p $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+ cp -L $(builddir)/.libs/libvmbackup.so $(DESTDIR)$(VMSVC_PLUGIN_INSTALLDIR)
+
--- /dev/null
+This is an attempt to describe the VmBackup state machine using ASCII diagrams.
+
+=== Main State Machine ===
+
+The main state machine, implemented in stateMachine.c, works as follows:
+
+ -------------> IDLE <-----------|
+ | | |
+ | b, e | a |
+ | | |
+ | e \/ |
+ SCRIPT_ERROR <--- SCRIPT_FREEZE |
+ ^ | |
+ | d | b |
+ | e \/ | b, e
+ SYNC_ERROR <----- SYNC_FREEZE |
+ ^ | |
+ | | c |
+ | e \/ |
+ |----------- SYNC_THAW |
+ | |
+ | d |
+ \/ |
+ SCRIPT_THAW --------
+
+The transitions mean the following events / conditions:
+
+a. vmbackup.start RPC
+b. vmbackup operation is finished
+c. vmbackup.snapshotDone RPC
+d. sync provider operation is finished
+e. error condition: runtime error, or vmbackup.abort RPC
+
+Sending a vmbackup.start RPC while the state machine is not IDLE causes an
+error to be returned to the client, but the state machine is not changed.
+Same behavior occurs for multiple vmbackup.snapshotDone RPCs. Multiple
+vmbackup.abort messages are ignored.
+
+Transitions to IDLE cause the backup operation to be finalized, and a "done"
+event to be sent to the VMX. Transitions from IDLE cause a "reset" event to be
+sent to the VMX.
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * scriptOps.c --
+ *
+ * Functions for handling freeze/thaw scripts.
+ */
+
+#include "vmBackupInt.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "vm_basic_defs.h"
+#include "file.h"
+#include "guestApp.h"
+#include "procMgr.h"
+#include "str.h"
+#include "util.h"
+
+
+typedef struct VmBackupScript {
+ char *path;
+ ProcMgr_AsyncProc *proc;
+} VmBackupScript;
+
+
+typedef struct VmBackupScriptOp {
+ VmBackupOp callbacks;
+ Bool canceled;
+ Bool thawFailed;
+ VmBackupScriptType type;
+ VmBackupState *state;
+} VmBackupScriptOp;
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupGetScriptPath --
+ *
+ * Returns the path where the scripts to be executed reside.
+ *
+ * Result
+ * A string with the requested path.
+ *
+ * Side effects:
+ * Allocates memory for the path.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+char *
+VmBackupGetScriptPath(void)
+{
+ char *scriptPath = NULL;
+ char *installPath = GuestApp_GetInstallPath();
+
+ if (installPath == NULL) {
+ return NULL;
+ }
+
+ scriptPath = Str_Asprintf(NULL, "%s%s%s", installPath, DIRSEPS, "backupScripts.d");
+ free(installPath);
+
+ return scriptPath;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupRunNextScript --
+ *
+ * Runs the next script for the given operation. If thawing (or running
+ * scripts after a failure), this function will try as much as possible
+ * to start a script, meaning that if it fails to start a script it will
+ * try to start the preceding one until one script is run, or it runs out
+ * of scripts to try.
+ *
+ * Results:
+ * -1: an error occurred.
+ * 0: no more scripts to run.
+ * 1: script was started.
+ *
+ * Side effects:
+ * Increments (or decrements) the "current script" index in the backup state.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+VmBackupRunNextScript(VmBackupScriptOp *op) // IN/OUT
+{
+ const char *scriptOp;
+ int ret = 0;
+ ssize_t index;
+ VmBackupScript *scripts = op->state->scripts;
+
+ switch (op->type) {
+ case VMBACKUP_SCRIPT_FREEZE:
+ index = ++op->state->currentScript;
+ scriptOp = "freeze";
+ break;
+
+ case VMBACKUP_SCRIPT_FREEZE_FAIL:
+ index = --op->state->currentScript;
+ scriptOp = "freezeFail";
+ break;
+
+ case VMBACKUP_SCRIPT_THAW:
+ index = --op->state->currentScript;
+ scriptOp = "thaw";
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+
+ while (index >= 0 && scripts[index].path != NULL) {
+ char *cmd;
+
+ cmd = Str_Asprintf(NULL, "\"%s\" %s", scripts[index].path, scriptOp);
+ if (cmd == NULL) {
+ index = --op->state->currentScript;
+ op->thawFailed = TRUE;
+ }
+
+ if ((scripts[index].proc = ProcMgr_ExecAsync(cmd, NULL)) == NULL) {
+ if (op->type == VMBACKUP_SCRIPT_FREEZE) {
+ ret = -1;
+ break;
+ } else {
+ index = --op->state->currentScript;
+ op->thawFailed = TRUE;
+ }
+ } else {
+ ret = 1;
+ break;
+ }
+
+ /* This happens if all thaw/fail scripts failed to start. */
+ if (index == -1 && scripts[0].proc == NULL) {
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupStringCompare --
+ *
+ * Comparison function used to sort the script list in ascending order.
+ *
+ * Result
+ * The result of strcmp(str1, str2).
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+VmBackupStringCompare(const void *str1, // IN
+ const void *str2) // IN
+{
+ return strcmp(* (char * const *) str1,* (char * const *) str2);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupScriptOpQuery --
+ *
+ * Checks the status of the current running script. If the script is
+ * finished, run the next script in the queue or, if no scripts are left,
+ * return a "finished" status.
+ *
+ * Result
+ * The status of the operation.
+ *
+ * Side effects:
+ * Might start a new process.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static VmBackupOpStatus
+VmBackupScriptOpQuery(VmBackupOp *_op) // IN
+{
+ VmBackupOpStatus ret = VMBACKUP_STATUS_PENDING;
+ VmBackupScriptOp *op = (VmBackupScriptOp *) _op;
+ VmBackupScript *scripts = op->state->scripts;
+ VmBackupScript *currScript = NULL;
+
+ if (scripts != NULL && op->state->currentScript >= 0) {
+ currScript = &scripts[op->state->currentScript];
+ }
+
+ if (op->canceled) {
+ ret = VMBACKUP_STATUS_CANCELED;
+ goto exit;
+ } else if (scripts == NULL || currScript == NULL || currScript->proc == NULL) {
+ ret = VMBACKUP_STATUS_FINISHED;
+ goto exit;
+ }
+
+ if (!ProcMgr_IsAsyncProcRunning(currScript->proc)) {
+ int exitCode;
+ Bool succeeded;
+
+ succeeded = (ProcMgr_GetExitCode(currScript->proc, &exitCode) == 0 &&
+ exitCode == 0);
+ ProcMgr_Free(currScript->proc);
+ currScript->proc = NULL;
+
+ /*
+ * If thaw scripts fail, keep running and only notify the failure after
+ * all others have run.
+ */
+ if (!succeeded) {
+ if (op->type == VMBACKUP_SCRIPT_FREEZE) {
+ ret = VMBACKUP_STATUS_ERROR;
+ goto exit;
+ } else if (op->type == VMBACKUP_SCRIPT_THAW) {
+ op->thawFailed = TRUE;
+ }
+ }
+
+ switch (VmBackupRunNextScript(op)) {
+ case -1:
+ ret = VMBACKUP_STATUS_ERROR;
+ break;
+
+ case 0:
+ ret = op->thawFailed ? VMBACKUP_STATUS_ERROR : VMBACKUP_STATUS_FINISHED;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+exit:
+ if (ret == VMBACKUP_STATUS_ERROR) {
+ /* Report the script error to the host */
+ VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ERROR,
+ VMBACKUP_SCRIPT_ERROR,
+ "Custom script failed.");
+ }
+ return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupScriptOpRelease --
+ *
+ * Frees memory allocated for the state object. Behavior is undefined
+ * if the memory is freed before the query function says the operation
+ * if finished.
+ *
+ * Result
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VmBackupScriptOpRelease(VmBackupOp *_op) // IN
+{
+ size_t i;
+ VmBackupScriptOp *op = (VmBackupScriptOp *) _op;
+
+ if (op->type != VMBACKUP_SCRIPT_FREEZE && op->state->scripts != NULL) {
+ VmBackupScript *scripts = op->state->scripts;
+ for (i = 0; scripts[i].path != NULL; i++) {
+ free(scripts[i].path);
+ if (scripts[i].proc != NULL) {
+ ProcMgr_Free(scripts[i].proc);
+ }
+ }
+ free(op->state->scripts);
+ op->state->scripts = NULL;
+ op->state->currentScript = 0;
+ }
+
+ free(op);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupScriptOpCancel --
+ *
+ * Cancels the current operation. Kills any currently running script and
+ * flags the operation as canceled.
+ *
+ * Result
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VmBackupScriptOpCancel(VmBackupOp *_op) // IN
+{
+ VmBackupScriptOp *op = (VmBackupScriptOp *) _op;
+ VmBackupScript *scripts = op->state->scripts;
+ VmBackupScript *currScript = NULL;
+ ProcMgr_Pid pid;
+
+ if (scripts != NULL) {
+ currScript = &scripts[op->state->currentScript];
+ ASSERT(currScript->proc != NULL);
+
+ pid = ProcMgr_GetPid(currScript->proc);
+ if (!ProcMgr_KillByPid(pid)) {
+ // XXX: what to do in this situation? other than log and cry?
+ } else {
+ int exitCode;
+ ProcMgr_GetExitCode(currScript->proc, &exitCode);
+ }
+ }
+
+ op->canceled = TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupNewScriptOp --
+ *
+ * Creates a new state object to monitor the execution of OnFreeze or
+ * OnThaw scripts. This will identify all the scripts in the backup scripts
+ * directory and add them to an execution queue.
+ *
+ * Note: there is some state created when instantianting the "OnFreeze"
+ * scripts which is only released after the "OnThaw" scripts are run. So
+ * the caller has to make sure that thaw (or fail) scripts are run every
+ * time the freeze scripts are run.
+ *
+ * Result
+ * A pointer to the operation state, or NULL on failure.
+ *
+ * Side effects:
+ * If there are scripts to be executed, the first one is started.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VmBackupOp *
+VmBackup_NewScriptOp(VmBackupScriptType type, // IN
+ VmBackupState *state) // IN
+{
+ Bool fail = FALSE;
+ char **fileList = NULL;
+ char *scriptDir = NULL;
+ int numFiles = 0;
+ size_t i;
+ VmBackupScriptOp *op = NULL;
+
+ scriptDir = VmBackupGetScriptPath();
+ if (scriptDir == NULL) {
+ goto exit;
+ }
+
+ op = calloc(1, sizeof *op);
+ if (op == NULL) {
+ goto exit;
+ }
+
+ op->state = state;
+ op->type = type;
+ op->callbacks.queryFn = VmBackupScriptOpQuery;
+ op->callbacks.cancelFn = VmBackupScriptOpCancel;
+ op->callbacks.releaseFn = VmBackupScriptOpRelease;
+
+ g_debug("Trying to run scripts from %s\n", scriptDir);
+
+ /*
+ * Load the list of scripts to run when freezing. The same list will be
+ * used later in case of failure, or when thawing, in reverse order.
+ *
+ * This logic won't recurse into directories, so only files directly under
+ * the script dir will be considered.
+ */
+ if (type == VMBACKUP_SCRIPT_FREEZE && File_IsDirectory(scriptDir)) {
+ size_t scriptCount = 0;
+
+ state->scripts = NULL;
+ state->currentScript = 0;
+ numFiles = File_ListDirectory(scriptDir, &fileList);
+
+ if (numFiles > 0) {
+ VmBackupScript *scripts;
+
+ scripts = calloc(1, (numFiles + 1) * sizeof *scripts);
+ if (scripts == NULL) {
+ fail = TRUE;
+ goto exit;
+ }
+
+ state->scripts = scripts;
+
+ /*
+ * VmBackupRunNextScript increments the index, so need to make it point
+ * to "before the first script".
+ */
+ state->currentScript = -1;
+
+ if (numFiles > 1) {
+ qsort(fileList, (size_t) numFiles, sizeof *fileList, VmBackupStringCompare);
+ }
+
+ for (i = 0; i < numFiles; i++) {
+ char *script;
+
+ script = Str_Asprintf(NULL, "%s%c%s", scriptDir, DIRSEPC, fileList[i]);
+ if (script == NULL) {
+ fail = TRUE;
+ goto exit;
+ } else if (File_IsFile(script)) {
+ scripts[scriptCount++].path = script;
+ } else {
+ free(script);
+ }
+ }
+ }
+ }
+
+ /*
+ * If there are any scripts to be executed, start the first one. If we get to
+ * this point, we won't free the scripts array until VmBackupScriptOpRelease
+ * is called after thawing (or after the sync provider failed and the "fail"
+ * scripts are run).
+ */
+ fail = (state->scripts != NULL && VmBackupRunNextScript(op) == -1);
+
+exit:
+ /* Free the file list. */
+ for (i = 0; i < numFiles; i++) {
+ free(fileList[i]);
+ }
+ free(fileList);
+
+ if (fail && op != NULL) {
+ VmBackup_Release((VmBackupOp *) op);
+ op = NULL;
+ }
+ free(scriptDir);
+ return (VmBackupOp *) op;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file stateMachine.c
+ *
+ * Implements a generic state machine for executing backup operations
+ * asynchronously. Since VSS is based on an asynchronous polling model,
+ * we're basing all backup operations on a similar model controlled by this
+ * state machine, even if it would be more eficient to use an event-driven
+ * approach in some cases.
+ *
+ * For a description of the state machine, check the README file.
+ *
+ * The sync provider state machine depends on the particular implementation.
+ * For the sync driver, it enables the driver and waits for a "snapshot done"
+ * message before finishing. For the VSS subsystem, the sync provider just
+ * implements a VSS backup cycle.
+ */
+
+#include "vmBackupInt.h"
+
+#include <gmodule.h>
+#include "guestApp.h"
+#include "str.h"
+#include "strutil.h"
+#include "util.h"
+#include "vmtools.h"
+
+#if !defined(__APPLE__)
+#include "embed_version.h"
+#include "vmtoolsd_version.h"
+VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
+#endif
+
+
+#define VMBACKUP_ENQUEUE_EVENT() do { \
+ gBackupState->timerEvent = g_timeout_source_new(gBackupState->pollPeriod); \
+ VMTOOLSAPP_ATTACH_SOURCE(gBackupState->ctx, \
+ gBackupState->timerEvent, \
+ VmBackupAsyncCallback, \
+ NULL, \
+ NULL); \
+} while (0)
+
+static VmBackupState *gBackupState = NULL;
+static VmBackupSyncProvider *gSyncProvider = NULL;
+
+static Bool
+VmBackupEnableSync(void);
+
+
+/**
+ * Sends a keep alive backup event to the VMX.
+ *
+ * @param[in] clientData Unused.
+ *
+ * @return FALSE
+ */
+
+static gboolean
+VmBackupKeepAliveCallback(void *clientData)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+ ASSERT(gBackupState != NULL);
+ g_source_unref(gBackupState->keepAlive);
+ gBackupState->keepAlive = NULL;
+ VmBackup_SendEvent(VMBACKUP_EVENT_KEEP_ALIVE, 0, "");
+ return FALSE;
+}
+
+
+/**
+ * Sends a command to the VMX asking it to update VMDB about a new backup event.
+ * This will restart the keep-alive timer.
+ *
+ * @param[in] event The event to set.
+ * @param[in] code Error code.
+ * @param[in] dest Error description.
+ *
+ * @return TRUE on success.
+ */
+
+Bool
+VmBackup_SendEvent(const char *event,
+ const uint32 code,
+ const char *desc)
+{
+ Bool success;
+ char *result;
+ size_t resultLen;
+ gchar *msg;
+
+ ASSERT(gBackupState != NULL);
+
+ g_debug("*** %s\n", __FUNCTION__);
+ if (gBackupState->keepAlive != NULL) {
+ g_source_destroy(gBackupState->keepAlive);
+ }
+
+ msg = g_strdup_printf(VMBACKUP_PROTOCOL_EVENT_SET" %s %u %s", event, code, desc);
+ success = RpcChannel_Send(gBackupState->ctx->rpc, msg, strlen(msg) + 1,
+ &result, &resultLen);
+
+ if (!success) {
+ g_warning("Failed to send event to the VMX: %s.\n", result);
+ }
+
+ gBackupState->keepAlive = g_timeout_source_new(VMBACKUP_KEEP_ALIVE_PERIOD / 2);
+ VMTOOLSAPP_ATTACH_SOURCE(gBackupState->ctx,
+ gBackupState->keepAlive,
+ VmBackupKeepAliveCallback,
+ NULL,
+ NULL);
+ return success;
+}
+
+
+/**
+ * Cleans up the backup state object and sends a "done" event to the VMX.
+ */
+
+static void
+VmBackupFinalize(void)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+ g_assert(gBackupState != NULL);
+ g_assert(gBackupState->machineState == VMBACKUP_MSTATE_IDLE);
+
+ if (gBackupState->currentOp != NULL) {
+ VmBackup_Cancel(gBackupState->currentOp);
+ VmBackup_Release(gBackupState->currentOp);
+ }
+
+ VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_DONE, VMBACKUP_SUCCESS, "");
+
+ if (gBackupState->timerEvent != NULL) {
+ g_source_destroy(gBackupState->timerEvent);
+ }
+
+ if (gBackupState->keepAlive != NULL) {
+ g_source_destroy(gBackupState->keepAlive);
+ }
+
+ free(gBackupState->volumes);
+ free(gBackupState);
+ gBackupState = NULL;
+}
+
+
+/**
+ * Starts the execution of the scripts for the given action type.
+ *
+ * @param[in] type Type of scripts being started.
+ *
+ * @return TRUE, unless starting the scripts fails for some reason.
+ */
+
+static Bool
+VmBackupStartScripts(VmBackupScriptType type)
+{
+ const char *opName;
+ VmBackupMState nextState;
+ g_debug("*** %s\n", __FUNCTION__);
+
+ switch (type) {
+ case VMBACKUP_SCRIPT_FREEZE:
+ opName = "VmBackupOnFreeze";
+ nextState = VMBACKUP_MSTATE_SCRIPT_FREEZE;
+ break;
+
+ case VMBACKUP_SCRIPT_FREEZE_FAIL:
+ opName = "VmBackupOnFreezeFail";
+ nextState = VMBACKUP_MSTATE_SCRIPT_ERROR;
+ break;
+
+ case VMBACKUP_SCRIPT_THAW:
+ opName = "VmBackupOnThaw";
+ nextState = VMBACKUP_MSTATE_SCRIPT_THAW;
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+
+ if (!VmBackup_SetCurrentOp(gBackupState,
+ VmBackup_NewScriptOp(type, gBackupState),
+ NULL,
+ opName)) {
+ VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ERROR,
+ VMBACKUP_SCRIPT_ERROR,
+ "Error when starting backup scripts.");
+ return FALSE;
+ }
+
+ gBackupState->machineState = nextState;
+ return TRUE;
+}
+
+
+/**
+ * Puts the state machine in the right state when an error occurs. The caller
+ * should check for the state of the backup upon this function returning: if
+ * it's IDLE, it means the backup state should be cleaned up.
+ *
+ * @return Whether the backup operation should be finalized.
+ */
+
+static gboolean
+VmBackupOnError(void)
+{
+ switch (gBackupState->machineState) {
+ case VMBACKUP_MSTATE_SCRIPT_FREEZE:
+ case VMBACKUP_MSTATE_SYNC_ERROR:
+ /* Next state is "script error". */
+ if (!VmBackupStartScripts(VMBACKUP_SCRIPT_FREEZE_FAIL)) {
+ gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
+ }
+ break;
+
+ case VMBACKUP_MSTATE_SYNC_FREEZE:
+ case VMBACKUP_MSTATE_SYNC_THAW:
+ /* Next state is "sync error". */
+ gBackupState->pollPeriod = 1000;
+ gBackupState->machineState = VMBACKUP_MSTATE_SYNC_ERROR;
+ break;
+
+ case VMBACKUP_MSTATE_SCRIPT_THAW:
+ /* Next state is "idle". */
+ gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
+ break;
+
+ default:
+ g_error("Unexpected machine state on error: %d\n", gBackupState->machineState);
+ }
+
+ return (gBackupState->machineState == VMBACKUP_MSTATE_IDLE);
+}
+
+
+/**
+ * Callback that checks for the status of the current operation. Calls the
+ * queued operations as needed.
+ *
+ * @param[in] clientData Unused.
+ *
+ * @return FALSE
+ */
+
+static gboolean
+VmBackupAsyncCallback(void *clientData)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+ g_assert(gBackupState != NULL);
+
+ g_source_unref(gBackupState->timerEvent);
+ gBackupState->timerEvent = NULL;
+
+ if (gBackupState->currentOp != NULL) {
+ VmBackupOpStatus status;
+
+ g_debug("VmBackupAsyncCallback: checking %s\n", gBackupState->currentOpName);
+ status = VmBackup_QueryStatus(gBackupState->currentOp);
+
+ switch (status) {
+ case VMBACKUP_STATUS_PENDING:
+ goto exit;
+
+ case VMBACKUP_STATUS_FINISHED:
+ g_debug("Async request completed\n");
+ VmBackup_Release(gBackupState->currentOp);
+ gBackupState->currentOp = NULL;
+ break;
+
+ default:
+ {
+ Bool freeMsg = TRUE;
+ char *errMsg = Str_Asprintf(NULL,
+ "Asynchronous operation failed: %s",
+ gBackupState->currentOpName);
+ if (errMsg == NULL) {
+ freeMsg = FALSE;
+ errMsg = "Asynchronous operation failed.";
+ }
+ VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ERROR,
+ VMBACKUP_UNEXPECTED_ERROR,
+ errMsg);
+ if (freeMsg) {
+ free(errMsg);
+ }
+
+ VmBackup_Release(gBackupState->currentOp);
+ gBackupState->currentOp = NULL;
+ VmBackupOnError();
+ goto exit;
+ }
+ }
+ }
+
+ /*
+ * Keep calling the registered callback until it's either NULL, or
+ * an asynchronous operation is scheduled.
+ */
+ while (gBackupState->callback != NULL) {
+ VmBackupCallback cb = gBackupState->callback;
+ gBackupState->callback = NULL;
+
+ if (cb(gBackupState)) {
+ if (gBackupState->currentOp != NULL || gBackupState->forceRequeue) {
+ goto exit;
+ }
+ } else {
+ VmBackupOnError();
+ goto exit;
+ }
+ }
+
+ /*
+ * At this point, the current operation can be declared finished, and the
+ * state machine can move to the next state.
+ */
+ switch (gBackupState->machineState) {
+ case VMBACKUP_MSTATE_SCRIPT_FREEZE:
+ /* Next state is "sync freeze". */
+ if (!VmBackupEnableSync()) {
+ VmBackupOnError();
+ }
+ break;
+
+ case VMBACKUP_MSTATE_SYNC_FREEZE:
+ /*
+ * The SYNC_FREEZE -> SYNC_THAW transition is handled by the RPC callback,
+ * so this case is a no-op.
+ */
+ break;
+
+ case VMBACKUP_MSTATE_SYNC_THAW:
+ /* Next state is "script thaw". */
+ if (!VmBackupStartScripts(VMBACKUP_SCRIPT_THAW)) {
+ VmBackupOnError();
+ }
+ break;
+
+ case VMBACKUP_MSTATE_SCRIPT_ERROR:
+ case VMBACKUP_MSTATE_SCRIPT_THAW:
+ /* Next state is "idle". */
+ gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
+ break;
+
+ case VMBACKUP_MSTATE_SYNC_ERROR:
+ /* Next state is "script error". */
+ if (!VmBackupStartScripts(VMBACKUP_SCRIPT_FREEZE_FAIL)) {
+ VmBackupOnError();
+ }
+ break;
+
+ default:
+ g_error("Unexpected machine state: %d\n", gBackupState->machineState);
+ }
+
+exit:
+ /* If the state machine is back in IDLE, it means the backup operation finished. */
+ if (gBackupState->machineState == VMBACKUP_MSTATE_IDLE) {
+ VmBackupFinalize();
+ } else {
+ gBackupState->forceRequeue = FALSE;
+ VMBACKUP_ENQUEUE_EVENT();
+ }
+ return FALSE;
+}
+
+
+/**
+ * Calls the sync provider's start function.
+ *
+ * @param[in] state The backup state.
+ *
+ * @return Whether the provider's start callback was successful.
+ */
+
+static Bool
+VmBackupEnableSync(void)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+ if (!gSyncProvider->start(gBackupState, gSyncProvider->clientData)) {
+ VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ERROR,
+ VMBACKUP_SYNC_ERROR,
+ "Error when enabling the sync provider.");
+ return FALSE;
+ }
+
+ gBackupState->machineState = VMBACKUP_MSTATE_SYNC_FREEZE;
+ return TRUE;
+}
+
+
+/* RpcIn callbacks. */
+
+
+/**
+ * Handler for the "vmbackup.start" message. Starts the "freeze" scripts
+ * unless there's another backup operation going on or some other
+ * unexpected error occurs.
+ *
+ * @param[in] data RPC data.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+VmBackupStart(RpcInData *data)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+ if (gBackupState != NULL) {
+ return RPCIN_SETRETVALS(data, "Backup operation already in progress.", FALSE);
+ }
+
+ gBackupState = Util_SafeMalloc(sizeof *gBackupState);
+ memset(gBackupState, 0, sizeof *gBackupState);
+
+ gBackupState->ctx = data->appCtx;
+ gBackupState->pollPeriod = 1000;
+ gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
+
+ if (data->argsSize > 0) {
+ int generateManifests = 0;
+ int index = 0;
+
+ if (StrUtil_GetNextIntToken(&generateManifests, &index, data->args, " ")) {
+ gBackupState->generateManifests = generateManifests;
+ }
+
+ if (data->args[index] != '\0') {
+ gBackupState->volumes = Util_SafeStrdup(data->args + index);
+ }
+ }
+
+ gBackupState->configDir = GuestApp_GetConfPath();
+ if (gBackupState->configDir == NULL) {
+ free(gBackupState);
+ gBackupState = NULL;
+ return RPCIN_SETRETVALS(data, "Error getting configuration directory.", FALSE);
+ }
+
+ VmBackup_SendEvent(VMBACKUP_EVENT_RESET, VMBACKUP_SUCCESS, "");
+
+ if (!VmBackupStartScripts(VMBACKUP_SCRIPT_FREEZE)) {
+ free(gBackupState);
+ gBackupState = NULL;
+ return RPCIN_SETRETVALS(data, "Error initializing backup.", FALSE);
+ }
+
+ VMBACKUP_ENQUEUE_EVENT();
+ return RPCIN_SETRETVALS(data, "", TRUE);
+}
+
+
+/**
+ * Aborts the current operation if one is active, and stops the backup
+ * process. If the sync provider has been activated, tell it to abort
+ * the ongoing operation.
+ *
+ * @param[in] data RPC data.
+ *
+ * @return TRUE
+ */
+
+static Bool
+VmBackupAbort(RpcInData *data)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+ if (gBackupState == NULL) {
+ return RPCIN_SETRETVALS(data, "Error: no backup in progress", FALSE);
+ } else if (gBackupState->machineState != VMBACKUP_MSTATE_SCRIPT_ERROR &&
+ gBackupState->machineState != VMBACKUP_MSTATE_SYNC_ERROR) {
+ /* Mark the current operation as cancelled. */
+ if (gBackupState->currentOp != NULL) {
+ VmBackup_Cancel(gBackupState->currentOp);
+ VmBackup_Release(gBackupState->currentOp);
+ gBackupState->currentOp = NULL;
+ }
+
+ /* If the sync provider is engaged, signal that it should stop. */
+ if (gBackupState->machineState == VMBACKUP_MSTATE_SYNC_FREEZE ||
+ gBackupState->machineState == VMBACKUP_MSTATE_SYNC_THAW) {
+ gSyncProvider->abort(gBackupState, gSyncProvider->clientData);
+ }
+
+ VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ABORT,
+ VMBACKUP_REMOTE_ABORT,
+ "Remote abort.");
+
+ /* Transition to the error state. */
+ if (VmBackupOnError()) {
+ VmBackupFinalize();
+ }
+ }
+ return RPCIN_SETRETVALS(data, "", TRUE);
+}
+
+
+/**
+ * Notifies the sync provider to thaw the file systems and puts the state
+ * machine in the SYNC_THAW state.
+ *
+ * @param[in] data RPC data.
+ *
+ * @return TRUE
+ */
+
+static Bool
+VmBackupSnapshotDone(RpcInData *data)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+ if (gBackupState == NULL) {
+ return RPCIN_SETRETVALS(data, "Error: no backup in progress", FALSE);
+ } else if (gBackupState->machineState != VMBACKUP_MSTATE_SYNC_FREEZE) {
+ return RPCIN_SETRETVALS(data,
+ "Error: unexpected state for snapshot done message.",
+ FALSE);
+ } else {
+ if (!gSyncProvider->snapshotDone(gBackupState, gSyncProvider->clientData)) {
+ VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ERROR,
+ VMBACKUP_SYNC_ERROR,
+ "Error when notifying the sync provider.");
+ if (VmBackupOnError()) {
+ VmBackupFinalize();
+ }
+ } else {
+ gBackupState->machineState = VMBACKUP_MSTATE_SYNC_THAW;
+ }
+ return RPCIN_SETRETVALS(data, "", TRUE);
+ }
+}
+
+
+/**
+ * Reset callback. Currently does nothing.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx Unused.
+ * @param[in] data Unused.
+ */
+
+static void
+VmBackupReset(gpointer src,
+ ToolsAppCtx *ctx,
+ gpointer data)
+{
+}
+
+
+/**
+ * Cleans up the plugin.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The app context.
+ * @param[in] data Unused.
+ */
+
+static void
+VmBackupShutdown(gpointer src,
+ ToolsAppCtx *ctx,
+ gpointer data)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+ if (gBackupState != NULL) {
+ VmBackupFinalize();
+ }
+
+ gSyncProvider->release(gSyncProvider);
+ gSyncProvider = NULL;
+}
+
+
+/**
+ * Plugin entry point. Initializes internal plugin state.
+ *
+ * @param[in] ctx The app context.
+ *
+ * @return The registration data. Returns NULL if there is no sync provider
+ * available to quiesce the filesystems.
+ */
+
+TOOLS_MODULE_EXPORT ToolsPluginData *
+ToolsOnLoad(ToolsAppCtx *ctx)
+{
+ static ToolsPluginData regData = {
+ "vmbackup",
+ NULL,
+ NULL
+ };
+
+ /*
+ * For Win32, first check whether we have VSS support available. Otherwise,
+ * check if there is a sync driver installed. If nothing is found, return
+ * NULL, since we don't want to register any handlers.
+ */
+
+ VmBackupSyncProvider *provider = NULL;
+
+#if defined(G_PLATFORM_WIN32)
+ if (ToolsCore_InitializeCOM(ctx)) {
+ provider = VmBackup_NewVssProvider();
+ }
+#endif
+
+ if (provider == NULL) {
+ provider = VmBackup_NewSyncDriverProvider();
+ }
+
+ if (provider != NULL) {
+ RpcChannelCallback rpcs[] = {
+ { VMBACKUP_PROTOCOL_START, VmBackupStart, NULL, NULL, NULL, 0 },
+ { VMBACKUP_PROTOCOL_ABORT, VmBackupAbort, NULL, NULL, NULL, 0 },
+ { VMBACKUP_PROTOCOL_SNAPSHOT_DONE, VmBackupSnapshotDone, NULL, NULL, NULL, 0 }
+ };
+ ToolsPluginSignalCb sigs[] = {
+ { TOOLS_CORE_SIG_RESET, VmBackupReset, NULL },
+ { TOOLS_CORE_SIG_SHUTDOWN, VmBackupShutdown, NULL },
+ };
+ ToolsAppReg regs[] = {
+ { TOOLS_APP_GUESTRPC, VMTools_WrapArray(rpcs, sizeof *rpcs, ARRAYSIZE(rpcs)) },
+ { TOOLS_APP_SIGNALS, VMTools_WrapArray(sigs, sizeof *sigs, ARRAYSIZE(sigs)) },
+ };
+
+ gSyncProvider = provider;
+ regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs));
+ return ®Data;
+ }
+
+ return NULL;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * syncDriverOps.c --
+ *
+ * Implements the sync driver provider for the backup state machine.
+ */
+
+#include "vmBackupInt.h"
+
+#include "file.h"
+#include "procMgr.h"
+#include "syncDriver.h"
+#include "util.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include <process.h>
+#endif
+
+typedef struct VmBackupDriverOp {
+ VmBackupOp callbacks;
+ const char *volumes;
+ Bool freeze;
+ Bool canceled;
+ SyncDriverHandle syncHandle;
+} VmBackupDriverOp;
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupDriverOpQuery --
+ *
+ * Checks the status of the app that is enabling or disabling the
+ * sync driver.
+ *
+ * Result
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static VmBackupOpStatus
+VmBackupDriverOpQuery(VmBackupOp *_op) // IN
+{
+ VmBackupDriverOp *op = (VmBackupDriverOp *) _op;
+ VmBackupOpStatus ret;
+
+ SyncDriverStatus st;
+
+ st = SyncDriver_QueryStatus(op->syncHandle, 0);
+ g_debug("SyncDriver status: %d\n", st);
+
+ switch(st) {
+ case SYNCDRIVER_BUSY:
+ ret = VMBACKUP_STATUS_PENDING;
+ break;
+
+ case SYNCDRIVER_IDLE:
+ if (op->freeze && op->canceled) {
+ SyncDriver_Thaw(op->syncHandle);
+ }
+ ret = (op->canceled) ? VMBACKUP_STATUS_CANCELED : VMBACKUP_STATUS_FINISHED;
+ break;
+
+ default:
+ ret = VMBACKUP_STATUS_ERROR;
+ break;
+ }
+
+ return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupDriverOpRelease --
+ *
+ * Cleans up data held by the state object.
+ *
+ * Result
+ * The status of the app.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VmBackupDriverOpRelease(VmBackupOp *_op) // IN
+{
+ VmBackupDriverOp *op = (VmBackupDriverOp *) _op;
+ if (!op->freeze) {
+ SyncDriver_CloseHandle(&op->syncHandle);
+ }
+ free(op);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupDriverOpCancel --
+ *
+ * Cancel an ongoing sync driver operation. This doesn't actually
+ * cancel the operation, but rather waits for it to finish, since
+ * just killing the worker thread might have undesired side effects.
+ * This will not cancel thaw operations.
+ *
+ * Result
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VmBackupDriverOpCancel(VmBackupOp *_op) // IN
+{
+ VmBackupDriverOp *op = (VmBackupDriverOp *) _op;
+ op->canceled = TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupNewDriverOp --
+ *
+ * Enables or disables the sync driver. Note: "volumes" is not copied,
+ * to avoid unnecessary waste of memory, since it's kept in the global
+ * backup state structure.
+ *
+ * Result
+ * A state object, unless some error occurs.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static VmBackupDriverOp *
+VmBackupNewDriverOp(Bool freeze, // IN
+ SyncDriverHandle handle, // IN
+ const char *volumes) // IN
+{
+ VmBackupDriverOp *op = NULL;
+
+ op = Util_SafeMalloc(sizeof *op);
+ memset(op, 0, sizeof *op);
+
+ op->callbacks.queryFn = VmBackupDriverOpQuery;
+ op->callbacks.cancelFn = VmBackupDriverOpCancel;
+ op->callbacks.releaseFn = VmBackupDriverOpRelease;
+ op->freeze = freeze;
+ op->volumes = volumes;
+
+ if (freeze && !SyncDriver_Freeze(op->volumes, &handle)) {
+ g_warning("Error freezing filesystems.\n");
+ free(op);
+ op = NULL;
+ } else if (!freeze && !SyncDriver_Thaw(handle)) {
+ g_warning("Error thawing filesystems.\n");
+ free(op);
+ op = NULL;
+ } else {
+ op->syncHandle = handle;
+ }
+ return op;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupSyncDriverReadyForSnapshot --
+ *
+ * Sends an event to the VMX indicating that the guest is ready for a
+ * snapshot to be taken (i.e., scripts have run and sync driver is
+ * enabled).
+ *
+ * Result
+ * TRUE, unless sending the message fails.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+VmBackupSyncDriverReadyForSnapshot(VmBackupState *state)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+ return VmBackup_SendEvent(VMBACKUP_EVENT_SNAPSHOT_COMMIT, 0, "");
+}
+
+
+/* Sync provider implementation. */
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupSyncDriverStart --
+ *
+ * Starts an asynchronous operation to enable the sync driver.
+ *
+ * Result
+ * TRUE, unless an error occurs.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+VmBackupSyncDriverStart(VmBackupState *state,
+ void *clientData)
+{
+ VmBackupDriverOp *op;
+
+ g_debug("*** %s\n", __FUNCTION__);
+ op = VmBackupNewDriverOp(TRUE,
+ (SyncDriverHandle) state->clientData,
+ state->volumes);
+
+ if (op != NULL) {
+ state->clientData = (intptr_t) op->syncHandle;
+ }
+
+ return VmBackup_SetCurrentOp(state,
+ (VmBackupOp *) op,
+ VmBackupSyncDriverReadyForSnapshot,
+ __FUNCTION__);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupSyncDriverAbort --
+ *
+ * Does nothing.
+ *
+ * Result
+ * TRUE.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+VmBackupSyncDriverAbort(VmBackupState *state,
+ void *clientData)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupSyncDriverSnapshotDone --
+ *
+ * Starts an asynchronous operation to disable the sync driver.
+ *
+ * Result
+ * TRUE, unless an error occurs.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+VmBackupSyncDriverSnapshotDone(VmBackupState *state,
+ void *clientData)
+{
+ VmBackupDriverOp *op;
+
+ g_debug("*** %s\n", __FUNCTION__);
+
+ op = VmBackupNewDriverOp(FALSE,
+ (SyncDriverHandle) state->clientData,
+ NULL);
+
+ return VmBackup_SetCurrentOp(state, (VmBackupOp *) op, NULL, __FUNCTION__);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackupSyncDriverRelease --
+ *
+ * Frees the given pointer.
+ *
+ * Result
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VmBackupSyncDriverRelease(struct VmBackupSyncProvider *provider)
+{
+ free(provider);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VmBackup_NewSyncDriverProvider --
+ *
+ * Returns a new VmBackupSyncProvider that will enable the sync driver
+ * as part of the "sync" operation of a backup.
+ *
+ * Result
+ * NULL on error.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VmBackupSyncProvider *
+VmBackup_NewSyncDriverProvider(void)
+{
+ VmBackupSyncProvider *provider;
+
+ if (!SyncDriver_Init()) {
+ g_debug("Error initializing the sync driver.\n");
+ return NULL;
+ }
+
+ provider = Util_SafeMalloc(sizeof *provider);
+ provider->start = VmBackupSyncDriverStart;
+ provider->abort = VmBackupSyncDriverAbort;
+ provider->snapshotDone = VmBackupSyncDriverSnapshotDone;
+ provider->release = VmBackupSyncDriverRelease;
+ provider->clientData = NULL;
+
+ return provider;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file vmBackupInt.h
+ *
+ * Internal definitions used by the vmbackup code.
+ */
+
+#ifndef _VMBACKUPINT_H_
+#define _VMBACKUPINT_H_
+
+#define G_LOG_DOMAIN "vmbackup"
+
+#include <glib.h>
+#include "vmware.h"
+#include "vmbackup_def.h"
+#include "vmtoolsApp.h"
+
+typedef enum {
+ VMBACKUP_STATUS_PENDING,
+ VMBACKUP_STATUS_FINISHED,
+ VMBACKUP_STATUS_CANCELED,
+ VMBACKUP_STATUS_ERROR
+} VmBackupOpStatus;
+
+typedef enum {
+ VMBACKUP_SCRIPT_FREEZE,
+ VMBACKUP_SCRIPT_FREEZE_FAIL,
+ VMBACKUP_SCRIPT_THAW
+} VmBackupScriptType;
+
+typedef enum {
+ VMBACKUP_MSTATE_IDLE,
+ VMBACKUP_MSTATE_SCRIPT_FREEZE,
+ VMBACKUP_MSTATE_SYNC_FREEZE,
+ VMBACKUP_MSTATE_SYNC_THAW,
+ VMBACKUP_MSTATE_SCRIPT_THAW,
+ VMBACKUP_MSTATE_SCRIPT_ERROR,
+ VMBACKUP_MSTATE_SYNC_ERROR
+} VmBackupMState;
+
+/**
+ * This is a "base struct" for asynchronous operations monitored by the
+ * state machine. Each implementation should provide these three functions
+ * at the start of the struct so that the state machine can properly
+ * interact with it.
+ */
+
+typedef struct VmBackupOp {
+ VmBackupOpStatus (*queryFn)(struct VmBackupOp *);
+ void (*releaseFn)(struct VmBackupOp *);
+ void (*cancelFn)(struct VmBackupOp *);
+} VmBackupOp;
+
+
+/**
+ * Holds information about the current state of the backup operation.
+ * Don't modify the fields directly - rather, use VmBackup_SetCurrentOp,
+ * which does most of the handling needed by users of the state machine.
+ */
+
+typedef struct VmBackupState {
+ ToolsAppCtx *ctx;
+ VmBackupOp *currentOp;
+ const char *currentOpName;
+ char *volumes;
+ guint pollPeriod;
+ GSource *timerEvent;
+ GSource *keepAlive;
+ Bool (*callback)(struct VmBackupState *);
+ Bool forceRequeue;
+ Bool generateManifests;
+ intptr_t clientData;
+ void *scripts;
+ const char *configDir;
+ ssize_t currentScript;
+ VmBackupMState machineState;
+} VmBackupState;
+
+typedef Bool (*VmBackupCallback)(VmBackupState *);
+typedef Bool (*VmBackupProviderCallback)(VmBackupState *, void *clientData);
+
+
+/**
+ * Defines the interface between the state machine and the implementation
+ * of the "sync provider": either the VSS requestor or the sync driver
+ * provider, currently.
+ */
+
+typedef struct VmBackupSyncProvider {
+ VmBackupProviderCallback start;
+ VmBackupProviderCallback abort;
+ VmBackupProviderCallback snapshotDone;
+ void (*release)(struct VmBackupSyncProvider *);
+ void *clientData;
+} VmBackupSyncProvider;
+
+
+/**
+ * Sets the current asynchronous operation being monitored, and an
+ * optional callback for after it's done executing. If the operation
+ * is NULL, the callback is set to execute later (currently, later = 200ms).
+ *
+ * @param[in] state The backup state.
+ * @param[in] op The current op to set.
+ * @param[in] callback Function to call after the operation is finished.
+ * @param[in] currentOpName Operation name, for debugging.
+ *
+ * @return TRUE if @a op is not NULL.
+ */
+
+static INLINE Bool
+VmBackup_SetCurrentOp(VmBackupState *state,
+ VmBackupOp *op,
+ VmBackupCallback callback,
+ const char *currentOpName)
+{
+ ASSERT(state != NULL);
+ ASSERT(state->currentOp == NULL);
+ state->currentOp = op;
+ state->callback = callback;
+ state->currentOpName = currentOpName;
+ state->forceRequeue = (callback != NULL && state->currentOp == NULL);
+ return (op != NULL);
+}
+
+
+/**
+ * Convenience function to call the operation-specific query function.
+ *
+ * @param[in] op The backup op.
+ *
+ * @return The operation's status.
+ */
+
+static INLINE VmBackupOpStatus
+VmBackup_QueryStatus(VmBackupOp *op)
+{
+ ASSERT(op != NULL);
+ return op->queryFn(op);
+}
+
+
+/**
+ * Convenience function to call the operation-specific cancel function.
+ * Code calling this function should still call VmBackup_QueryStatus()
+ * waiting for it to return a finished status (i.e., something other
+ * than VMBACKUP_STATUS_PENDING).
+ *
+ * @param[in] op The backup op.
+ */
+
+static INLINE void
+VmBackup_Cancel(VmBackupOp *op)
+{
+ ASSERT(op != NULL);
+ op->cancelFn(op);
+}
+
+
+/**
+ * Convenience function to call the operation-specific release function.
+ * Releasing a state object that hasn't finished yet (i.e.,
+ * VmBackup_QueryStatus returns VMBACKUP_STATUS_PENDING) can result in
+ * undefined behavior.
+ *
+ * @param[in] op The backup op.
+ */
+
+static INLINE void
+VmBackup_Release(VmBackupOp *op)
+{
+ ASSERT(op != NULL);
+ op->releaseFn(op);
+}
+
+
+VmBackupSyncProvider *
+VmBackup_NewSyncDriverProvider(void);
+
+#if defined(G_PLATFORM_WIN32)
+VmBackupSyncProvider *
+VmBackup_NewVssProvider(void);
+#endif
+
+VmBackupOp *
+VmBackup_NewScriptOp(VmBackupScriptType freeze,
+ VmBackupState *state);
+
+Bool
+VmBackup_SendEvent(const char *event,
+ const uint32 code,
+ const char *desc);
+
+#endif /* _VMBACKUPINT_H_*/
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+bin_PROGRAMS = vmtoolsd
+
+vmtoolsd_CPPFLAGS =
+vmtoolsd_CPPFLAGS += @VMTOOLS_CPPFLAGS@
+vmtoolsd_CPPFLAGS += @GMODULE_CPPFLAGS@
+vmtoolsd_CPPFLAGS += @GOBJECT_CPPFLAGS@
+vmtoolsd_CPPFLAGS += @GTHREAD_CPPFLAGS@
+vmtoolsd_CPPFLAGS += -I$(builddir)
+
+vmtoolsd_LDADD =
+vmtoolsd_LDADD += @VMTOOLS_LIBS@
+vmtoolsd_LDADD += @GMODULE_LIBS@
+vmtoolsd_LDADD += @GOBJECT_LIBS@
+vmtoolsd_LDADD += @GTHREAD_LIBS@
+
+vmtoolsd_SOURCES =
+vmtoolsd_SOURCES += cmdLine.c
+vmtoolsd_SOURCES += mainLoop.c
+vmtoolsd_SOURCES += mainPosix.c
+vmtoolsd_SOURCES += pluginMgr.c
+vmtoolsd_SOURCES += serviceObj.c
+vmtoolsd_SOURCES += toolsRpc.c
+vmtoolsd_SOURCES += svcSignals.c
+
+BUILT_SOURCES =
+BUILT_SOURCES += svcSignals.c
+BUILT_SOURCES += svcSignals.h
+
+CLEANFILES =
+CLEANFILES += svcSignals.c
+CLEANFILES += svcSignals.h
+
+EXTRA_DIST =
+EXTRA_DIST += svcSignals.gm
+
+svcSignals.c: $(top_srcdir)/services/vmtoolsd/svcSignals.gm
+ glib-genmarshal --body $(top_srcdir)/services/vmtoolsd/svcSignals.gm > \
+ $@ || (rm -f $@ && exit 1)
+
+svcSignals.h: $(top_srcdir)/services/vmtoolsd/svcSignals.gm
+ glib-genmarshal --header $(top_srcdir)/services/vmtoolsd/svcSignals.gm > \
+ $@ || (rm -f $@ && exit 1)
+
+if HAVE_ICU
+ vmtoolsd_LDADD += @ICU_LIBS@
+ vmtoolsd_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXX) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+else
+ vmtoolsd_LINK = $(LINK)
+endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file cmdLine.c
+ *
+ * Parses the daemon's command line arguments. Some commands may cause the
+ * process to exit.
+ */
+
+#include "toolsCoreInt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if !defined(G_PLATFORM_WIN32)
+# include <unistd.h>
+#endif
+#include <glib/gi18n.h>
+
+#include "conf.h"
+#include "rpcout.h"
+#include "str.h"
+#include "vmtools.h"
+#include "vmtoolsd_version.h"
+
+
+/**
+ * Runs the given Tools RPC command, printing the result to the terminal and
+ * exiting the application afterwards.
+ *
+ * @param[in] option Unused.
+ * @param[in] value RPC command.
+ * @param[in] data Unused.
+ * @param[out] error Unused.
+ *
+ * @return This function doesn't return.
+ */
+
+static gboolean
+ToolsCoreRunCommand(const gchar *option,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ char *result = NULL;
+ Bool status = FALSE;
+
+ status = RpcOut_sendOne(&result, NULL, "%s", value);
+
+ if (!status) {
+ g_printerr("%s\n", result ? result : "NULL");
+ } else {
+ g_print("%s\n", result);
+ }
+
+ vm_free(result);
+ exit(status ? 0 : 1);
+}
+
+
+#if defined(G_PLATFORM_WIN32)
+
+/**
+ * Function used to ignore command line arguments.
+ *
+ * @param[in] option Unused.
+ * @param[in] value Unused.
+ * @param[in] data Unused.
+ * @param[out] error Unused.
+ *
+ * @return TRUE
+ */
+
+static gboolean
+ToolsCoreIgnoreArg(const gchar *option,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ return TRUE;
+}
+
+
+/**
+ * Asks a running instance of a service to stop running.
+ *
+ * @param[in] svcname Name of the service to be killed.
+ *
+ * @return Whether killing the service was successful.
+ */
+
+static gboolean
+ToolsCoreKillService(const gchar *svcname)
+{
+ gboolean ret = FALSE;
+ gchar *msg;
+ wchar_t *evt;
+ HANDLE h = NULL;
+
+ g_assert(svcname != NULL);
+
+ evt = Str_Aswprintf(NULL, QUIT_EVENT_NAME_FMT, svcname);
+ if (evt == NULL) {
+ g_printerr("Out of memory!\n");
+ goto exit;
+ }
+
+ h = OpenEvent(EVENT_MODIFY_STATE, FALSE, evt);
+ if (h == NULL) {
+ goto error;
+ }
+
+ if (!SetEvent(h)) {
+ goto error;
+ }
+
+ ret = TRUE;
+ goto exit;
+
+error:
+ msg = g_win32_error_message(GetLastError());
+ g_printerr("Cannot open quit event: %s\n", msg);
+ g_free(msg);
+
+exit:
+ vm_free(evt);
+ CloseHandle(h);
+ return ret;
+}
+
+#endif
+
+
+/**
+ * Parses the command line. For a list of available options, look at the source
+ * below, where the option array is declared.
+ *
+ * @param[out] state Parsed options will be placed in this struct.
+ * @param[in] argc Argument count.
+ * @param[in] argv Argument array.
+ *
+ * @return TRUE on success.
+ */
+
+gboolean
+ToolsCore_ParseCommandLine(ToolsServiceState *state,
+ int argc,
+ char *argv[])
+{
+ gboolean ret = FALSE;
+ gboolean version = FALSE;
+#if defined(G_PLATFORM_WIN32)
+ gboolean kill = FALSE;
+#endif
+ GOptionEntry clOptions[] = {
+ { "name", 'n', 0, G_OPTION_ARG_STRING, &state->name,
+ N_("Name of the service being started."), N_("svcname") },
+ { "plugin-path", 'p', 0, G_OPTION_ARG_FILENAME, &state->pluginPath,
+ N_("Path to the plugin directory."), N_("path") },
+ { "cmd", '\0', 0, G_OPTION_ARG_CALLBACK, ToolsCoreRunCommand,
+ N_("Sends an RPC command to the host and exits."), N_("command") },
+#if defined(G_PLATFORM_WIN32)
+ { "kill", 'k', 0, G_OPTION_ARG_NONE, &kill,
+ N_("Stops a running instance of a tools service."), 0 },
+ { "install", 'i', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, ToolsCoreIgnoreArg,
+ N_("Installs the service with the Service Control Manager."), N_("args") },
+ { "uninstall", 'u', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, ToolsCoreIgnoreArg,
+ N_("Uninstalls the service from the Service Control Manager."), NULL },
+ { "displayname", 'd', 0, G_OPTION_ARG_STRING, &state->displayName,
+ N_("Service display name (only used with -i)."), N_("name") },
+#else
+ { "background", 'b', 0, G_OPTION_ARG_FILENAME, &state->pidFile,
+ N_("Runs in the background and creates a pid file."), N_("pidfile") },
+ { "blockFd", '\0', 0, G_OPTION_ARG_INT, &state->ctx.blockFD,
+ N_("File descriptor for the VMware blocking fs."), N_("fd") },
+#endif
+ { "config", 'c', 0, G_OPTION_ARG_FILENAME, &state->configFile,
+ N_("Uses the config file at the given path."), N_("path") },
+ { "debug", 'g', 0, G_OPTION_ARG_FILENAME, &state->debugPlugin,
+ N_("Runs in debug mode, using the given plugin."), N_("path") },
+ { "log", 'l', 0, G_OPTION_ARG_NONE, &state->log,
+ N_("Turns on logging. Overrides the config file."), NULL },
+ { "version", 'v', 0, G_OPTION_ARG_NONE, &version,
+ N_("Prints the daemon version and exits."), NULL },
+ { NULL }
+ };
+ GError *error = NULL;
+ GOptionContext *context = NULL;
+
+#if !defined(G_PLATFORM_WIN32)
+ state->ctx.blockFD = -1;
+#endif
+
+ context = g_option_context_new(NULL);
+#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 12
+ g_option_context_set_summary(context, N_("Runs the VMware Tools daemon."));
+#endif
+ g_option_context_add_main_entries(context, clOptions, NULL);
+
+ if (!g_option_context_parse(context, &argc, &argv, &error)) {
+ g_print("%s: %s\n", N_("Command line parsing failed"), error->message);
+ goto exit;
+ }
+
+ if (version) {
+ g_print("%s %s\n", _("VMware Tools daemon, version"), VMTOOLSD_VERSION_STRING);
+ exit(0);
+ }
+
+ VMTools_EnableLogging(state->log);
+ if (state->name == NULL) {
+ state->name = VMTOOLS_GUEST_SERVICE;
+ state->mainService = TRUE;
+ } else {
+ state->mainService = (strcmp(state->name, VMTOOLS_GUEST_SERVICE) == 0);
+ }
+
+#if defined(G_PLATFORM_WIN32)
+ if (kill) {
+ exit(ToolsCoreKillService(state->name) ? 0 : 1);
+ }
+#else
+ /* If not running the "vmusr" service, ignore the blockFd parameter. */
+ if (strcmp(state->name, VMTOOLS_USER_SERVICE) != 0) {
+ if (state->ctx.blockFD >= 0) {
+ close(state->ctx.blockFD);
+ }
+ state->ctx.blockFD = -1;
+ }
+#endif
+
+ ret = TRUE;
+
+exit:
+ g_clear_error(&error);
+ g_option_context_free(context);
+ return ret;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file mainLoop.c
+ *
+ * Functions for running the tools service's main loop.
+ */
+
+#if defined(_WIN32)
+# define MODULE_NAME(x) #x ".dll"
+#elif defined(__APPLE__)
+# define MODULE_NAME(x) "lib" #x ".dylib"
+#else
+# define MODULE_NAME(x) "lib" #x ".so"
+#endif
+
+#include <stdlib.h>
+#include "toolsCoreInt.h"
+#include "conf.h"
+#include "guestApp.h"
+#include "serviceObj.h"
+#include "util.h"
+#include "vm_app.h"
+#include "vmcheck.h"
+#include "vmtools.h"
+
+
+/**
+ * Loads the debug library and calls its initialization function. This function
+ * panics is something goes wrong.
+ *
+ * @param[in] state Service state.
+ */
+
+static void
+ToolsCoreInitializeDebug(ToolsServiceState *state)
+{
+ RpcDebugLibData *libdata;
+ RpcDebugInitializeFn initFn;
+
+ state->debugLib = g_module_open(MODULE_NAME(vmrpcdbg), G_MODULE_BIND_LOCAL);
+ if (state->debugLib == NULL) {
+ g_error("Cannot load vmrpcdbg library.\n");
+ }
+
+ if (!g_module_symbol(state->debugLib,
+ "RpcDebug_Initialize",
+ (gpointer *) &initFn)) {
+ g_error("Cannot find symbol: RpcDebug_Initialize\n");
+ }
+
+ libdata = initFn(&state->ctx, state->debugPlugin);
+ g_assert(libdata != NULL);
+ g_assert(libdata->debugPlugin != NULL);
+
+ state->debugData = libdata;
+}
+
+
+/**
+ * Cleans up the main loop after it has executed. After this function
+ * returns, the fields of the state object shouldn't be used anymore.
+ *
+ * @param[in] state Service state.
+ */
+
+void
+ToolsCore_Cleanup(ToolsServiceState *state)
+{
+ ToolsCore_UnloadPlugins(state);
+ if (state->ctx.rpc != NULL) {
+ RpcChannel_Destroy(state->ctx.rpc);
+ state->ctx.rpc = NULL;
+ }
+ g_key_file_free(state->ctx.config);
+ g_main_loop_unref(state->ctx.mainLoop);
+
+#if defined(G_PLATFORM_WIN32)
+ if (state->ctx.comInitialized) {
+ CoUninitialize();
+ state->ctx.comInitialized = FALSE;
+ }
+#endif
+
+ if (state->debugData != NULL) {
+ state->debugData->shutdown(&state->ctx, state->debugData);
+ g_module_close(state->debugLib);
+ state->debugData = NULL;
+ state->debugLib = NULL;
+ }
+
+ g_object_unref(state->ctx.serviceObj);
+ state->ctx.serviceObj = NULL;
+ state->ctx.config = NULL;
+ state->ctx.mainLoop = NULL;
+}
+
+
+/**
+ * Returns the name of the TCLO app name. This will only return non-NULL
+ * if the service is either the tools "guestd" or "userd" service.
+ *
+ * @param[in] state The service state.
+ *
+ * @return The app name, or NULL if not running a known TCLO app.
+ */
+
+const char *
+ToolsCore_GetTcloName(ToolsServiceState *state)
+{
+ if (state->mainService) {
+ return TOOLS_DAEMON_NAME;
+ } else if (strcmp(state->name, VMTOOLS_USER_SERVICE) == 0) {
+ return TOOLS_DND_NAME;
+ } else {
+ return NULL;
+ }
+}
+
+
+/**
+ * Performs any initial setup steps for the service's main loop.
+ *
+ * @param[in] state Service state.
+ *
+ * @return Whether initialization was successful.
+ */
+
+gboolean
+ToolsCore_Setup(ToolsServiceState *state)
+{
+ GMainContext *gctx;
+ char *confFile = state->configFile;
+
+ if (confFile == NULL) {
+ confFile = VMTools_GetToolsConfFile();
+ }
+
+ if (!g_thread_supported()) {
+ g_thread_init(NULL);
+ }
+
+ VMTools_SetDefaultLogDomain(state->name);
+
+ /* Load the tools config file. */
+ if (confFile != NULL) {
+ state->ctx.config = VMTools_LoadConfig(confFile,
+ G_KEY_FILE_NONE,
+ state->mainService);
+ if (state->ctx.config == NULL) {
+ /* Couldn't load the config file. Just create an empty dictionary. */
+ state->ctx.config = g_key_file_new();
+ }
+ }
+
+ VMTools_ConfigLogging(state->ctx.config);
+ if (state->log) {
+ VMTools_EnableLogging(state->log);
+ }
+
+ /* Initializes the app context. */
+ gctx = g_main_context_default();
+ state->ctx.name = state->name;
+ state->ctx.errorCode = EXIT_SUCCESS;
+ state->ctx.mainLoop = g_main_loop_new(gctx, TRUE);
+ state->ctx.isVMware = VmCheck_IsVirtualWorld();
+
+ g_type_init();
+ state->ctx.serviceObj = g_object_new(TOOLSCORE_TYPE_SERVICE, NULL);
+
+ /* Initializes the debug library if needed. */
+ if (state->debugPlugin != NULL) {
+ ToolsCoreInitializeDebug(state);
+ }
+
+ /* Initialize the RpcIn channel for the known tools services. */
+ if (ToolsCore_GetTcloName(state) != NULL &&
+ !ToolsCore_InitRpc(state)) {
+ goto error;
+ }
+
+ if (!state->ctx.rpc->start(state->ctx.rpc)) {
+ goto error;
+ }
+
+ if (!ToolsCore_LoadPlugins(state)) {
+ goto error;
+ }
+
+ ToolsCore_RegisterPlugins(state);
+ goto exit;
+
+error:
+ if (state->ctx.rpc != NULL) {
+ state->ctx.rpc->shutdown(state->ctx.rpc);
+ state->ctx.rpc = NULL;
+ }
+ if (state->ctx.mainLoop != NULL) {
+ g_main_loop_unref(state->ctx.mainLoop);
+ state->ctx.mainLoop = NULL;
+ }
+
+exit:
+ if (state->configFile == NULL) {
+ g_free(confFile);
+ }
+ return (state->ctx.mainLoop != NULL);
+}
+
+
+/**
+ * Runs the service's main loop.
+ *
+ * @param[in] state Service state.
+ *
+ * @return Exit code.
+ */
+
+int
+ToolsCore_Run(ToolsServiceState *state)
+{
+#if defined(__APPLE__)
+ ToolsCore_CFRunLoop(state);
+#else
+ g_main_loop_run(state->ctx.mainLoop);
+#endif
+ return state->ctx.errorCode;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file mainPosix.c
+ *
+ * Service entry point for the POSIX version of the tools daemon.
+ */
+
+
+#include "toolsCoreInt.h"
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <glib/gstdio.h>
+#include "system.h"
+#include "unicode.h"
+#include "vmtools.h"
+
+#if !defined(__APPLE__)
+#include "embed_version.h"
+#include "vmtoolsd_version.h"
+VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
+#endif
+
+static ToolsServiceState gState = { NULL, };
+
+/**
+ * Handles a signal that would terminate the process. Asks the main loop
+ * to exit nicely.
+ *
+ * @param[in] info Unused.
+ * @param[in] data Pointer to the main loop to be stopped.
+ *
+ * @return FALSE
+ */
+
+gboolean
+ToolsCoreSigHandler(const siginfo_t *info,
+ gpointer data)
+{
+ g_main_loop_quit((GMainLoop *)data);
+ return FALSE;
+}
+
+
+/**
+ * Tools daemon entry function.
+ *
+ * @param[in] argc Argument count.
+ * @param[in] argv Argument array.
+ *
+ * @return 0 on successful execution, error code otherwise.
+ */
+
+int
+main(int argc,
+ char *argv[])
+{
+ int ret = EXIT_FAILURE;
+ GSource *src;
+
+ Unicode_Init(argc, &argv, NULL);
+
+ if (!ToolsCore_ParseCommandLine(&gState, argc, argv)) {
+ goto exit;
+ }
+
+ if (!ToolsCore_Setup(&gState)) {
+ goto exit;
+ }
+
+ src = VMTools_NewSignalSource(SIGHUP);
+ VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src,
+ ToolsCoreSigHandler, gState.ctx.mainLoop, NULL);
+ g_source_unref(src);
+
+ src = VMTools_NewSignalSource(SIGINT);
+ VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src,
+ ToolsCoreSigHandler, gState.ctx.mainLoop, NULL);
+ g_source_unref(src);
+
+ src = VMTools_NewSignalSource(SIGQUIT);
+ VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src,
+ ToolsCoreSigHandler, gState.ctx.mainLoop, NULL);
+ g_source_unref(src);
+
+ src = VMTools_NewSignalSource(SIGTERM);
+ VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src,
+ ToolsCoreSigHandler, gState.ctx.mainLoop, NULL);
+ g_source_unref(src);
+
+ if (gState.pidFile != NULL &&
+ !System_Daemon(FALSE, FALSE, gState.pidFile)) {
+ goto exit;
+ }
+
+ ret = ToolsCore_Run(&gState);
+
+ ToolsCore_Cleanup(&gState);
+
+ if (gState.pidFile != NULL) {
+ g_unlink(gState.pidFile);
+ }
+exit:
+ return ret;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file pluginMgr.c
+ *
+ * Provides functions for loading and manipulating Tools plugins.
+ */
+
+#include <string.h>
+#include "vm_assert.h"
+#include "guestApp.h"
+#include "toolsCoreInt.h"
+#include "util.h"
+#include "vmtools.h"
+
+
+/**
+ * Compares two strings. To be used with g_ptr_array_sort.
+ *
+ * @param[in] _str1 Pointer to string for comparison.
+ * @param[in] _str2 Pointer to string for comparison.
+ *
+ * @return Result of strcmp.
+ */
+
+static gint
+ToolsCoreStrPtrCompare(gconstpointer _str1,
+ gconstpointer _str2)
+{
+ const gchar *str1 = *((const gchar **) _str1);
+ const gchar *str2 = *((const gchar **) _str2);
+ return strcmp(str1, str2);
+}
+
+
+/**
+ * Loads all plugins present in the plugin directory. If the plugin path
+ * is NULL, then default directories are used in case the service is either
+ * the main tools service of the user daemon, otherwise failure is returned.
+ *
+ * @param[in] state The service state.
+ *
+ * @return Whether loading the plugins was successful.
+ */
+
+gboolean
+ToolsCore_LoadPlugins(ToolsServiceState *state)
+{
+ gboolean ret = FALSE;
+ const gchar *staticEntry;
+ guint i;
+ GDir *dir = NULL;
+ GError *err = NULL;
+ GPtrArray *plugins;
+
+ g_assert(g_module_supported());
+
+ if (state->pluginPath == NULL) {
+ if (state->mainService ||
+ strcmp(state->name, VMTOOLS_USER_SERVICE) == 0) {
+ char *instPath;
+ instPath = GuestApp_GetInstallPath();
+ state->pluginPath = g_strdup_printf("%s%cplugins%c%s",
+ instPath,
+ DIRSEPC,
+ DIRSEPC,
+ state->name);
+ vm_free(instPath);
+ } else {
+ g_warning("No plugin path provided for service '%s'.\n", state->name);
+ goto exit;
+ }
+ }
+
+ if (!g_file_test(state->pluginPath, G_FILE_TEST_IS_DIR)) {
+ g_warning("Plugin path is not a directory: %s\n", state->pluginPath);
+ goto exit;
+ }
+
+ dir = g_dir_open(state->pluginPath, 0, &err);
+ if (dir == NULL) {
+ g_warning("Error opening dir: %s\n", err->message);
+ goto exit;
+ }
+
+ plugins = g_ptr_array_new();
+
+ /*
+ * Load plugins in alphabetical order, so the load order is the same
+ * regardless of how the filesystem returns entries.
+ */
+ while ((staticEntry = g_dir_read_name(dir)) != NULL) {
+ g_ptr_array_add(plugins, g_strdup(staticEntry));
+ }
+
+ g_ptr_array_sort(plugins, ToolsCoreStrPtrCompare);
+
+ state->plugins = g_ptr_array_new();
+ for (i = 0; i < plugins->len; i++) {
+ gchar *entry;
+ gchar *path;
+ GModule *module = NULL;
+ ToolsPlugin *plugin = NULL;
+ ToolsPluginData *data = NULL;
+ ToolsPluginOnLoad onload;
+
+ entry = g_ptr_array_index(plugins, i);
+ path = g_strdup_printf("%s%c%s", state->pluginPath, DIRSEPC, entry);
+
+ if (!g_file_test(path, G_FILE_TEST_IS_REGULAR)) {
+ g_warning("File '%s' is not a regular file, skipping.\n", entry);
+ goto next;
+ }
+
+ module = g_module_open(path, G_MODULE_BIND_LOCAL);
+ if (module == NULL) {
+ g_warning("Opening plugin '%s' failed.\n", entry);
+ goto next;
+ }
+
+ if (!g_module_symbol(module, "ToolsOnLoad", (gpointer *) &onload)) {
+ g_warning("Lookup of plugin entry point for '%s' failed.\n", entry);
+ goto next;
+ }
+
+ if (onload != NULL) {
+ data = onload(&state->ctx);
+ }
+
+ if (data == NULL) {
+ g_message("Plugin '%s' didn't provide deployment data, unloading.\n", entry);
+ goto next;
+ }
+
+ g_assert(data->name != NULL);
+ g_module_make_resident(module);
+ plugin = g_malloc(sizeof *plugin);
+ plugin->module = module;
+ plugin->data = data;
+
+ g_ptr_array_add(state->plugins, plugin);
+ g_debug("Plugin '%s' initialized.\n", plugin->data->name);
+
+ next:
+ g_free(path);
+ if (plugin == NULL && module != NULL) {
+ if (!g_module_close(module)) {
+ g_warning("Error unloading plugin '%s': %s\n", entry, g_module_error());
+ }
+ }
+ }
+
+ for (i = 0; i < plugins->len; i++) {
+ g_free(g_ptr_array_index(plugins, i));
+ }
+ g_ptr_array_free(plugins, TRUE);
+ ret = TRUE;
+
+exit:
+ if (dir != NULL) {
+ g_dir_close(dir);
+ }
+ g_clear_error(&err);
+ return ret;
+}
+
+
+/**
+ * Registers all RPC handlers provided by the loaded and enabled plugins.
+ *
+ * @param[in] state The service state.
+ */
+
+void
+ToolsCore_RegisterPlugins(ToolsServiceState *state)
+{
+ guint i;
+
+ if (state->plugins == NULL) {
+ return;
+ }
+
+ for (i = 0; i < state->plugins->len; i++) {
+ ToolsPlugin *plugin = g_ptr_array_index(state->plugins, i);
+ GArray *regs = (plugin->data != NULL) ? plugin->data->regs : NULL;
+ guint j;
+
+ if (regs == NULL) {
+ continue;
+ }
+
+ for (j = 0; j < regs->len; j++) {
+ guint k;
+ ToolsAppReg *reg = &g_array_index(regs, ToolsAppReg, j);
+
+ switch (reg->type) {
+ case TOOLS_APP_GUESTRPC:
+ ASSERT(reg->data != NULL);
+ if (state->ctx.rpc == NULL) {
+ g_warning("Plugin '%s' asked to register a Guest RPC handler, "
+ "but there's no RPC channel.\n", plugin->data->name);
+ } else {
+ for (k = 0; k < reg->data->len; k++) {
+ RpcChannelCallback *cb = &g_array_index(reg->data,
+ RpcChannelCallback,
+ k);
+ RpcChannel_RegisterCallback(state->ctx.rpc, cb);
+ }
+ }
+ break;
+
+ case TOOLS_APP_SIGNALS:
+ ASSERT(reg->data != NULL);
+ for (k = 0; k < reg->data->len; k++) {
+ ToolsPluginSignalCb *sig = &g_array_index(reg->data,
+ ToolsPluginSignalCb,
+ k);
+ g_signal_connect(state->ctx.serviceObj,
+ sig->signame,
+ sig->callback,
+ sig->clientData);
+ }
+ break;
+
+ default:
+ NOT_IMPLEMENTED();
+ }
+ }
+ }
+}
+
+
+/**
+ * Calls the shutdown callback for all loaded plugins, and cleans up the list
+ * of loaded plugins. Plugins are unloaded in the opposite order they were
+ * loaded.
+ *
+ * Note that if a plugin does not provide a shutdown callback, it may leak
+ * data that may have been dynamically allocated in the plugin registration
+ * info. Since this function is intended to be called once during service
+ * shutdown, this it not that big of a deal.
+ *
+ * @param[in] state The service state.
+ */
+
+void
+ToolsCore_UnloadPlugins(ToolsServiceState *state)
+{
+ GArray *pcaps = NULL;
+
+ if (state->plugins == NULL) {
+ return;
+ }
+
+ g_signal_emit_by_name(state->ctx.serviceObj,
+ TOOLS_CORE_SIG_CAPABILITIES,
+ &state->ctx,
+ FALSE,
+ &pcaps);
+
+ if (pcaps != NULL) {
+ ToolsCore_SetCapabilities(state->ctx.rpc, pcaps, FALSE);
+ g_array_free(pcaps, TRUE);
+ }
+
+ g_signal_emit_by_name(state->ctx.serviceObj, TOOLS_CORE_SIG_SHUTDOWN, &state->ctx);
+
+ while (state->plugins->len > 0) {
+ ToolsPlugin *plugin = g_ptr_array_index(state->plugins, state->plugins->len - 1);
+ GArray *regs = (plugin->data != NULL) ? plugin->data->regs : NULL;
+
+ g_debug("Unloading plugin '%s'.\n", plugin->data->name);
+
+ if (regs != NULL) {
+ guint i;
+ for (i = 0; i < regs->len; i++) {
+ ToolsAppReg *reg = &g_array_index(regs, ToolsAppReg, i);
+ if (reg->data != NULL) {
+ g_array_free(reg->data, TRUE);
+ }
+ }
+ g_array_free(regs, TRUE);
+ }
+
+ g_ptr_array_remove_index(state->plugins, state->plugins->len - 1);
+ g_module_close(plugin->module);
+ g_free(plugin);
+ }
+
+ g_ptr_array_free(state->plugins, TRUE);
+ state->plugins = NULL;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file serviceObj.c
+ *
+ * Implementation of the "ToolsCore_Service" gobject.
+ */
+
+#include "toolsCoreInt.h"
+#include "serviceObj.h"
+#include "svcSignals.h"
+#include "vmtoolsApp.h"
+
+
+/**
+ * Accumulator function for the "set option" signal. If a handler returns
+ * TRUE, sets the result of the signal propagation to TRUE.
+ *
+ * @param[in] ihint Unused.
+ * @param[out] retval Return value of the signal.
+ * @param[in] handlerRet Return value from the current handler.
+ * @param[in] data Unused.
+ *
+ * @return TRUE
+ */
+
+static gboolean
+ToolsCoreSetOptionAccumulator(GSignalInvocationHint *ihint,
+ GValue *retval,
+ const GValue *handlerRet,
+ gpointer data)
+{
+ if (!g_value_get_boolean(retval)) {
+ g_value_set_boolean(retval, g_value_get_boolean(handlerRet));
+ }
+ return TRUE;
+}
+
+
+/**
+ * Accumulator function for the "capabilities" signal. Just puts the contents
+ * of all returned GArray instances into a "master" instance.
+ *
+ * @param[in] ihint Unused.
+ * @param[out] retval Return value of the signal.
+ * @param[in] handlerRet Return value from the current handler.
+ * @param[in] data Unused.
+ *
+ * @return TRUE.
+ */
+
+static gboolean
+ToolsCoreCapabilitiesAccumulator(GSignalInvocationHint *ihint,
+ GValue *retval,
+ const GValue *handlerRet,
+ gpointer data)
+{
+ GArray *caps = g_value_get_pointer(handlerRet);
+
+ if (caps != NULL) {
+ guint i;
+ GArray *acc = g_value_get_pointer(retval);
+
+ if (acc == NULL) {
+ acc = g_array_new(FALSE, TRUE, sizeof (ToolsAppCapability));
+ g_value_set_pointer(retval, acc);
+ }
+
+ for (i = 0; i < caps->len; i++) {
+ g_array_append_val(acc, g_array_index(caps, ToolsAppCapability, i));
+ }
+
+ g_array_free(caps, TRUE);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * Initializes the ToolsCoreService class. Sets up the signals that are sent
+ * by the vmtoolsd service.
+ *
+ * @param[in] klass The class instance to initialize.
+ */
+
+static void
+ToolsCore_Service_class_init(gpointer _klass,
+ gpointer klassData)
+{
+ ToolsCoreServiceClass *klass = _klass;
+ g_signal_new(TOOLS_CORE_SIG_CAPABILITIES,
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ ToolsCoreCapabilitiesAccumulator,
+ NULL,
+ g_cclosure_user_marshal_POINTER__POINTER_BOOLEAN,
+ G_TYPE_POINTER,
+ 2,
+ G_TYPE_POINTER,
+ G_TYPE_BOOLEAN);
+ g_signal_new(TOOLS_CORE_SIG_RESET,
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+ g_signal_new(TOOLS_CORE_SIG_SET_OPTION,
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ ToolsCoreSetOptionAccumulator,
+ NULL,
+ g_cclosure_user_marshal_BOOLEAN__POINTER_STRING_STRING,
+ G_TYPE_BOOLEAN,
+ 3,
+ G_TYPE_POINTER,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+ g_signal_new(TOOLS_CORE_SIG_SHUTDOWN,
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+#if defined(G_PLATFORM_WIN32)
+ g_signal_new(TOOLS_CORE_SIG_SESSION_CHANGE,
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_user_marshal_VOID__POINTER_UINT_UINT,
+ G_TYPE_NONE,
+ 3,
+ G_TYPE_POINTER,
+ G_TYPE_UINT,
+ G_TYPE_UINT);
+#endif
+}
+
+
+/**
+ * Initializes the ToolsCoreService type if it hasn't been done yet, and
+ * return the type instance. This method is not thread safe.
+ *
+ * @return The ToolsCoreService type.
+ */
+
+GType
+ToolsCore_Service_get_type(void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ sizeof (ToolsCoreServiceClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ ToolsCore_Service_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (ToolsCoreService),
+ 0, /* n_preallocs */
+ NULL, /* instance_init */
+ };
+ type = g_type_register_static(G_TYPE_OBJECT,
+ "ToolsCoreService",
+ &info,
+ 0);
+ }
+ return type;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _SERVICEOBJ_H_
+#define _SERVICEOBJ_H_
+
+/**
+ * @file serviceObj.h
+ *
+ * Interface of the "core service" object. This interface is not really
+ * public, just the type itself, so that plugins can provide their own
+ * signals for communicating with other plugins in the same process. For
+ * this reason, it doesn't provide all the GObject boilerplate macros.
+ */
+
+#include <glib-object.h>
+#include "vmtoolsApp.h"
+
+#define TOOLSCORE_TYPE_SERVICE ToolsCore_Service_get_type()
+
+typedef struct ToolsCoreService {
+ GObject parent;
+} ToolsCoreService;
+
+typedef struct ToolsCoreServiceClass {
+ GObjectClass parentClass;
+} ToolsCoreServiceClass;
+
+GType
+ToolsCore_Service_get_type(void);
+
+#endif /* _SERVICEOBJ_H_ */
+
--- /dev/null
+##########################################################
+# Copyright (C) 2009 VMware, Inc. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation version 2.1 and no later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+# License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+##########################################################
+
+##
+# @file svcSignals.gm
+#
+# Defines the custom GClosure marshal functions for the core services signals.
+#
+# @see vmtoolsApp.h
+#
+
+# The "capabilities" signal.
+POINTER:POINTER,BOOLEAN
+
+# The "set option" signal.
+BOOLEAN:POINTER,STRING,STRING
+
+# The "session change" signal.
+# Used on Win32 only.
+VOID:POINTER,UINT,UINT
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _TOOLSCOREINT_H_
+#define _TOOLSCOREINT_H_
+
+/**
+ * @file toolsCoreInt.h
+ *
+ * Internal functions for the tools daemon.
+ */
+
+#define G_LOG_DOMAIN "vmtoolsd"
+
+#include <glib-object.h>
+#include <gmodule.h>
+#include "vmrpcdbg.h"
+#include "vmtoolsApp.h"
+
+/* Used by the Windows implementation to communicate with other processes. */
+#if defined(G_PLATFORM_WIN32)
+# define QUIT_EVENT_NAME_FMT L"Global\\VMwareToolsQuitEvent_%s"
+#endif
+
+/** Defines the internal data about a plugin. */
+typedef struct ToolsPlugin {
+ GModule *module;
+ ToolsPluginData *data;
+} ToolsPlugin;
+
+/** Defines internal service state. */
+typedef struct ToolsServiceState {
+ gchar *name;
+ gchar *configFile;
+ gboolean log;
+ gboolean mainService;
+ gchar *pluginPath;
+ GPtrArray *plugins;
+#if defined(_WIN32)
+ gchar *displayName;
+#else
+ gchar *pidFile;
+#endif
+ GModule *debugLib;
+ gchar *debugPlugin;
+ RpcDebugLibData *debugData;
+ ToolsAppCtx ctx;
+} ToolsServiceState;
+
+
+gboolean
+ToolsCore_ParseCommandLine(ToolsServiceState *state,
+ int argc,
+ char *argv[]);
+
+void
+ToolsCore_Cleanup(ToolsServiceState *state);
+
+const char *
+ToolsCore_GetTcloName(ToolsServiceState *state);
+
+int
+ToolsCore_Run(ToolsServiceState *state);
+
+gboolean
+ToolsCore_Setup(ToolsServiceState *state);
+
+gboolean
+ToolsCore_InitRpc(ToolsServiceState *state);
+
+gboolean
+ToolsCore_LoadPlugins(ToolsServiceState *state);
+
+void
+ToolsCore_RegisterPlugins(ToolsServiceState *state);
+
+void
+ToolsCore_SetCapabilities(RpcChannel *chan,
+ GArray *caps,
+ gboolean set);
+
+void
+ToolsCore_UnloadPlugins(ToolsServiceState *state);
+
+#if defined(__APPLE__)
+void
+ToolsCore_CFRunLoop(ToolsServiceState *state);
+#endif
+
+#endif /* _TOOLSCOREINT_H_ */
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file toolsRpc.c
+ *
+ * Functions related to the GuestRPC channel provided by the service.
+ * Provides the interface for the service to bring up the RPC channel,
+ * and handlers for the RPC messages which are handled by the service
+ * itself.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "vm_assert.h"
+#include "conf.h"
+#include "str.h"
+#include "strutil.h"
+#include "toolsCoreInt.h"
+#include "vmtools.h"
+#include "vm_tools_version.h"
+
+
+/**
+ * Take action after an RPC channel reset.
+ *
+ * @param[in] chan The RPC channel.
+ * @param[in] success Whether reset was successful.
+ * @param[in] _state The service state.
+ */
+
+static void
+ToolsCoreCheckReset(struct RpcChannel *chan,
+ gboolean success,
+ gpointer _state)
+{
+ ToolsServiceState *state = _state;
+
+ ASSERT(state != NULL);
+
+ if (success) {
+ const gchar *app;
+ gchar *msg;
+
+ app = ToolsCore_GetTcloName(state);
+ g_assert(app != NULL);
+
+ msg = g_strdup_printf("vmx.capability.unified_loop %s", app);
+ if (!RpcChannel_Send(state->ctx.rpc, msg, strlen(msg) + 1, NULL, NULL)) {
+ g_warning("VMX doesn't support the Tools unified loop.\n"
+ "Some functionality (like setting options) may not work.\n");
+ }
+ g_free(msg);
+
+ g_signal_emit_by_name(state->ctx.serviceObj,
+ TOOLS_CORE_SIG_RESET,
+ &state->ctx);
+ } else {
+ VMTOOLSAPP_ERROR(&state->ctx, EXIT_FAILURE);
+ }
+}
+
+
+/**
+ * Checks all loaded plugins for their capabilities, and sends the data to the
+ * host. The code will try to send all capabilities, just logging errors as
+ * they occur.
+ *
+ * @param[in] data The RPC data.
+ *
+ * @return TRUE.
+ */
+
+static Bool
+ToolsCoreRpcCapReg(RpcInData *data)
+{
+ GArray *pcaps = NULL;
+ ToolsServiceState *state = data->clientData;
+
+ g_signal_emit_by_name(state->ctx.serviceObj,
+ TOOLS_CORE_SIG_CAPABILITIES,
+ &state->ctx,
+ TRUE,
+ &pcaps);
+
+ if (pcaps != NULL) {
+ ToolsCore_SetCapabilities(state->ctx.rpc, pcaps, TRUE);
+ g_array_free(pcaps, TRUE);
+ }
+
+ /* Send the tools version to the VMX. */
+ if (state->mainService) {
+ char *result = NULL;
+ size_t resultLen;
+ gboolean disableVersion;
+ gchar *toolsVersion;
+ GError *err = NULL;
+
+ disableVersion = g_key_file_get_boolean(state->ctx.config,
+ "vmtools",
+ CONFNAME_DISABLETOOLSVERSION,
+ &err);
+ g_clear_error(&err);
+ toolsVersion = g_strdup_printf("tools.set.version %u",
+ disableVersion ? TOOLS_VERSION_UNMANAGED
+ : TOOLS_VERSION_CURRENT);
+
+ if (!RpcChannel_Send(state->ctx.rpc, toolsVersion, strlen(toolsVersion) + 1,
+ &result, &resultLen)) {
+ g_debug("Error setting tools version: %s.\n", result);
+ }
+ vm_free(result);
+ g_free(toolsVersion);
+ }
+
+ return RPCIN_SETRETVALS(data, "", TRUE);
+}
+
+
+/**
+ * Handles a "set option" RPC. Calls the plugins which have registered interest
+ * in the option being set.
+ *
+ * @param[in] data The RPC data.
+ *
+ * @return TRUE.
+ */
+
+static Bool
+ToolsCoreRpcSetOption(RpcInData *data)
+{
+
+ gboolean retVal = FALSE;
+ char *option;
+ char *value;
+ unsigned int index = 0;
+ ToolsServiceState *state = data->clientData;
+
+ /* Parse the option & value string. */
+ option = StrUtil_GetNextToken(&index, data->args, " ");
+ /* Ignore leading space before value. */
+ index++;
+ value = StrUtil_GetNextToken(&index, data->args, "");
+
+ if (option == NULL || value == NULL || strlen(value) == 0) {
+ goto exit;
+ }
+
+ g_debug("Setting option '%s' to '%s'.\n", option, value);
+ g_key_file_set_string(state->ctx.config, state->ctx.name, option, value);
+
+ g_signal_emit_by_name(state->ctx.serviceObj,
+ TOOLS_CORE_SIG_SET_OPTION,
+ &state->ctx,
+ option,
+ value,
+ &retVal);
+
+exit:
+ vm_free(option);
+ vm_free(value);
+ if (retVal) {
+ RPCIN_SETRETVALS(data, "", retVal);
+ } else {
+ RPCIN_SETRETVALS(data, "Unknown or invalid option", retVal);
+ }
+ return (Bool) retVal;
+}
+
+
+/**
+ * Initializes the RPC channel. Currently this instantiates an RpcIn loop.
+ * This function should only be called once.
+ *
+ * @param[in] state The service state.
+ *
+ * @return TRUE on success.
+ */
+
+gboolean
+ToolsCore_InitRpc(ToolsServiceState *state)
+{
+ static RpcChannelCallback rpcs[] = {
+ { "Capabilities_Register", ToolsCoreRpcCapReg, NULL, NULL, NULL, 0 },
+ { "Set_Option", ToolsCoreRpcSetOption, NULL, NULL, NULL, 0 },
+ };
+
+ size_t i;
+ const gchar *app;
+ GMainContext *mainCtx = g_main_loop_get_context(state->ctx.mainLoop);
+
+ g_assert(state->ctx.rpc == NULL);
+
+ if (state->debugPlugin != NULL) {
+ app = "debug";
+ state->ctx.rpc = state->debugData->newDebugChannel(&state->ctx,
+ state->debugData);
+ } else {
+ /*
+ * Currently we try to bring up an RpcIn channel, which will only run
+ * inside a Virtual Machine. We want to exit with a "success" status
+ * if this check fails, though. (See bug 297528 for why.)
+ *
+ * XXX: this should be relaxed when we try to bring up a VMCI or TCP channel.
+ */
+ if (!state->ctx.isVMware) {
+ g_warning("The %s service needs to run inside a virtual machine.\n",
+ state->name);
+ exit(0);
+ }
+
+ state->ctx.rpc = RpcChannel_NewBackdoorChannel(mainCtx);
+ app = ToolsCore_GetTcloName(state);
+ g_assert(app != NULL);
+ }
+
+ RpcChannel_Setup(state->ctx.rpc,
+ app,
+ mainCtx,
+ &state->ctx,
+ ToolsCoreCheckReset,
+ state);
+
+ /* Register the "built in" RPCs. */
+ for (i = 0; i < ARRAYSIZE(rpcs); i++) {
+ RpcChannelCallback *rpc = &rpcs[i];
+ rpc->clientData = state;
+ RpcChannel_RegisterCallback(state->ctx.rpc, rpc);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * Sends a list of capabilities to the host.
+ *
+ * @param[in] chan The RPC channel.
+ * @param[in] caps The list of capabilities.
+ * @param[in] set TRUE is setting capabilities (otherwise they're set to 0).
+ */
+
+void
+ToolsCore_SetCapabilities(RpcChannel *chan,
+ GArray *caps,
+ gboolean set)
+{
+ char *result;
+ size_t resultLen;
+ guint i;
+ gchar *newcaps = NULL;
+
+ for (i = 0; i < caps->len; i++) {
+ gchar *tmp;
+ ToolsAppCapability *cap = &g_array_index(caps, ToolsAppCapability, i);
+ switch (cap->type) {
+ case TOOLS_CAP_OLD:
+ result = NULL;
+ tmp = g_strdup_printf("tools.capability.%s %u",
+ cap->name,
+ set ? cap->value : 0);
+ if (!RpcChannel_Send(chan, tmp, strlen(tmp) + 1, &result, &resultLen)) {
+ g_warning("Error sending capability %s: %s\n", cap->name, result);
+ }
+ vm_free(result);
+ g_free(tmp);
+ break;
+
+ case TOOLS_CAP_OLD_NOVAL:
+ /*
+ * This is kind of weird, because of the way the VMX treats RPCs and
+ * what is expected of these capabilities without arguments. For a
+ * few details, see the comments in RpcOut_sendOne() (rpcout.c).
+ * Basically, for the VMX handlers not to complain, we need to send the
+ * RPC with the empty space at the end, and not consider the NULL
+ * character when counting the bytes.
+ */
+ if (set) {
+ tmp = g_strdup_printf("tools.capability.%s ", cap->name);
+ if (!RpcChannel_Send(chan, tmp, strlen(tmp), &result, &resultLen)) {
+ g_warning("Error sending capability %s: %s\n", cap->name, result);
+ }
+ vm_free(result);
+ g_free(tmp);
+ }
+ break;
+
+ case TOOLS_CAP_NEW:
+ if (newcaps == NULL) {
+ newcaps = g_strdup(GUEST_CAP_FEATURES);
+ }
+ tmp = g_strdup_printf("%s %d=%u",
+ newcaps,
+ cap->index,
+ set ? cap->value : 0);
+ g_free(newcaps);
+ newcaps = tmp;
+ break;
+
+ default:
+ g_error("Invalid capability type: %d\n", cap->type);
+ }
+ }
+
+ if (newcaps != NULL) {
+ result = NULL;
+ if (!RpcChannel_Send(chan, newcaps, strlen(newcaps) + 1, &result, &resultLen)) {
+ g_warning("Error sending new-style capabilities: %s\n", result);
+ }
+ vm_free(result);
+ g_free(newcaps);
+ }
+}
+
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+SUBDIRS =
+SUBDIRS += vmrpcdbg
+SUBDIRS += testDebug
+SUBDIRS += testPlugin
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libtestDebug.la
+
+libtestDebug_la_CPPFLAGS =
+libtestDebug_la_CPPFLAGS += @GOBJECT_CPPFLAGS@
+libtestDebug_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
+
+libtestDebug_la_LDFLAGS =
+libtestDebug_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libtestDebug_la_LIBADD =
+libtestDebug_la_LIBADD += @GOBJECT_LIBS@
+libtestDebug_la_LIBADD += @VMTOOLS_LIBS@
+libtestDebug_la_LIBADD += ../vmrpcdbg/libvmrpcdbg.la
+
+libtestDebug_la_SOURCES =
+libtestDebug_la_SOURCES += testDebug.c
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file testDebug.c
+ *
+ * A simple debug plugin that validates the messages sent by the service after
+ * a "reset" is received, and also interacts with the test plugin to test the
+ * functions provided by the service.
+ */
+
+#define G_LOG_DOMAIN "testDebug"
+#include <glib-object.h>
+#include "util.h"
+#include "vm_app.h"
+#include "vmrpcdbg.h"
+#include "vmtools.h"
+#include "guestrpc/ghiGetBinaryHandlers.h"
+
+static gboolean
+TestDebugValidateReset(RpcInData *data, Bool ret);
+
+static gboolean
+TestDebugValidateUnknown(RpcInData *data, Bool ret);
+
+#define SET_OPTION_TEST ("Set_Option " TOOLSOPTION_BROADCASTIP " 1")
+
+/** RPC messages injected into the application using RpcDebug_SendNext(). */
+static RpcDebugMsgMapping gRpcMessages[] = {
+ { "reset", sizeof "reset", TestDebugValidateReset, FALSE },
+ { "ping", sizeof "ping", NULL, FALSE },
+ { "Capabilities_Register", sizeof "Capabilities_Register", NULL, FALSE },
+ { "test.rpcin.unknown", sizeof "test.rpcin.unknown", TestDebugValidateUnknown, FALSE },
+ /* This one is initialized manually, since it contains dynamic data. */
+ { NULL, 0, NULL, TRUE },
+ { "test.rpcin.msg2", sizeof "test.rpcin.msg2", NULL, FALSE },
+ { "test.rpcin.msg3", sizeof "test.rpcin.msg3", NULL, FALSE },
+ { SET_OPTION_TEST, sizeof SET_OPTION_TEST, NULL, FALSE },
+ { "Capabilities_Register", sizeof "Capabilities_Register", NULL, FALSE },
+ /* NULL terminator. */
+ { NULL, 0, NULL, FALSE }
+};
+
+static gboolean gSignalReceived = FALSE;
+
+
+/**
+ * Handles a "test-signal" sent by the test plugin. Just sets a static variable
+ * that will be checked by TestDebugReceiveRpc1 to make sure custom signals are
+ * working.
+ *
+ * @param[in] src Unused.
+ * @param[in] data Unused.
+ */
+
+static void
+TestDebugHandleSignal(gpointer src,
+ gpointer data)
+{
+ g_debug("Received test signal.\n");
+ gSignalReceived = TRUE;
+}
+
+
+/**
+ * Validates the response from a "reset".
+ *
+ * @param[in] data RPC request data.
+ * @param[in] ret Return value from RPC handler.
+ *
+ * @return @a ret.
+ */
+
+static gboolean
+TestDebugValidateReset(RpcInData *data,
+ Bool ret)
+{
+ ToolsAppCtx *ctx = data->appCtx;
+ g_assert(data->result != NULL);
+ if (strcmp(data->result, "ATR debug") != 0) {
+ g_error("Unexpected response to reset: %s\n", data->result);
+ }
+
+ /*
+ * If reset was successful, connect the "test-signal" signal so we
+ * test custom registration of signals. The test plugin will emit
+ * this signal after it sends an "test.rpcout.msg1" RPC as part of
+ * handling a "test.rpcin.msg1" RPC.
+ */
+ g_signal_connect(ctx->serviceObj,
+ "test-signal",
+ G_CALLBACK(TestDebugHandleSignal),
+ NULL);
+
+ return (gboolean) ret;
+}
+
+
+/**
+ * Validates a "test.rpcout.msg1" message sent by the test plugin. This message
+ * is sent when the plugin receives a "test.rpcin.msg1" RPC, and contains an
+ * XDR-encoded GHIBinaryHandlersIconDetails struct.
+ *
+ * @param[in] data Incoming data.
+ * @param[in] dataLen Size of incoming data.
+ * @param[out] result Result sent back to the application.
+ * @param[out] resultLen Length of result.
+ *
+ * @return TRUE (asserts on failure).
+ */
+
+static gboolean
+TestDebugReceiveRpc1(char *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen)
+{
+ GHIBinaryHandlersIconDetails *details = (GHIBinaryHandlersIconDetails *) data;
+
+ g_assert(gSignalReceived);
+ g_assert(details->width == 100);
+ g_assert(details->height == 200);
+ g_assert(strcmp(details->identifier, "rpc1test") == 0);
+
+ g_debug("Successfully validated rpc1!\n");
+ return TRUE;
+}
+
+
+/**
+ * Validates a "version" message sent during capability registration.
+ * No validation is actually done - the message is just printed.
+ *
+ * @param[in] data Incoming data.
+ * @param[in] dataLen Size of incoming data.
+ * @param[out] result Result sent back to the application.
+ * @param[out] resultLen Length of result.
+ *
+ * @return TRUE.
+ */
+
+static gboolean
+TestDebugReceiveVersion(char *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen)
+{
+ g_debug("Received tools version message: %s\n", data);
+ RPCDEBUG_SET_RESULT("", result, resultLen);
+ return TRUE;
+}
+
+
+/**
+ * Validates the results for an unknown RPC sent to the guest.
+ *
+ * @param[in] data RPC request data.
+ * @param[in] ret Return value from RPC handler.
+ *
+ * @return The opposite of @a ret.
+ */
+
+static gboolean
+TestDebugValidateUnknown(RpcInData *data,
+ Bool ret)
+{
+ g_assert(strcmp(data->result, "Unknown Command") == 0);
+ return !ret;
+}
+
+
+/**
+ * Populates the RPC request data with the next message in the queue.
+ *
+ * @param[in] rpcdata Data for the injected RPC request data.
+ *
+ * @return TRUE if sending messages, FALSE if no more messages to be sent.
+ */
+
+static gboolean
+TestDebugSendNext(RpcDebugMsgMapping *rpcdata)
+{
+ static RpcDebugMsgList msgList = { gRpcMessages, 0 };
+ return RpcDebug_SendNext(rpcdata, &msgList);
+}
+
+
+/**
+ * Returns the debug plugin's registration data.
+ *
+ * @param[in] ctx The application context.
+ *
+ * @return The application data.
+ */
+
+TOOLS_MODULE_EXPORT RpcDebugPlugin *
+RpcDebugOnLoad(ToolsAppCtx *ctx)
+{
+ static RpcDebugRecvMapping recvFns[] = {
+ { "tools.set.version", TestDebugReceiveVersion, NULL, 0 },
+ { "test.rpcout.msg1", TestDebugReceiveRpc1,
+ xdr_GHIBinaryHandlersIconDetails, sizeof (GHIBinaryHandlersIconDetails) },
+ { NULL, NULL }
+ };
+ static RpcDebugPlugin regData = {
+ recvFns,
+ NULL,
+ TestDebugSendNext,
+ NULL
+ };
+
+ GHIBinaryHandlersIconDetails details;
+ details.width = 100;
+ details.height = 200;
+ details.identifier = "rpc1test";
+
+ /* Build the command for the "test.rpcin.msg1" RPC. */
+ if (!RpcChannel_BuildXdrCommand("test.rpcin.msg1",
+ xdr_GHIBinaryHandlersIconDetails,
+ &details,
+ &gRpcMessages[4].message,
+ &gRpcMessages[4].messageLen)) {
+ g_error("Failed to create test.rpcin.msg1 command.\n");
+ }
+
+ return ®Data;
+}
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libtestPlugin.la
+
+libtestPlugin_la_CPPFLAGS =
+libtestPlugin_la_CPPFLAGS += @GOBJECT_CPPFLAGS@
+libtestPlugin_la_CPPFLAGS += @PLUGIN_CPPFLAGS@
+
+libtestPlugin_la_LDFLAGS =
+libtestPlugin_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libtestPlugin_la_LIBADD =
+libtestPlugin_la_LIBADD += @GOBJECT_LIBS@
+libtestPlugin_la_LIBADD += @VMTOOLS_LIBS@
+libtestPlugin_la_LIBADD += @XDR_LIBS@
+
+libtestPlugin_la_SOURCES =
+libtestPlugin_la_SOURCES += testData_xdr.c
+libtestPlugin_la_SOURCES += testPlugin.c
+
+BUILT_SOURCES =
+BUILT_SOURCES += testData_xdr.c
+BUILT_SOURCES += testData.h
+
+# XXX: see explanation in lib/guestRpc/Makefile.am
+CFLAGS += -Wno-unused
+
+CLEANFILES =
+CLEANFILES += testData_xdr.c
+CLEANFILES += testData.h
+
+EXTRA_DIST =
+EXTRA_DIST += testData.x
+
+testData.h: testData.x
+ if [ $(top_builddir) != $(top_srcdir) ]; then \
+ cp -f $(top_srcdir)/tests/testPlugin/testData.x $(builddir); \
+ fi
+ $(RPCGEN) $(RPCGENFLAGS) -h -o $@ $(builddir)/testData.x
+ $(SED) 's,rpc/rpc\.h,vmxrpc.h,' $@ > $@.tmp
+ mv $@.tmp $@
+
+testData_xdr.c: testData.x testData.h
+ $(RPCGEN) $(RPCGENFLAGS) -c -o $@ $(builddir)/testData.x
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file testData.x
+ *
+ * Just define a struct for testing automatic XDR serialization.
+ */
+
+struct TestPluginData {
+ string data<128>;
+};
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file testPlugin.c
+ *
+ * Implements a test plugin for the tools services. The plugin register for
+ * a few RPCs that are never sent by the VMX, so to "use" it you have to use
+ * a debug plugin that sends those RPCs. The test debug plugin does that.
+ */
+
+#define G_LOG_DOMAIN "test"
+
+#include <glib-object.h>
+#include <gmodule.h>
+#include "testData.h"
+#include "util.h"
+#include "vmtoolsApp.h"
+#include "vm_app.h"
+#include "vmtools.h"
+#include "guestrpc/ghiGetBinaryHandlers.h"
+
+
+/**
+ * Handles a "test.rpcin.msg1" RPC message. The incoming data should be an
+ * XDR-encoded GHIBinaryHandlersIconDetails struct; the struct is written back
+ * to the RPC channel using RpcChannel_Send (command "test.rpcout.msg1").
+ *
+ * Also emits a "test-signal", to test custom signal registration.
+ *
+ * @param[in] data RPC data.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+TestPluginRpc1(RpcInData *data)
+{
+ ToolsAppCtx *ctx = data->appCtx;
+ GHIBinaryHandlersIconDetails *details = (GHIBinaryHandlersIconDetails *) data->args;
+ char *cmd;
+ size_t cmdLen;
+
+ g_assert(details->width == 100);
+ g_assert(details->height == 200);
+ g_assert(strcmp(details->identifier, "rpc1test") == 0);
+
+ g_signal_emit_by_name(ctx->serviceObj, "test-signal");
+
+ if (!RpcChannel_BuildXdrCommand("test.rpcout.msg1",
+ xdr_GHIBinaryHandlersIconDetails,
+ details,
+ &cmd,
+ &cmdLen)) {
+ g_error("Failed to create test.rpcout.msg1 command.\n");
+ }
+
+ if (!RpcChannel_Send(ctx->rpc, cmd, cmdLen, NULL, NULL)) {
+ g_error("Failed to send 'test.rpcout.msg1' message.\n");
+ }
+
+ vm_free(cmd);
+
+ g_debug("Successfully handled rpc %s\n", data->name);
+ return RPCIN_SETRETVALS(data, "", TRUE);
+}
+
+
+/**
+ * Handles a "test.rpcin.msg2" RPC message.
+ *
+ * @param[in] data RPC data.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+TestPluginRpc2(RpcInData *data)
+{
+ g_debug("%s: %s\n", __FUNCTION__, data->name);
+ return RPCIN_SETRETVALS(data, "", TRUE);
+}
+
+
+/**
+ * Handles a "test.rpcin.msg3" RPC message. Logs information to the
+ * output and returns data to be serialized using XDR.
+ *
+ * @param[in] data RPC data.
+ *
+ * @return TRUE on success.
+ */
+
+static Bool
+TestPluginRpc3(RpcInData *data)
+{
+ TestPluginData *ret;
+ g_debug("%s: %s\n", __FUNCTION__, data->name);
+
+ ret = g_malloc(sizeof *ret);
+ ret->data = Util_SafeStrdup("Hello World!");
+
+ data->result = (char *) ret;
+ return TRUE;
+}
+
+
+/**
+ * Called by the service core when the host requests the capabilities supported
+ * by the guest tools.
+ *
+ * @param[in] src Unused.
+ * @param[in] ctx The app context.
+ * @param[in] set Whether capabilities are being set or unset (unused).
+ * @param[in] plugin Plugin registration data.
+ *
+ * @return A list of capabilities to be sent to the host.
+ */
+
+static GArray *
+TestPluginCapabilities(gpointer src,
+ ToolsAppCtx *ctx,
+ gboolean set,
+ ToolsPluginData *plugin)
+{
+ ToolsAppCapability caps[] = {
+ { TOOLS_CAP_OLD, "resolution_set", 0, 1 },
+ { TOOLS_CAP_OLD, "display_topology_set", 0, 2 },
+ { TOOLS_CAP_NEW, NULL, UNITY_CAP_START_MENU, 1 },
+ { TOOLS_CAP_NEW, NULL, GHI_CAP_SHELL_ACTION_BROWSE, 1 }
+ };
+
+ g_debug("%s: got capability signal, setting = %d.\n", __FUNCTION__, set);
+ return VMTools_WrapArray(caps, sizeof *caps, ARRAYSIZE(caps));
+}
+
+
+/**
+ * Handles a reset signal; just logs debug information. This callback is
+ * called when the service receives a "reset" message from the VMX, meaning
+ * the VMX may be restarting the RPC channel (due, for example, to restoring
+ * a snapshot, resuming a VM or a VMotion), and should be used to reset any
+ * application state that depends on the VMX.
+ *
+ * @param[in] src Event source.
+ * @param[in] ctx The app context.
+ * @param[in] plugin Plugin registration data.
+ *
+ * @return TRUE on success.
+ */
+
+static gboolean
+TestPluginReset(gpointer src,
+ ToolsAppCtx *ctx,
+ ToolsPluginData *plugin)
+{
+ g_assert(ctx != NULL);
+ g_debug("%s: reset signal for app %s\n", __FUNCTION__, ctx->name);
+ return TRUE;
+}
+
+
+#if defined(G_PLATFORM_WIN32)
+/**
+ * Handles a session state change callback; this is only called on Windows,
+ * from both the "vmsvc" instance (handled by SCM notifications) and from
+ * "vmusr" with the "fast user switch" plugin.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The application context.
+ * @param[in] code Session state change code.
+ * @param[in] id Session ID.
+ * @param[in] data Client data.
+ */
+
+static void
+TestPluginSessionChange(gpointer src,
+ ToolsAppCtx *ctx,
+ DWORD code,
+ DWORD sessionId,
+ ToolsPluginData *plugin)
+{
+ g_debug("Got session state change signal, code = %u, id = %u\n", code, sessionId);
+}
+#endif
+
+
+/**
+ * Handles a shutdown callback; just logs debug information. This is called
+ * before the service is shut down, and should be used to clean up any resources
+ * that were initialized by the application.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The app context.
+ * @param[in] plugin Plugin registration data.
+ */
+
+static void
+TestPluginShutdown(gpointer src,
+ ToolsAppCtx *ctx,
+ ToolsPluginData *plugin)
+{
+ g_debug("%s: shutdown signal.\n", __FUNCTION__);
+}
+
+
+/**
+ * Handles a "Set_Option" callback. Just logs debug information. This callback
+ * is called when the VMX sends a "Set_Option" command to tools, to configure
+ * different options whose values are kept outside of the virtual machine.
+ *
+ * @param[in] src Event source.
+ * @param[in] ctx The app context.
+ * @param[in] plugin Plugin registration data.
+ * @param[in] option Option being set.
+ * @param[in] value Option value.
+ *
+ * @return TRUE on success.
+ */
+
+static gboolean
+TestPluginSetOption(gpointer src,
+ ToolsAppCtx *ctx,
+ const gchar *option,
+ const gchar *value,
+ ToolsPluginData *plugin)
+{
+ g_debug("%s: set '%s' to '%s'\n", __FUNCTION__, option, value);
+ return TRUE;
+}
+
+
+/**
+ * Plugin entry point. Returns the registration data. This is called once when
+ * the plugin is loaded into the service process.
+ *
+ * @param[in] ctx The app context.
+ *
+ * @return The registration data.
+ */
+
+TOOLS_MODULE_EXPORT ToolsPluginData *
+ToolsOnLoad(ToolsAppCtx *ctx)
+{
+ static ToolsPluginData regData = {
+ "testPlugin",
+ NULL,
+ NULL
+ };
+
+ RpcChannelCallback rpcs[] = {
+ { "test.rpcin.msg1",
+ TestPluginRpc1, NULL, xdr_GHIBinaryHandlersIconDetails, NULL,
+ sizeof (GHIBinaryHandlersIconDetails) },
+ { "test.rpcin.msg2",
+ TestPluginRpc2, NULL, NULL, NULL, 0 },
+ { "test.rpcin.msg3",
+ TestPluginRpc3, NULL, NULL, xdr_TestPluginData, 0 }
+ };
+ ToolsPluginSignalCb sigs[] = {
+ { TOOLS_CORE_SIG_RESET, TestPluginReset, ®Data },
+ { TOOLS_CORE_SIG_SHUTDOWN, TestPluginShutdown, ®Data },
+ { TOOLS_CORE_SIG_CAPABILITIES, TestPluginCapabilities, ®Data },
+ { TOOLS_CORE_SIG_SET_OPTION, TestPluginSetOption, ®Data },
+#if defined(G_PLATFORM_WIN32)
+ { TOOLS_CORE_SIG_SESSION_CHANGE, TestPluginSessionChange, ®Data },
+#endif
+ };
+ ToolsAppReg regs[] = {
+ { TOOLS_APP_GUESTRPC, VMTools_WrapArray(rpcs, sizeof *rpcs, ARRAYSIZE(rpcs)) },
+ { TOOLS_APP_SIGNALS, VMTools_WrapArray(sigs, sizeof *sigs, ARRAYSIZE(sigs)) }
+ };
+
+ g_signal_new("test-signal",
+ G_OBJECT_TYPE(ctx->serviceObj),
+ 0,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs));
+ return ®Data;
+}
+
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+################################################################################
+### Copyright 2009 VMware, Inc. All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+################################################################################
+
+noinst_LTLIBRARIES = libvmrpcdbg.la
+
+libvmrpcdbg_la_CPPFLAGS =
+libvmrpcdbg_la_CPPFLAGS += @GMODULE_CPPFLAGS@
+libvmrpcdbg_la_CPPFLAGS += @VMTOOLS_CPPFLAGS@
+
+libvmrpcdbg_la_LDFLAGS =
+libvmrpcdbg_la_LDFLAGS += @PLUGIN_LDFLAGS@
+
+libvmrpcdbg_la_LIBADD =
+libvmrpcdbg_la_LIBADD += @GMODULE_LIBS@
+libvmrpcdbg_la_LIBADD += @VMTOOLS_LIBS@
+libvmrpcdbg_la_LIBADD += @XDR_LIBS@
+
+libvmrpcdbg_la_SOURCES =
+libvmrpcdbg_la_SOURCES += debugChannel.c
+libvmrpcdbg_la_SOURCES += vmrpcdbg.c
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file debugChannel.c
+ *
+ * Implements an RPC Channel that is backed by a "debug plugin". The plugin
+ * provides information about what data should be "read" by the RPC Channel,
+ * and sinks for the data the application writes to the channel, so that the
+ * plugin can perform validation.
+ */
+
+#define G_LOG_DOMAIN "rpcdbg"
+
+#include <gmodule.h>
+
+#include "strutil.h"
+#include "vmrpcdbg.h"
+#include "vmtools.h"
+#include "util.h"
+#include "vmxrpc.h"
+#include "xdrutil.h"
+
+typedef struct DbgChannelData {
+ gboolean hasLibRef;
+ RpcDebugPlugin *plugin;
+ GSource *msgTimer;
+} DbgChannelData;
+
+/**
+ * Reads one RPC from the plugin and dispatches it to the application.
+ * This function will ask the service process to stop running if a
+ * failure occurs, where failure is defined either by the validation
+ * function returning FALSE, or, if no validation function is provided,
+ * the application's callback returning FALSE.
+ *
+ * @param[in] _chan The RPC channel instance.
+ *
+ * @return TRUE if the callback should continue to be scheduled.
+ */
+
+static gboolean
+RpcDebugDispatch(gpointer _chan)
+{
+ Bool ret;
+ RpcChannel *chan = _chan;
+ DbgChannelData *cdata = chan->_private;
+ RpcDebugPlugin *plugin = cdata->plugin;
+ RpcInData data;
+ RpcDebugMsgMapping rpcdata;
+
+ memset(&data, 0, sizeof data);
+ memset(&rpcdata, 0, sizeof rpcdata);
+
+ if (!plugin->sendFn(&rpcdata)) {
+ RpcDebug_DecRef(chan->appCtx);
+ cdata->hasLibRef = FALSE;
+ return FALSE;
+ } else if (rpcdata.message == NULL) {
+ /*
+ * Nothing to send. Maybe the debug plugin is waiting for something to
+ * happen before sending another message.
+ */
+ return TRUE;
+ }
+
+ data.clientData = chan;
+ data.appCtx = chan->appCtx;
+ data.args = rpcdata.message;
+ data.argsSize = rpcdata.messageLen;
+
+ ret = RpcChannel_Dispatch(&data);
+ if (rpcdata.validateFn != NULL) {
+ ret = (Bool) rpcdata.validateFn(&data, ret);
+ } else if (!ret) {
+ g_debug("RpcChannel_Dispatch returned error for RPC.\n");
+ }
+
+ if (data.freeResult) {
+ vm_free(data.result);
+ }
+
+ if (rpcdata.freeMsg) {
+ vm_free(rpcdata.message);
+ }
+
+ if (!ret) {
+ VMTOOLSAPP_ERROR((ToolsAppCtx *) chan->appCtx, 1);
+ RpcDebug_DecRef(chan->appCtx);
+ cdata->hasLibRef = FALSE;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
+ * Starts sending data to the service. The function will send one RPC
+ * approximately every 100ms, to somewhat mimic the behavior of the
+ * backdoor-based channel.
+ *
+ * @param[in] chan The RPC channel instance.
+ *
+ * @return TRUE.
+ */
+
+static Bool
+RpcDebugStart(RpcChannel *chan)
+{
+ DbgChannelData *data = chan->_private;
+
+ ASSERT(chan->appName != NULL);
+ ASSERT(data->msgTimer == NULL);
+
+ data->msgTimer = g_timeout_source_new(100);
+ VMTOOLSAPP_ATTACH_SOURCE((ToolsAppCtx *)chan->appCtx,
+ data->msgTimer,
+ RpcDebugDispatch,
+ chan,
+ NULL);
+ return TRUE;
+}
+
+
+/**
+ * Stops the channel; cancel the timer that sends polls the debug plugin for
+ * messages to send.
+ *
+ * @param[in] chan Unused.
+ *
+ * @return TRUE.
+ */
+
+static Bool
+RpcDebugStop(RpcChannel *chan)
+{
+ DbgChannelData *data = chan->_private;
+ if (data->msgTimer != NULL) {
+ g_source_unref(data->msgTimer);
+ data->msgTimer = NULL;
+ }
+ return TRUE;
+}
+
+
+/**
+ * Sends the given data to the plugin. This function tries to parse the
+ * incoming data based on the "cmd args" convention, and call the "receive"
+ * function provided by the debug plugin.
+ *
+ * @param[in] chan The RPC channel instance.
+ * @param[in] data Data to send.
+ * @param[in] dataLen Number of bytes to send.
+ * @param[out] result Response from other side.
+ * @param[out] resultLen Number of bytes in response.
+ *
+ * @return The result from the plugin's validation function, or TRUE if
+ * a validation function was not provided.
+ */
+
+static Bool
+RpcDebugSend(RpcChannel *chan,
+ char *data,
+ size_t dataLen,
+ char **result,
+ size_t *resultLen)
+{
+ char *copy;
+ gpointer xdrdata = NULL;
+ RpcDebugPlugin *plugin = ((DbgChannelData *)chan->_private)->plugin;
+ RpcDebugRecvMapping *mapping = NULL;
+ RpcDebugRecvFn recvFn = NULL;
+ Bool ret = TRUE;
+
+ g_assert(chan->appName != NULL);
+
+ /* Be paranoid. Like the VMX, NULL-terminate the incoming data. */
+ copy = g_malloc(dataLen + 1);
+ memcpy(copy, data, dataLen);
+ copy[dataLen] = '\0';
+
+ /* Try to find a mapping the the command in the RPC. */
+ if (plugin->recvFns) {
+ char *cmd;
+ unsigned int idx = 0;
+
+ cmd = StrUtil_GetNextToken(&idx, copy, " ");
+ if (cmd != NULL) {
+ RpcDebugRecvMapping *test;
+ for (test = plugin->recvFns; test->name != NULL; test++) {
+ if (strcmp(test->name, cmd) == 0) {
+ mapping = test;
+ break;
+ }
+ }
+ }
+ vm_free(cmd);
+ }
+
+ if (mapping != NULL) {
+ recvFn = mapping->recvFn;
+ if (mapping->xdrProc != NULL) {
+ char *start;
+
+ g_assert(mapping->xdrSize > 0);
+
+ /* Find out where the XDR data starts. */
+ start = strchr(copy, ' ');
+ if (start == NULL) {
+ RPCDEBUG_SET_RESULT("Can't find command delimiter.", result, resultLen);
+ ret = FALSE;
+ goto exit;
+ }
+ start++;
+
+ xdrdata = g_malloc0(mapping->xdrSize);
+ if (!XdrUtil_Deserialize(start,
+ dataLen - (start - copy),
+ mapping->xdrProc,
+ xdrdata)) {
+ RPCDEBUG_SET_RESULT("XDR deserialization failed.", result, resultLen);
+ ret = FALSE;
+ goto exit;
+ }
+ }
+ } else {
+ recvFn = plugin->dfltRecvFn;
+ }
+
+ if (recvFn != NULL) {
+ ret = recvFn((xdrdata != NULL) ? xdrdata : copy, dataLen, result, resultLen);
+ } else {
+ RPCDEBUG_SET_RESULT("", result, resultLen);
+ }
+
+exit:
+ if (xdrdata != NULL) {
+ VMX_XDR_FREE(mapping->xdrProc, xdrdata);
+ g_free(xdrdata);
+ }
+ g_free(copy);
+ return ret;
+}
+
+
+/**
+ * Does nothing.
+ *
+ * @param[in] chan The RPC channel instance.
+ *
+ * @return TRUE.
+ */
+
+static Bool
+RpcDebugShutdown(RpcChannel *chan)
+{
+ DbgChannelData *cdata = chan->_private;
+ g_assert(chan->appName != NULL);
+ if (cdata->hasLibRef) {
+ RpcDebug_DecRef(chan->appCtx);
+ }
+ g_free(chan->_private);
+ return TRUE;
+}
+
+
+/**
+ * Instantiates a new RPC Debug Channel. This function will load and initialize
+ * the given debug plugin.
+ *
+ * This function will panic is something wrong happens while loading the plugin.
+ *
+ * @param[in] ctx The application context.
+ * @param[in] data Debug library data.
+ *
+ * @return A new channel.
+ */
+
+RpcChannel *
+RpcDebug_NewDebugChannel(ToolsAppCtx *ctx,
+ RpcDebugLibData *data)
+{
+ DbgChannelData *cdata;
+ RpcChannel *ret;
+
+ g_assert(data != NULL);
+
+ ret = g_malloc0(sizeof *ret);
+ ret->start = RpcDebugStart;
+ ret->stop = RpcDebugStop;
+ ret->send = RpcDebugSend;
+ ret->shutdown = RpcDebugShutdown;
+
+ cdata = g_malloc0(sizeof *cdata);
+ cdata->plugin = data->debugPlugin;
+ ret->_private = cdata;
+
+ RpcDebug_IncRef();
+ return ret;
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file vmrpcdbg.c
+ *
+ * Implementation of the library functions not related to the RPC channel.
+ */
+
+#define G_LOG_DOMAIN "rpcdbg"
+
+#include <gmodule.h>
+#include <rpc/rpc.h>
+#include "vmrpcdbg.h"
+
+#if !defined(__APPLE__)
+#include "embed_version.h"
+#include "vmtoolsd_version.h"
+VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
+#endif
+
+static GModule *gPlugin = NULL;
+
+/* Atomic types are not volatile in old glib versions. */
+#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 10
+static volatile gint gRefCount = 0;
+#else
+static gint gRefCount = 0;
+#endif
+
+
+/**
+ * Decreases the internal ref count of the library. When the ref count reaches
+ * zero, this function will ask the application's main loop to stop running.
+ *
+ * @param[in] ctx The application contexnt.
+ */
+
+void
+RpcDebug_DecRef(ToolsAppCtx *ctx)
+{
+ if (g_atomic_int_dec_and_test(&gRefCount)) {
+ g_main_loop_quit(ctx->mainLoop);
+ }
+}
+
+
+/**
+ * Increases the internal ref count of the library. Test code that needs the
+ * process to stay alive should call this function to ensure that.
+ */
+
+void
+RpcDebug_IncRef(void)
+{
+ g_atomic_int_inc(&gRefCount);
+}
+
+
+/**
+ * Initializes the debug library and loads the debug plugin at the given path.
+ * This function panics if something goes wrong.
+ *
+ * @param[in] ctx The application context.
+ * @param[in] dbgPlugin Path to the debug plugin.
+ *
+ * @return Structure containing the debug library's information.
+ */
+
+RpcDebugLibData *
+RpcDebug_Initialize(ToolsAppCtx *ctx,
+ gchar *dbgPlugin)
+{
+ RpcDebugOnLoadFn onload;
+ RpcDebugLibData *ldata;
+
+ ldata = g_malloc(sizeof *ldata);
+
+ g_assert(gPlugin == NULL);
+ gPlugin = g_module_open(dbgPlugin, G_MODULE_BIND_LOCAL);
+ if (gPlugin == NULL) {
+ g_error("Can't load plugin: %s\n", dbgPlugin);
+ }
+
+ if (!g_module_symbol(gPlugin, "RpcDebugOnLoad", (gpointer *) &onload)) {
+ g_error("No entry point in debug plugin %s\n", dbgPlugin);
+ }
+
+ ldata->debugPlugin = onload(ctx);
+ if (ldata->debugPlugin == NULL) {
+ g_error("No registration data from plugin %s\n", dbgPlugin);
+ }
+
+ ldata->newDebugChannel = RpcDebug_NewDebugChannel;
+ ldata->shutdown = RpcDebug_Shutdown;
+
+ return ldata;
+}
+
+
+/**
+ * Places the next item on the given RPC message list into the given RPC data.
+ * Updates the current index of the list.
+ *
+ * @param[in] rpcdata The injected RPC data.
+ * @param[in] list The message list.
+ *
+ * @return TRUE if updated the RPC data, FALSE if reached the end of the list.
+ */
+
+gboolean
+RpcDebug_SendNext(RpcDebugMsgMapping *rpcdata,
+ RpcDebugMsgList *list)
+{
+ if (list->mappings[list->index].message != NULL) {
+ rpcdata->message = list->mappings[list->index].message;
+ rpcdata->messageLen = list->mappings[list->index].messageLen;
+ rpcdata->validateFn = list->mappings[list->index].validateFn;
+ rpcdata->freeMsg = list->mappings[list->index].freeMsg;
+ list->index++;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ * Shuts down the debug library. Unloads the debug plugin. The plugin's data
+ * shouldn't be used after this function is called.
+ *
+ * @param[in] ctx The application context.
+ * @param[in] ldata Debug library data.
+ */
+
+void
+RpcDebug_Shutdown(ToolsAppCtx *ctx,
+ RpcDebugLibData *ldata)
+{
+ g_assert(g_atomic_int_get(&gRefCount) == 0);
+ g_assert(ldata != NULL);
+
+ if (ldata->debugPlugin != NULL && ldata->debugPlugin->shutdownFn != NULL) {
+ ldata->debugPlugin->shutdownFn(ctx, ldata->debugPlugin);
+ }
+ if (gPlugin != NULL) {
+ g_module_close(gPlugin);
+ gPlugin = NULL;
+ }
+}
+
vmware_toolbox_SOURCES += toolbox-gtk.c
vmware_toolbox_SOURCES += toolboxAbout.c
vmware_toolbox_SOURCES += toolboxDevices.c
+ vmware_toolbox_SOURCES += toolboxInt.c
vmware_toolbox_SOURCES += toolboxOptions.c
vmware_toolbox_SOURCES += toolboxScripts.c
vmware_toolbox_SOURCES += toolboxShrink.c
- vmware_toolbox_SOURCES += toolboxRecord.c
+ vmware_toolbox_SOURCES += $(top_srcdir)/libvmtools/vmtoolsConfig.c
+
+ vmware_toolbox_CPPFLAGS =
+ vmware_toolbox_CPPFLAGS += -DG_LOG_DOMAIN=\"toolbox\"
# Here's something wacky: automake will muck up the translation of this
# conditional if it is indented. For more details, see:
$(INSTALL) -m 644 bigIcon.xpm \
$(DESTDIR)/usr/share/pixmaps/vmware/vmware-toolbox.xpm
uninstall-hook:
- -$(RM) -f $(DESTDIR)$(datadir)/share/applications/vmware-toolbox.desktop
- -$(RM) -rf $(DESTDIR)/usr/share/pixmaps/vmware
+ rm -f $(DESTDIR)$(datadir)/share/applications/vmware-toolbox.desktop
+ rm -rf $(DESTDIR)/usr/share/pixmaps/vmware
endif
-if ENABLE_CORE_SERVICES
- bin_PROGRAMS += vmware-toolbox-cmd
+bin_PROGRAMS += vmware-toolbox-cmd
- vmware_toolbox_cmd_LDADD =
- vmware_toolbox_cmd_LDADD += ../libguestlib/libguestlib.la
- vmware_toolbox_cmd_LDADD += @VMTOOLS_LIBS@
+vmware_toolbox_cmd_LDADD =
+vmware_toolbox_cmd_LDADD += ../libguestlib/libguestlib.la
+vmware_toolbox_cmd_LDADD += @VMTOOLS_LIBS@
- vmware_toolbox_cmd_CPPFLAGS =
- vmware_toolbox_cmd_CPPFLAGS += @VMTOOLS_CPPFLAGS@
+vmware_toolbox_cmd_CPPFLAGS =
+vmware_toolbox_cmd_CPPFLAGS += @VMTOOLS_CPPFLAGS@
- vmware_toolbox_cmd_SOURCES =
- vmware_toolbox_cmd_SOURCES += debugStdio.c
- vmware_toolbox_cmd_SOURCES += toolbox-cmd.c
- vmware_toolbox_cmd_SOURCES += toolboxcmd-devices.c
- vmware_toolbox_cmd_SOURCES += toolboxcmd-scripts.c
- vmware_toolbox_cmd_SOURCES += toolboxcmd-shrink.c
- vmware_toolbox_cmd_SOURCES += toolboxcmd-stat.c
- vmware_toolbox_cmd_SOURCES += toolboxcmd-time.c
- vmware_toolbox_cmd_SOURCES += toolboxcmd-record.c
+vmware_toolbox_cmd_SOURCES =
+vmware_toolbox_cmd_SOURCES += debugStdio.c
+vmware_toolbox_cmd_SOURCES += toolbox-cmd.c
+vmware_toolbox_cmd_SOURCES += toolboxcmd-devices.c
+vmware_toolbox_cmd_SOURCES += toolboxcmd-scripts.c
+vmware_toolbox_cmd_SOURCES += toolboxcmd-shrink.c
+vmware_toolbox_cmd_SOURCES += toolboxcmd-stat.c
+vmware_toolbox_cmd_SOURCES += toolboxcmd-time.c
if HAVE_ICU
vmware_toolbox_cmd_LDADD += @ICU_LIBS@
vmware_toolbox_cmd_LINK = $(LINK)
endif
-endif
-
static int StatCommand(char **argv, int argc);
static int ScriptCommand(char **argv, int argc);
static int TimeSyncCommand(char **argv, int argc);
-static int RecordCommand(char **argv, int argc);
static void DeviceHelp(char *progName);
static void DiskHelp(char *progName);
static void ScriptHelp(char *progName);
static void StatHelp(char *progName);
static void TimeSyncHelp(char *progName);
-static void RecordHelp(char *progName);
static void ToolboxCmdHelp(char *progName);
static CmdTable *ParseCommand(char **argv, int argc);
static Bool CheckArgumentLength(char **argv, int argc);
{ "disk", DiskCommand, TRUE, DiskHelp},
{ "stat", StatCommand, FALSE, StatHelp},
{ "device", DeviceCommand, FALSE, DeviceHelp},
- { "record", RecordCommand, FALSE, RecordHelp},
{ "help", HelpCommand, FALSE, ToolboxCmdHelp},
{ NULL, } };
static void
DeviceHelp(char *progName) // IN: The name of the program obtained from argv[0]
{
- printf("device: enable, disable, list devices, or get a device status"
+ printf("device: functions related to the virtual machine's hardware devices\n"
"Usage: %s device <subcommand> [args]\n"
" dev is the name of the device.\n\n"
"Subcommands:\n"
- " enable <dev>: enables the device dev\n"
+ " enable <dev>: enable the device dev\n"
" disable <dev>: disable the device dev\n"
- " list: list enabled and disabled devices\n"
- " status <dev>: prints the status of device dev\n", progName);
+ " list: list all available devices\n"
+ " status <dev>: print the status of a device\n", progName);
}
static void
ToolboxCmdHelp(char *progName)
{
- printf("usage: %s <command> [options] [subcommand]\n"
+ printf("Usage: %s <command> [options] [subcommand]\n"
"Type \'%s help <command>\' for help on a specific command.\n"
"Type \'%s --version' to see the Vmware Tools version.\n"
- "Type \'%s --quiet to supress stdout printing\n"
- "Most commands take a subcommand\n\n"
+ "Use --quiet to suppress stdout output.\n"
+ "Most commands take a subcommand.\n\n"
"Available commands:\n"
" timesync\n"
" device\n"
" script\n"
" disk\n"
" stat\n"
- " record\n\n"
+ "\n"
"For additional information please visit http://www.vmware.com/support/\n\n",
- progName, progName, progName, progName);
+ progName, progName, progName);
}
static void
TimeSyncHelp(char *progName) // IN: The name of the program obtained from argv[0]
{
- printf("timesync: enable, disable, or check the status of time "
- "sync on the guest OS\n"
+ printf("timesync: functions for controlling time synchronization on the guest OS\n"
"Usage: %s timesync <subcommand>\n\n"
"Subcommands\n"
- " enable: enable time sync\n"
- " disable: disable time sync\n"
- " status: display the time sync status\n", progName);
+ " enable: enable time synchronization\n"
+ " disable: disable time synchronization\n"
+ " status: print the time synchronization status\n", progName);
}
static void
ScriptHelp(char *progName) // IN: The name of the program obtained from argv[0]
{
- printf("script: enable, disable, set, or set to default a particular script\n"
- "Usage: %s script <power|resume|suspend|shutdown> <subcomamnd> [args]\n\n"
+ printf("script: control the scripts run in response to power operations\n"
+ "Usage: %s script <power|resume|suspend|shutdown> <subcomamnd> [args]\n\n"
"Subcommands:\n"
- " enable: enables and restores the script to the default one\n"
- " disable: disables a particular script\n"
- " set <full_path>: sets a script to the script given by full_path\n"
- " default: returns the path to the default script\n"
- " current: returns the path to the current script\n", progName);
+ " enable: enable the given script and restore its path to the default\n"
+ " disable: disable the given script\n"
+ " set <full_path>: set the given script to the given path\n"
+ " default: print the default path of the given script\n"
+ " current: print the current path of the given script\n", progName);
}
static void
StatHelp(char *progName) // IN: The name of the program obtained from argv[0]
{
- printf("stat: usefull guest and host information\n"
+ printf("stat: print useful guest and host information\n"
"Usage: %s state <subcommand>\n\n"
"Subcommands\n"
- " hosttime: gets the time host time\n"
- " memory: gets the virtual machine memory in MBs\n"
- " speed: gets the virtual machine speed in MHz\n"
+ " hosttime: print the host time\n"
+ " memory: print the virtual machine memory in MBs\n"
+ " speed: print the CPU speed in MHz\n"
"ESX guests only subcommands\n"
- " sessionid: Prints the current the session id\n"
- " balloon: Prints memory ballooning\n"
- " swap: Prints memory swapping\n"
- " memlimit: Prins memery limit\n"
- " memres: Prints memory reservation\n"
- " cpures: Prints cpu reservation\n"
- " cpulimit: Prints cput limit\n", progName);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * RecordHelp --
- *
- * Prints the help for the record command.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-RecordHelp(char *progName) // IN: The name of the program obtained from argv[0]
-{
- printf("record: control recording process inside guest\n"
- "Usage: %s record <subcommand>\n\n"
- "Subcommands\n"
- " start: start recording\n"
- " stop: stop recording\n", progName);
+ " sessionid: print the current session id\n"
+ " balloon: print memory ballooning information\n"
+ " swap: print memory swapping information\n"
+ " memlimit: print memory limit information\n"
+ " memres: print memory reservation information\n"
+ " cpures: print CPU reservation information\n"
+ " cpulimit: print CPU limit information\n", progName);
}
}
-/*
- *-----------------------------------------------------------------------------
- *
- * RecordCommand --
- *
- * Parse and Handle recording commands.
- *
- * Results:
- * Returns EXIT_SUCCESS on success.
- * Returns the appropriate exit code errors.
- *
- * Side effects:
- * Might start and stop recording, guest os may be suspended
- * to wait for the recording panel in host.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-RecordCommand(char **argv, // IN: Command line arguments
- int argc) // IN: Length of command line argumenst
-{
- if (CheckArgumentLength(argv, argc)) {
- if (strcmp(argv[optind], "start") == 0) {
- return Record_StartRecording();
- } else if (strcmp(argv[optind], "stop") == 0) {
- return Record_StopRecording();
- } else {
- fprintf(stderr, "Unknown subcommand");
- }
- }
- RecordHelp(argv[0]);
- return EX_USAGE;
-}
-
-
/*
*-----------------------------------------------------------------------------
*
* Check if we are in a VM
*/
if (!VmCheck_IsVirtualWorld()) {
- fprintf(stderr, "toolbox-cmd must be run inside a virtual machine.\n");
+ fprintf(stderr, "%s must be run inside a virtual machine.\n", argv[0]);
exit(EXIT_FAILURE);
}
static GtkWidget *toolsMain;
static Bool optionAutoHide;
static guint gTimeoutId;
-static const char **gNativeEnviron;
+const char **gNativeEnviron;
/* Help pages. These need to be in the same order as the tabs in the UI. */
static const char *gHelpPages[] = {
"tools_devices.htm",
"tools_scripts.htm",
"tools_shrink.htm",
- NULL, // Record/Replay
"tools_about.htm",
};
gtk_label_new_with_mnemonic(TAB_LABEL_SCRIPTS));
gtk_notebook_append_page(GTK_NOTEBOOK(notebookMain), Shrink_Create(ToolsMain),
gtk_label_new_with_mnemonic(TAB_LABEL_SHRINK));
- gtk_notebook_append_page(GTK_NOTEBOOK(notebookMain), Record_Create(ToolsMain),
- gtk_label_new_with_mnemonic(TAB_LABEL_RECORD));
gtk_notebook_append_page(GTK_NOTEBOOK(notebookMain), About_Create(ToolsMain),
gtk_label_new_with_mnemonic(TAB_LABEL_ABOUT));
#else
gtk_label_new(TAB_LABEL_SCRIPTS));
gtk_notebook_append_page(GTK_NOTEBOOK(notebookMain), Shrink_Create(ToolsMain),
gtk_label_new(TAB_LABEL_SHRINK));
- gtk_notebook_append_page(GTK_NOTEBOOK(notebookMain), Record_Create(ToolsMain),
- gtk_lable_new(TAB_LABEL_RECORD));
gtk_notebook_append_page(GTK_NOTEBOOK(notebookMain), About_Create(ToolsMain),
gtk_label_new(TAB_LABEL_ABOUT));
#endif
*/
void
-InitHelpDir(GuestApp_Dict *pConfDict) // IN
+InitHelpDir(GKeyFile *pConfDict) // IN
{
- const char *tmpDir = NULL;
+ gchar *tmpDir = NULL;
ASSERT(hlpDir == NULL);
- tmpDir = GuestApp_GetDictEntry(pConfDict, CONFNAME_HELPDIR);
+ tmpDir = g_key_file_get_string(pConfDict, "toolbox", CONFNAME_HELPDIR, NULL);
if (!tmpDir || !File_Exists(tmpDir)) {
unsigned int i;
for (i = 0; i < ARRAYSIZE(candidates); i++) {
if (File_Exists(candidates[i])) {
- tmpDir = candidates[i];
+ tmpDir = g_strdup(candidates[i]);
break;
}
}
}
if (tmpDir) {
- hlpDir = Util_SafeStrdup(tmpDir);
+ hlpDir = tmpDir;
}
}
{
Bool optIconify, optHelp, optVersion;
struct sigaction olds[ARRAYSIZE(gSignals)];
- GuestApp_Dict *pConfDict;
+ GKeyFile *pConfDict;
if (!VmCheck_IsVirtualWorld()) {
#ifndef ALLOW_TOOLS_IN_FOREIGN_VM
Panic("vmware-toolbox can't set signal handler\n");
}
- pConfDict = Conf_Load();
- Debug_Set(GuestApp_GetDictEntryBool(pConfDict, CONFNAME_LOG), DEBUG_PREFIX);
- Debug_EnableToFile(GuestApp_GetDictEntry(pConfDict, CONFNAME_LOGFILE), FALSE);
+ pConfDict = Toolbox_LoadToolsConf();
+ Debug_Set(g_key_file_get_boolean(pConfDict, "logging", CONFNAME_LOG, NULL),
+ DEBUG_PREFIX);
+ Debug_EnableToFile(g_key_file_get_string(pConfDict, "logging",
+ CONFNAME_LOGFILE, NULL),
+ FALSE);
InitHelpDir(pConfDict);
- GuestApp_FreeDict(pConfDict);
+ g_key_file_free(pConfDict);
optionAutoHide = FALSE;
gdk_pixmap_unref(pixmap);
gdk_bitmap_unref(bitmask);
- free(hlpDir);
+ g_free(hlpDir);
return 0;
}
gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-#ifdef _GTK2_
+#ifdef GTK2
Str_Snprintf(buf1, sizeof buf1, "%s %s",
UTF8_COPYRIGHT_STRING,
RIGHT_RESERVED);
int Stat_GetMemoryLimit(void);
int Stat_GetMemoryReservation(void);
-/*
- * Record commands
- */
-Bool Record_StartRecording(void);
-Bool Record_StopRecording(void);
-
#endif /*_TOOLBOX_CMD_H_*/
#define TAB_LABEL_DEVICES "De_vices"
#define TAB_LABEL_SCRIPTS "Scri_pts"
#define TAB_LABEL_SHRINK "Shrin_k"
-#define TAB_LABEL_RECORD "_Record"
#define TAB_LABEL_ABOUT "Abo_ut"
#else
#define TAB_LABEL_OPTIONS "Options"
#define TAB_LABEL_DEVICES "Devices"
#define TAB_LABEL_SCRIPTS "Scripts"
#define TAB_LABEL_SHRINK "Shrink"
-#define TAB_LABEL_RECORD "Record"
#define TAB_LABEL_ABOUT "About"
#endif
GtkWidget* Options_Create(GtkWidget* mainWnd);
GtkWidget* Scripts_Create(GtkWidget* mainWnd);
GtkWidget* Shrink_Create(GtkWidget* mainWnd);
-GtkWidget* Record_Create(GtkWidget* mainWnd);
void Options_OnTimeSyncToggled(gpointer btn, gpointer data);
void Devices_OnDeviceToggled(gpointer btn, gpointer data);
extern GtkWidget *optionsTimeSync;
extern DblLnkLst_Links *gEventQueue;
extern GtkWidget *scriptsApply;
+extern const char **gNativeEnviron;
#endif // _TOOLBOX_INT_H_
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * toolboxInt.c --
+ *
+ * Internal, shared functions for the GTK toolbox.
+ */
+
+#include <errno.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+#include "conf.h"
+#include "debug.h"
+#include "guestApp.h"
+#include "util.h"
+#include "vmtools.h"
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Toolbox_LoadToolsConf --
+ *
+ * Load the Tools configuration file from the default location.
+ *
+ * XXX: This function is temporary until the GTK toolbox is refactored
+ * to be able to use vmtoolslib.
+ *
+ * Results:
+ * The config object. If loading the data fails, returns an empty conf object.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+GKeyFile *
+Toolbox_LoadToolsConf(void)
+{
+ gchar *path = VMTools_GetToolsConfFile();
+ GKeyFile *config;
+
+ config = VMTools_LoadConfig(path,
+ G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS,
+ TRUE);
+
+ if (config == NULL) {
+ Debug("Unable to load config file.\n");
+ config = g_key_file_new();
+ }
+
+ g_free(path);
+ return config;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Toolbox_SaveToolsConf --
+ *
+ * Saves the given config data to the default tools config file location.
+ *
+ * XXX: This function is temporary until the GTK toolbox is refactored
+ * to be able to use vmtoolslib.
+ *
+ * Results:
+ * Whether saving was successful.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+gboolean
+Toolbox_SaveToolsConf(GKeyFile *config) // IN
+{
+ gboolean ret = FALSE;
+ gchar *path = NULL;
+ GError *err = NULL;
+
+ path = VMTools_GetToolsConfFile();
+ ret = VMTools_WriteConfig(path, config, &err);
+
+ if (!ret) {
+ Warning("Error saving conf data: %s\n", err->message);
+ g_clear_error(&err);
+ }
+
+ g_free(path);
+ return ret;
+}
+
#ifndef _TOOLBOX_INT_H_
#define _TOOLBOX_INT_H_
+#include <glib.h>
#include "vm_basic_types.h"
#include "vm_version.h"
#include "dbllnklst.h"
"enabled while the host believes it is disabled.\n\n " \
"Please close and reopen the Toolbox to synchronize " \
"it with the host.\n"
-#define RECORD_VMX_ERR "Error, the Record/Replay control operation failed. This could be for " \
- "one of the following reasons:\n" \
- "1. You are running an old version of a VMware product.\n\n" \
- "2. Your product has disabled these controls. To enable them, consult " \
- "the product documentation.\n\n" \
- "3. You tried to start a recording while already recording.\n\n" \
- "4. You tried to stop a recording while not recording.\n\n" \
+
+
+GKeyFile *
+Toolbox_LoadToolsConf(void);
+
+gboolean
+Toolbox_SaveToolsConf(GKeyFile *config);
#endif /*_TOOLBOX_INT_H_*/
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2008 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-/*
- * toolboxRecord.c --
- *
- * The record tab for the linux gtk toolbox.
- */
-
-#include <unistd.h>
-
-#include "toolboxGtkInt.h"
-#include "debug.h"
-#include "statelogger_backdoor_def.h"
-
-static void RecordOnStart(gpointer, gpointer);
-static void RecordOnStop(gpointer, gpointer);
-
-/*
- *-----------------------------------------------------------------------------
- *
- * Record_Create --
- *
- * Create, layout, and init the Record tab UI and all its widgets.
- *
- * Results:
- * The Record tab widget (it's a vbox).
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-GtkWidget *
-Record_Create(GtkWidget* mainWnd)
-{
- GtkWidget *recordtab;
- GtkWidget *hbox[2];
- GtkWidget *startbtn;
- GtkWidget *stopbtn;
- GtkWidget *label;
- recordtab = gtk_vbox_new(FALSE, 50);
- gtk_widget_show(recordtab);
- gtk_container_set_border_width(GTK_CONTAINER(recordtab), 10);
- hbox[0] = gtk_hbox_new(FALSE, 10);
- hbox[1] = gtk_hbox_new(FALSE, 10);
- label =
- gtk_label_new("Press start or stop button to control recording.");
- gtk_widget_show(hbox[0]);
- gtk_widget_show(hbox[1]);
- gtk_widget_show(label);
- gtk_box_pack_start(GTK_BOX(recordtab), hbox[0], FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(hbox[0]), label, TRUE, TRUE, 0);
- gtk_box_pack_start(GTK_BOX(recordtab), hbox[1], FALSE, FALSE, 0);
-#ifdef GTK2
- startbtn = gtk_button_new_with_mnemonic("_Start");
- stopbtn = gtk_button_new_with_mnemonic("S_top");
-#else
- startbtn = gtk_button_new_with_label("Start");
- stopbtn = gtk_button_new_with_label("Stop");
-#endif
- gtk_widget_show(startbtn);
- gtk_box_pack_start(GTK_BOX(hbox[1]), startbtn, FALSE, FALSE, 10);
- gtk_widget_set_usize(startbtn, 70, 25);
- gtk_signal_connect(GTK_OBJECT(startbtn), "clicked",
- GTK_SIGNAL_FUNC(RecordOnStart), NULL);
- gtk_widget_show(stopbtn);
- gtk_box_pack_end(GTK_BOX(hbox[1]), stopbtn, FALSE, FALSE, 10);
- gtk_widget_set_usize(stopbtn, 70, 6);
- gtk_signal_connect(GTK_OBJECT(stopbtn), "clicked",
- GTK_SIGNAL_FUNC(RecordOnStop), NULL);
-
- return recordtab;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * RecordOnStart --
- *
- * Callback for the gtk signal "clicked" on the Record tab's start
- * button.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Host VMware product starts recording this vm.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-RecordOnStart(gpointer btn, // IN: unused
- gpointer data) // IN: unused
-{
- if (GuestApp_ControlRecord(STATELOGGER_BKDR_START_LOGGING) == FALSE) {
- ToolsMain_MsgBox(NULL, RECORD_VMX_ERR);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * RecordOnStop --
- *
- * Callback for the gtk signal "clicked" on the Record tab's stop
- * button.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Host VMware product stops recording this vm.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-RecordOnStop(gpointer btn, // IN: unused
- gpointer data) // IN: unused
-{
- if (GuestApp_ControlRecord(STATELOGGER_BKDR_STOP_LOGGING) == FALSE) {
- ToolsMain_MsgBox(NULL, RECORD_VMX_ERR);
- }
-}
-
#include "toolboxGtkInt.h"
#include "guestApp.h"
#include "conf.h"
+#include "debug.h"
#include "str.h"
+#include "posix.h"
#include "procMgr.h"
#include "file.h"
+#include "util.h"
/*
* From toolboxInt.h
/* X terminal application and option (to launch vi to edit scripts). */
static char *termApp;
static char *termAppOption;
-static GuestApp_Dict *confDict;
+static GKeyFile *confDict;
static GtkWidget *scriptsUseScript;
static GtkWidget *scriptsDefaultScript;
static GtkWidget *scriptsCustomScript;
GList *items = NULL;
GSList *radiobtn_group = NULL;
- confDict = Conf_Load();
+ confDict = Toolbox_LoadToolsConf();
scriptstab = gtk_vbox_new(FALSE, 10);
gtk_widget_show(scriptstab);
#ifdef GTK2
gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_COMBO(scriptsCombo)->entry);
- scriptsUseScript = gtk_check_button_new_with_mnemonic("_Use Script");
+ scriptsUseScript = gtk_check_button_new_with_mnemonic("Use Scr_ipt");
#else
scriptsUseScript = gtk_check_button_new_with_label("Use Script");
#endif
GTK_SIGNAL_FUNC(Scripts_OnUseScriptToggled), NULL);
/*
- * Try to find an available x terminal app to launch vi.
+ * Try to find an available x terminal app to launch a text editor.
*
- * Options with different X terminal apps to launch vi:
- * xterm -e vi foo.txt
- * rxvt -e vi foo.txt
- * konsole -e vi foo.txt
- * gnome-terminal -x vi foo.txt
+ * Options with different X terminal apps to launch the editor:
+ * xterm -e [app] foo.txt
+ * rxvt -e [app] foo.txt
+ * konsole -e [app] foo.txt
+ * gnome-terminal -x [app] foo.txt
*/
termApp = NULL;
termAppOption = "-e";
Scripts_OnComboChanged(gpointer entry, // IN: the entry selected
gpointer data) // IN: unused
{
- const char *path, *defaultPath;
+ const char *defaultPath;
const char *currentState;
+ const char *confName = NULL;
+ gchar *path;
+
currentState = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(scriptsCombo)->entry));
if (strcmp(currentState, SCRIPT_SUSPEND) == 0) {
- path = GuestApp_GetDictEntry(confDict, CONFNAME_SUSPENDSCRIPT);
- defaultPath = GuestApp_GetDictEntryDefault(confDict, CONFNAME_SUSPENDSCRIPT);
+ confName = CONFNAME_SUSPENDSCRIPT;
} else if (strcmp(currentState, SCRIPT_RESUME) == 0) {
- path = GuestApp_GetDictEntry(confDict, CONFNAME_RESUMESCRIPT);
- defaultPath = GuestApp_GetDictEntryDefault(confDict, CONFNAME_RESUMESCRIPT);
+ confName = CONFNAME_RESUMESCRIPT;
} else if (strcmp(currentState, SCRIPT_OFF) == 0) {
- path = GuestApp_GetDictEntry(confDict, CONFNAME_POWEROFFSCRIPT);
- defaultPath = GuestApp_GetDictEntryDefault(confDict, CONFNAME_POWEROFFSCRIPT);
+ confName = CONFNAME_POWEROFFSCRIPT;
} else if (strcmp(currentState, SCRIPT_ON) == 0) {
- path = GuestApp_GetDictEntry(confDict, CONFNAME_POWERONSCRIPT);
- defaultPath = GuestApp_GetDictEntryDefault(confDict, CONFNAME_POWERONSCRIPT);
+ confName = CONFNAME_POWERONSCRIPT;
+ }
+
+ if (confName != NULL) {
+ path = g_key_file_get_string(confDict, "powerops", confName, NULL);
+ if (path == NULL) {
+ path = g_strdup("");
+ }
+ defaultPath = GuestApp_GetDefaultScript(confName);
} else {
- path = "";
+ path = g_strdup("");
defaultPath = "";
}
-
+
gtk_signal_handler_block_by_func(GTK_OBJECT(scriptsUseScript),
GTK_SIGNAL_FUNC(Scripts_OnUseScriptToggled),
NULL);
NULL);
if (strcmp(path, "") == 0) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(scriptsUseScript), FALSE);
- path = defaultPath;
+ path = g_strdup(defaultPath);
} else {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(scriptsUseScript), TRUE);
}
GTK_SIGNAL_FUNC(Scripts_OnUseScriptToggled),
NULL);
Scripts_UpdateEnabled();
+ g_free(path);
}
gpointer data) // IN: unused
{
const char *path;
+ const char *defaultPath;
const char *currentState;
- char *confName;
+ const char *confName = NULL;
Bool enabledUse, enabledDef;
currentState = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(scriptsCombo)->entry));
} else if (strcmp(currentState, SCRIPT_ON) == 0) {
confName = CONFNAME_POWERONSCRIPT;
} else {
- confName = "";
+ /* Not reached? */
+ return;
}
+ defaultPath = GuestApp_GetDefaultScript(confName);
enabledUse = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(scriptsUseScript));
enabledDef = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(scriptsDefaultScript));
path = "";
} else {
if (enabledDef) {
- path = GuestApp_GetDictEntryDefault(confDict, confName);
+ path = defaultPath;
} else {
path = gtk_editable_get_chars(GTK_EDITABLE(scriptsPath), 0, -1);
}
}
- GuestApp_SetDictEntry(confDict, confName, path);
+ g_key_file_set_string(confDict, "powerops", confName, path);
- GuestApp_WriteDict(confDict);
+ Toolbox_SaveToolsConf(confDict);
Scripts_UpdateEnabled();
gtk_widget_set_sensitive(scriptsApply, FALSE);
Scripts_OnEdit(gpointer btn, // IN: unused
gpointer data) // IN: unused
{
+ char *editor;
const char *scriptName;
- char *cmd;
+ const char *argv[5];
+ size_t idx = 0;
if (!termApp) {
ToolsMain_MsgBox("Error", "Unable to locate terminal application in "
return;
}
- scriptName = gtk_entry_get_text(GTK_ENTRY(scriptsPath));
- cmd = Str_Asprintf(NULL, "%s %s vi %s >/dev/null 2>&1",
- termApp, termAppOption, scriptName);
- if (!cmd) {
- ToolsMain_MsgBox("Error", "Failure creating command to edit script.");
- return;
+ editor = Posix_Getenv("EDITOR");
+ if (editor == NULL || strlen(editor) == 0) {
+ Debug("EDITOR not set, defaulting to vi.\n");
+ free(editor);
+ editor = g_find_program_in_path("vi");
+ if (editor == NULL) {
+ ToolsMain_MsgBox("Error",
+ "Cannot edit script because the an editor was not found.");
+ goto exit;
+ } else {
+ /*
+ * Make sure "editor" is allocated with malloc(), so that the call to
+ * free() later does the right thing.
+ */
+ char *tmp = editor;
+ editor = Util_SafeStrdup(tmp);
+ g_free(tmp);
+ }
}
- if (!ProcMgr_ExecSync(cmd, NULL)) {
- ToolsMain_MsgBox("Error", "Cannot edit script because the vi editor "
- "was not found.");
+ scriptName = gtk_entry_get_text(GTK_ENTRY(scriptsPath));
+ argv[idx++] = termApp;
+ if (termAppOption != NULL && strlen(termAppOption) > 0) {
+ argv[idx++] = termAppOption;
+ }
+ argv[idx++] = editor;
+ argv[idx++] = scriptName;
+ argv[idx++] = NULL;
+
+ /* Restore the original LD_LIBRARY_PATH before invoking external apps. */
+ if (!g_spawn_sync(NULL, (gchar **) argv, (gchar **) gNativeEnviron,
+ G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, NULL, NULL)) {
+ gchar *msg = g_strdup_printf("Cannot edit script: failed to execute editor %s.",
+ editor);
+ ToolsMain_MsgBox("Error", msg);
+ g_free(msg);
}
- free(cmd);
+exit:
+ free(editor);
}
gpointer data) // IN: unused
{
const char *scriptName;
+ gchar *cmd = NULL;
scriptName = gtk_entry_get_text(GTK_ENTRY(scriptsPath));
- if (!ProcMgr_ExecSync(scriptName, NULL)) {
+ if (!g_path_is_absolute(scriptName)) {
+ char *toolsPath = GuestApp_GetInstallPath();
+ ASSERT_MEM_ALLOC(toolsPath);
+ cmd = g_strdup_printf("%s%c%s", toolsPath, DIRSEPC, scriptName);
+ free(toolsPath);
+ }
+
+ if (!ProcMgr_ExecSync((cmd != NULL) ? cmd : scriptName, NULL)) {
ToolsMain_MsgBox("Error", "Failure executing script, please ensure the "
"file exists and is executable.");
}
+
+ g_free(cmd);
}
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2008 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-/*
- * toolboxcmd-record.c --
- *
- * Record operations for toolbox command line console.
- */
-
-#include "toolboxCmdInt.h"
-#include "statelogger_backdoor_def.h"
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * Record_StartRecording --
- *
- * Start recording process.
- *
- * Results:
- * TRUE if the call is successful, FALSE otherwise.
- *
- * Side effects:
- * Host VMware product starts recording this vm.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-Record_StartRecording(void)
-{
- if (GuestApp_ControlRecord(STATELOGGER_BKDR_START_LOGGING) == TRUE) {
- return TRUE;
- } else {
- fprintf(stderr, RECORD_VMX_ERR);
- return FALSE;
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * Record_StopRecording --
- *
- * Stop recording process,
- *
- * Results:
- * TRUE if the call is successful, FALSE otherwise.
- *
- * Side effects:
- * Host VMware product stops recording this vm.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-Record_StopRecording(void)
-{
- if (GuestApp_ControlRecord(STATELOGGER_BKDR_STOP_LOGGING) == TRUE) {
- return TRUE;
- } else {
- fprintf(stderr, RECORD_VMX_ERR);
- return FALSE;
- }
-}
-
* The scripts functions for the linux toolbox-cmd
*/
+#include <glib.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include "system.h"
#include "toolboxCmdInt.h"
+#include "vmtools.h"
#define SCRIPT_SUSPEND "suspend"
static int ScriptToggle(char *apm, Bool enable, int quiet_flag);
static char* GetConfName(char *apm);
static int GetConfEntry(char *apm, ScriptType type);
-static int WriteDict(GuestApp_Dict *confDict, int quiet_flag);
/*
/*
*-----------------------------------------------------------------------------
*
- * GetConfEntry --
+ * LoadConfFile --
*
- * Gets the entry in the ConfDict.
+ * Loads the tools configuration file. If running as admin, tries to
+ * upgrade it if an old-style file is found.
*
* Results:
- * The conf entry.
+ * A new GKeyFile *. If the conf file is not valid, it will be empty.
*
* Side effects:
* None.
*-----------------------------------------------------------------------------
*/
-static int
-GetConfEntry(char *apm, // IN: apm name
- ScriptType type) // IN: Script type (default or current)
+static GKeyFile *
+LoadConfFile(void)
{
- const char *entry = NULL;
- GuestApp_Dict *confDict;
- char *confName;
- confDict = Conf_Load();
- confName = GetConfName(apm);
- if (!confName) {
- fprintf(stderr, "Unknown operation\n");
- return EX_USAGE;
- }
- if (type == Default) {
- entry = GuestApp_GetDictEntryDefault(confDict, confName);
- } else if (type == Current) {
- entry = GuestApp_GetDictEntry(confDict, confName);
- }
- if (entry) {
- printf("%s\n", entry);
- return EXIT_SUCCESS;
- } else {
- fprintf(stderr, "Error retreiving the path for script %s\n", apm);
- return EX_TEMPFAIL;
+ gchar *confPath;
+ GKeyFile *confDict;
+
+ confPath = VMTools_GetToolsConfFile();
+ confDict = VMTools_LoadConfig(confPath,
+ G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS,
+ System_IsUserAdmin());
+
+ if (confDict == NULL) {
+ confDict = g_key_file_new();
}
+
+ g_free(confPath);
+ return confDict;
}
/*
*-----------------------------------------------------------------------------
*
- * WriteDict --
+ * GetConfEntry --
*
- * Writes a ConfDict to the hard disk.
+ * Gets the entry in the config dictionary.
*
* Results:
- * EXIT_SUCCESS on success.
- * EXIT_TEMPFAIL on failure
+ * EXIT_SUCCESS on success, error code otherwise.
*
* Side effects:
- * Writes the Dict to the hard disk.
+ * None.
*
*-----------------------------------------------------------------------------
*/
static int
-WriteDict(GuestApp_Dict *confDict, // IN: The Dict to be writen
- int quiet_flag) // IN: Verbosity flag.
+GetConfEntry(char *apm, // IN: apm name
+ ScriptType type) // IN: Script type (default or current)
{
- if (!GuestApp_WriteDict(confDict)) {
- fprintf(stderr, "Unable to write dictionary\n");
- GuestApp_FreeDict(confDict);
- return EX_TEMPFAIL;
- } else {
- if (!quiet_flag) {
- printf("Script Set\n");
+ gchar *entry = NULL;
+ GKeyFile *confDict = NULL;
+ char *confName;
+ int ret;
+
+ confName = GetConfName(apm);
+ if (!confName) {
+ fprintf(stderr, "Unknown operation\n");
+ return EX_USAGE;
+ }
+
+ confDict = LoadConfFile();
+
+ if (type == Default) {
+ entry = g_strdup(GuestApp_GetDefaultScript(confName));
+ } else if (type == Current) {
+ entry = g_key_file_get_string(confDict, "powerops", confName, NULL);
+ if (entry == NULL) {
+ entry = g_strdup(GuestApp_GetDefaultScript(confName));
}
- GuestApp_FreeDict(confDict);
- return EXIT_SUCCESS;
}
+
+ if (strlen(entry) > 0) {
+ printf("%s\n", entry);
+ ret = EXIT_SUCCESS;
+ } else {
+ fprintf(stderr, "No script for operation %s\n", apm);
+ ret = EX_TEMPFAIL;
+ }
+
+ g_free(entry);
+ g_key_file_free(confDict);
+ return ret;
}
{
const char *path;
char *confName;
- GuestApp_Dict *confDict;
- confDict = Conf_Load();
+ gchar *confPath;
+ int ret = EXIT_SUCCESS;
+ GKeyFile *confDict;
+ GError *err = NULL;
+
confName = GetConfName(apm);
if (!confName) {
return EX_USAGE;
}
+ confDict = LoadConfFile();
+
if (!enable) {
path = "";
} else {
- path = GuestApp_GetDictEntryDefault (confDict, confName);
+ path = GuestApp_GetDefaultScript(confName);
}
- GuestApp_SetDictEntry(confDict, confName, path);
+ g_key_file_set_string(confDict, "powerops", confName, path);
+ confPath = VMTools_GetToolsConfFile();
+ if (!VMTools_WriteConfig(confPath, confDict, &err)) {
+ fprintf(stderr, "Error writing config: %s\n", err->message);
+ g_clear_error(&err);
+ ret = EX_TEMPFAIL;
+ }
- return WriteDict(confDict, quiet_flag);
+ g_key_file_free(confDict);
+ g_free(confPath);
+ return ret;
}
int quiet_flag) // IN: Verbosity flag
{
char *confName;
- GuestApp_Dict *confDict;
+ int ret = EXIT_SUCCESS;
+ gchar *confPath = NULL;
+ GKeyFile *confDict = NULL;
+ GError *err = NULL;
+
if (!File_Exists(path)) {
fprintf(stderr, "%s doesn't exists\n", path);
return EX_OSFILE;
}
- confDict = Conf_Load();
+
confName = GetConfName(apm);
if (!confName) {
fprintf(stderr, "Unknown operation\n");
return EX_USAGE;
}
- GuestApp_SetDictEntry(confDict, confName, path);
- return WriteDict(confDict, quiet_flag);
+ confPath = VMTools_GetToolsConfFile();
+ confDict = LoadConfFile();
+
+ g_key_file_set_string(confDict, "powerops", confName, path);
+
+ if (!VMTools_WriteConfig(confPath, confDict, &err)) {
+ fprintf(stderr, "Error writing config: %s\n", err->message);
+ g_clear_error(&err);
+ ret = EX_TEMPFAIL;
+ }
+ g_key_file_free(confDict);
+ g_free(confPath);
+ return ret;
}
AM_CFLAGS =
AM_CFLAGS += @GTK_CPPFLAGS@
+if HAVE_GTKMM
+ AM_CFLAGS += @GTKMM_CPPFLAGS@
+endif
AM_CFLAGS += @VMWARE_USER_CPPFLAGS@
AM_CFLAGS += -I$(top_builddir)/include
AM_CFLAGS += -DRESOLUTION_X11
+AM_CFLAGS += -I$(top_srcdir)/services/plugins/vix
+
+AM_CXXFLAGS = $(AM_CFLAGS)
vmware_user_LDADD =
vmware_user_LDADD += ../lib/conf/libConf.la
-vmware_user_LDADD += ../lib/dnd/libDnd.la
+if HAVE_GTKMM
+ vmware_user_LDADD += ../lib/dndGuest/libDndGuest.la
+endif
vmware_user_LDADD += ../lib/eventManager/libEventManager.la
vmware_user_LDADD += ../lib/file/libFile.la
if ENABLE_UNITY
vmware_user_LDADD += ../lib/foundryMsg/libFoundryMsg.la
vmware_user_LDADD += ../lib/backdoor/libBackdoor.la
vmware_user_LDADD += ../lib/dict/libDict.la
+vmware_user_LDADD += ../lib/dnd/libDnd.la
vmware_user_LDADD += ../lib/dynxdr/libDynxdr.la
vmware_user_LDADD += ../lib/hgfs/libHgfs.la
vmware_user_LDADD += ../lib/message/libMessage.la
vmware_user_LDADD += ../lib/region/libRegion.la
endif
vmware_user_LDADD += -lcrypt
+vmware_user_LDADD += -lstdc++
+if LINUX
+vmware_user_LDADD += -lgcc_s
+endif
vmware_user_LDADD += @GTK_LIBS@
+if HAVE_GTKMM
+ vmware_user_LDADD += @GTKMM_LIBS@
+endif
vmware_user_LDADD += @VMWARE_USER_LDADD@
vmware_user_LDADD += @COMMON_XLIBS@
if ENABLE_UNITY
vmware_user_SOURCES =
vmware_user_SOURCES += copyPaste.c
+if HAVE_GTKMM
+ vmware_user_SOURCES += copyPasteUI.cpp
+endif
+vmware_user_SOURCES += copyPasteWrapper.cpp
vmware_user_SOURCES += debugStdio.c
vmware_user_SOURCES += dnd.c
vmware_user_SOURCES += foreignVMToolsDaemon.c
vmware_user_SOURCES += foreignVMToolsNetworking.c
-vmware_user_SOURCES += foundryToolsDaemon.c
+vmware_user_SOURCES += $(top_srcdir)/services/plugins/vix/foundryToolsDaemon.c
vmware_user_SOURCES += notify.c
vmware_user_SOURCES += pointer.c
-vmware_user_SOURCES += vmware-user.c
+if HAVE_GTKMM
+ vmware_user_SOURCES += stringxx/string.cc
+endif
+vmware_user_SOURCES += vmware-user.cpp
if HAVE_ICU
vmware_user_LDADD += @ICU_LIBS@
install-exec-hook:
$(INSTALL) -d $(DESTDIR)$(datadir)/applications/
- $(INSTALL) -m 644 ../scripts/common/vmware-user.desktop \
+ $(INSTALL) -m 644 $(top_srcdir)/scripts/common/vmware-user.desktop \
$(DESTDIR)$(datadir)/applications/
uninstall-hook:
- -$(RM) -f $(DESTDIR)$(datadir)/applications/vmware-user.desktop
+ rm -f $(DESTDIR)$(datadir)/applications/vmware-user.desktop
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2005 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * copyPaste.c --
+ *
+ * Set of functions in guest side for copy/paste (both file and text).
+ * Currently there are 2 versions copy/paste. Version 1 only supports
+ * text copy/paste, and based on backdoor cmd. Version 2 supports both
+ * text and file copy/paste, and based on guestRPC.
+ *
+ * G->H Text Copy/Paste (version 1)
+ * --------------------
+ * When Ungrab, CopyPaste_RequestSelection got called, which try to get
+ * selection text and send to backdoor.
+ *
+ * H->G Text Copy/Paste (version 1)
+ * --------------------
+ * When grab, CopyPaste_GetBackdoorSelections got called, which first
+ * get host selection text, then claim as selection owner. If some app
+ * asks for selection, CopyPasteSelectionGetCB will reply with host
+ * selection text.
+ *
+ * G->H Copy/Paste (version 2)
+ * --------------------
+ * When Ungrab, host vmx will send out rpc command "copypaste.gh.data.get",
+ * which handler is CopyPasteRpcInGHSetDataCB. It first tries to get selection
+ * contents and sends it back as rpc result. For file transfer, host vmx
+ * will transfer files with hgFileCopy lib. Function CopyPasteGHFileListGetNext
+ * will handle the file list during transfer.
+ *
+ * H->G Copy/Paste (version 2)
+ * --------------------
+ * When grab, host vmx will send host selection content to guest with
+ * out rpc command "copypaste.hg.data.set", which handler is
+ * CopyPasteRpcInHGSetDataCB. It first keeps a copy then claim as selection
+ * owner. If some app asks for files, CopyPasteSelectionGetCB will ask host
+ * vmx to transfer files into a temp dir with rpc "copypaste.hgCopyFiles",
+ * then reply with host selection file list. For KDE and gnome the file list
+ * format is different. If someapp asks for text, CopyPasteSelectionGetCB
+ * will provide the data.
+ */
+
+#include "vmwareuserInt.h"
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "vm_assert.h"
+#include "debug.h"
+#include "str.h"
+#include "strutil.h"
+#include "vm_app.h"
+#include "eventManager.h"
+#include "guestApp.h"
+#include "dnd.h"
+#include "util.h"
+#include "cpName.h"
+#include "cpNameUtil.h"
+#include "guestInfoServer.h"
+#include "vmblock.h"
+#include "file.h"
+#include "codeset.h"
+#include "escape.h"
+#include "hostinfo.h"
+#include "wiper.h"
+
+
+/*
+ * Gtk 1.2 doesn't know about the CLIPBOARD selection, but that doesn't matter, we
+ * just create the atom we need directly in main().
+ */
+#ifndef GDK_SELECTION_CLIPBOARD
+GdkAtom GDK_SELECTION_CLIPBOARD;
+#endif
+
+#ifndef GDK_SELECTION_TYPE_TIMESTAMP
+GdkAtom GDK_SELECTION_TYPE_TIMESTAMP;
+#endif
+
+#ifndef GDK_SELECTION_TYPE_UTF8_STRING
+GdkAtom GDK_SELECTION_TYPE_UTF8_STRING;
+#endif
+
+typedef struct FCPGHState {
+ char *fileList;
+ char *fileListNext;
+ size_t fileListSize;
+} FCPGHState;
+
+/*
+ * Currently there are 2 versions copy/paste.
+ * Key points in copy/paste version 1:
+ * 1. Only text copy/paste
+ * 2. copy/paste is based on backdoor directly
+ *
+ * Key points in copy/paste version 2:
+ * 1. Support both file/text copy/paste
+ * 2. Both file/text copy/paste are based on guestRPC
+ */
+static int32 gVmxCopyPasteVersion = 1;
+
+/*
+ * Getting a selection is an asyncronous event, so we have to keep track of both
+ * selections globablly in order to decide which one to use.
+ */
+static Bool gWaitingOnGuestSelection = FALSE;
+static char gGuestSelPrimaryBuf[MAX_SELECTION_BUFFER_LENGTH];
+static char gGuestSelClipboardBuf[MAX_SELECTION_BUFFER_LENGTH];
+static uint64 gGuestSelPrimaryTime = 0;
+static uint64 gGuestSelClipboardTime = 0;
+static char gHostClipboardBuf[MAX_SELECTION_BUFFER_LENGTH];
+
+/* Guest->Host state. */
+FCPGHState gFcpGHState;
+/* RPC buffer for Guest->Host FCP. */
+static char *gGHFCPRpcResultBuffer;
+/* File list size for Guest->Host FCP. */
+static size_t gGHFCPListSize;
+static Bool gHGFCPPending;
+/* Current selection is text or file list (for FCP). */
+static Bool gHGIsClipboardFCP;
+/*
+ * Total file size in selection list. This is used to check if there is enough
+ * space in guest OS for host->guest file transfer.
+ */
+static uint64 gHGFCPTotalSize;
+
+static GdkAtom gFCPAtom[NR_FCP_TARGETS];
+
+/* Host->guest file transfer status, used for sync between transfer and paste. */
+int gHGFCPFileTransferStatus;
+
+static char gFileRoot[DND_MAX_PATH];
+static size_t gFileRootSize;
+static Bool gIsOwner;
+static VmTimeType gHGGetListTime;
+
+/*
+ * Forward Declarations
+ */
+static INLINE void CopyPasteStateInit(void);
+static void CopyPasteSelectionReceivedCB(GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ gpointer data);
+static void CopyPasteSelectionGetCB(GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time_stamp,
+ gpointer data);
+static gint CopyPasteSelectionClearCB(GtkWidget *widget,
+ GdkEventSelection *event,
+ gpointer data);
+
+static void CopyPasteSetBackdoorSelections(void);
+static Bool CopyPasteRpcInGHSetDataCB(char const **result, size_t *resultLen,
+ const char *name, const char *args,
+ size_t argsSize,void *clientData);
+static Bool CopyPasteRpcInHGSetDataCB(char const **result, size_t *resultLen,
+ const char *name, const char *args,
+ size_t argsSize,void *clientData);
+
+static INLINE void CopyPasteGHFileListClear(void);
+static INLINE void CopyPasteGHFileListSet(char *fileList, size_t fileListSize);
+
+/* This struct is only used by CopyPasteSelectionRemoveTarget. */
+struct SelectionTargetList {
+ GdkAtom selection;
+ GtkTargetList *list;
+};
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteSelectionRemoveTarget --
+ *
+ * To remove a target from a selection target list. The reason to develop
+ * this function is that in gtk there is only gtk_selection_add_target to
+ * add supported target to selection list, but no function to remove one.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * If no more target, the selection list will be removed too.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteSelectionRemoveTarget(GtkWidget *widget,
+ GdkAtom selection,
+ GdkAtom target)
+{
+ const char *selection_handler_key = "gtk-selection-handlers";
+ struct SelectionTargetList *targetList;
+ GList *tempList;
+ GList *selectionLists;
+
+ /* Get selection list. */
+ selectionLists = gtk_object_get_data(GTK_OBJECT (widget), selection_handler_key);
+ tempList = selectionLists;
+ while (tempList) {
+ /* Enumerate the list to find the selection. */
+ targetList = tempList->data;
+ if (targetList->selection == selection) {
+ /* Remove target. */
+ gtk_target_list_remove(targetList->list, target);
+ /* If no more target, remove selection from list. */
+ if (!targetList->list->list) {
+ /* Free target list. */
+ gtk_target_list_unref(targetList->list);
+ g_free(targetList);
+ /* Remove and free selection node. */
+ selectionLists = g_list_remove_link(selectionLists, tempList);
+ g_list_free_1(tempList);
+ }
+ break;
+ }
+ tempList = tempList->next;
+ }
+ /* Put new selection list back. */
+ gtk_object_set_data (GTK_OBJECT (widget), selection_handler_key, selectionLists);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPaste_RequestSelection --
+ *
+ * Request the guest's text clipboard (asynchronously), we'll give it to
+ * the host when the request completes. For version 1 guest->host text
+ * copy/paste.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The owner of the clipboard will get a request from our application.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPaste_RequestSelection(void)
+{
+ if (gVmxCopyPasteVersion > 1) {
+ return;
+ }
+
+ /*
+ * Ask for both the PRIMARY and CLIPBOARD selections.
+ */
+ gGuestSelPrimaryBuf[0] = '\0';
+ gGuestSelClipboardBuf[0] = '\0';
+
+ /* Only send out request if we are not the owner. */
+ if (!gIsOwner) {
+ /* Try to get utf8 text from primary and clipboard. */
+ gWaitingOnGuestSelection = TRUE;
+ gtk_selection_convert(gUserMainWidget,
+ GDK_SELECTION_PRIMARY,
+ GDK_SELECTION_TYPE_UTF8_STRING,
+ GDK_CURRENT_TIME);
+ while (gWaitingOnGuestSelection) gtk_main_iteration();
+
+ gWaitingOnGuestSelection = TRUE;
+ gtk_selection_convert(gUserMainWidget,
+ GDK_SELECTION_CLIPBOARD,
+ GDK_SELECTION_TYPE_UTF8_STRING,
+ GDK_CURRENT_TIME);
+ while (gWaitingOnGuestSelection) gtk_main_iteration();
+
+ if (gGuestSelPrimaryBuf[0] == '\0' && gGuestSelClipboardBuf[0] == '\0') {
+ /*
+ * If we cannot get utf8 text, try to get localized text from primary
+ * and clipboard.
+ */
+ gWaitingOnGuestSelection = TRUE;
+ gtk_selection_convert(gUserMainWidget,
+ GDK_SELECTION_PRIMARY,
+ GDK_SELECTION_TYPE_STRING,
+ GDK_CURRENT_TIME);
+ while (gWaitingOnGuestSelection) gtk_main_iteration();
+
+ gWaitingOnGuestSelection = TRUE;
+ gtk_selection_convert(gUserMainWidget,
+ GDK_SELECTION_CLIPBOARD,
+ GDK_SELECTION_TYPE_STRING,
+ GDK_CURRENT_TIME);
+ while (gWaitingOnGuestSelection) gtk_main_iteration();
+ }
+ }
+ /* Send text to host. */
+ Debug("CopyPaste_RequestSelection: Prim is [%s], Clip is [%s]\n",
+ gGuestSelPrimaryBuf, gGuestSelClipboardBuf);
+ CopyPasteSetBackdoorSelections();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteSelectionReceivedCB --
+ *
+ * Callback for the gtk signal "selection_recieved".
+ * Called because we previously requested a copy/paste selection and
+ * finally got results of that asynchronous operation. After some basic
+ * sanity checks, send the result (in selection_data) thru the backdoor
+ * (version 1) or guestRPC (version 2) so the vmx can copy it to host
+ * clipboard.
+ *
+ * We made several requests for selections, the string (actual data) and
+ * file list for each of PRIMARY and CLIPBOARD selections. So this funtion
+ * will get called several times, once for each request.
+ *
+ * For guest->host copy/paste (both text and file).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteSelectionReceivedCB(GtkWidget *widget, // IN: unused
+ GtkSelectionData *selection_data, // IN: requested data
+ gpointer data) // IN: unused
+{
+ char *target;
+ char *utf8Str = NULL;
+ size_t len;
+ size_t aligned_len;
+
+ if ((widget == NULL) || (selection_data == NULL)) {
+ Debug("CopyPasteSelectionReceivedCB: Error, widget or selection_data is invalid\n");
+ goto exit;
+ }
+
+ if (selection_data->length < 0) {
+ Debug("CopyPasteSelectionReceivedCB: Error, length less than 0\n");
+ goto exit;
+ }
+
+ /* Try to get clipboard or selection timestamp. */
+ if (selection_data->target == GDK_SELECTION_TYPE_TIMESTAMP) {
+ if (selection_data->selection == GDK_SELECTION_PRIMARY) {
+ if (selection_data->length == 4) {
+ gGuestSelPrimaryTime = *(uint32 *)selection_data->data;
+ Debug("CopyPasteSelectionReceivedCB: Got pri time [%"FMT64"u]\n",
+ gGuestSelPrimaryTime);
+ } else if (selection_data->length == 8) {
+ gGuestSelPrimaryTime = *(uint64 *)selection_data->data;
+ Debug("CopyPasteSelectionReceivedCB: Got pri time [%"FMT64"u]\n",
+ gGuestSelPrimaryTime);
+ } else {
+ Debug("CopyPasteSelectionReceivedCB: Unknown pri time. Size %d\n",
+ selection_data->length);
+ }
+ }
+ if (selection_data->selection == GDK_SELECTION_CLIPBOARD) {
+ if (selection_data->length == 4) {
+ gGuestSelClipboardTime = *(uint32 *)selection_data->data;
+ Debug("CopyPasteSelectionReceivedCB: Got clip time [%"FMT64"u]\n",
+ gGuestSelClipboardTime);
+ } else if (selection_data->length == 8) {
+ gGuestSelClipboardTime = *(uint64 *)selection_data->data;
+ Debug("CopyPasteSelectionReceivedCB: Got clip time [%"FMT64"u]\n",
+ gGuestSelClipboardTime);
+ } else {
+ Debug("CopyPasteSelectionReceivedCB: Unknown clip time. Size %d\n",
+ selection_data->length);
+ }
+ }
+ goto exit;
+ }
+
+ if (selection_data->selection == GDK_SELECTION_PRIMARY) {
+ target = gGuestSelPrimaryBuf;
+ } else if (selection_data->selection == GDK_SELECTION_CLIPBOARD) {
+ target = gGuestSelClipboardBuf;
+ } else {
+ goto exit;
+ }
+
+ utf8Str = selection_data->data;
+ len = strlen(selection_data->data);
+
+ if (selection_data->target != GDK_SELECTION_TYPE_STRING &&
+ selection_data->target != GDK_SELECTION_TYPE_UTF8_STRING) {
+ /* It is a file list. */
+ if (len >= MAX_SELECTION_BUFFER_LENGTH - 1) {
+ Warning("CopyPasteSelectionReceivedCB file list too long\n");
+ } else {
+ memcpy(target, selection_data->data, len + 1);
+ }
+ goto exit;
+ }
+
+ /*
+ * If target is GDK_SELECTION_TYPE_STRING, assume encoding is local code
+ * set. Convert to utf8 before send to vmx.
+ */
+ if (selection_data->target == GDK_SELECTION_TYPE_STRING &&
+ !CodeSet_CurrentToUtf8(selection_data->data,
+ selection_data->length,
+ &utf8Str,
+ &len)) {
+ Debug("CopyPasteSelectionReceivedCB: Couldn't convert to utf8 code set\n");
+ gWaitingOnGuestSelection = FALSE;
+ return;
+ }
+
+ /*
+ * String in backdoor communication is 4 bytes by 4 bytes, so the len
+ * should be aligned to 4;
+ */
+ aligned_len = (len + 4) & ~3;
+ if (aligned_len >= MAX_SELECTION_BUFFER_LENGTH) {
+ /* With alignment, len is still possible to be less than max. */
+ if (len < (MAX_SELECTION_BUFFER_LENGTH - 1)) {
+ memcpy(target, utf8Str, len + 1);
+ } else {
+ memcpy(target, utf8Str, MAX_SELECTION_BUFFER_LENGTH - 1);
+ target[MAX_SELECTION_BUFFER_LENGTH - 1] ='\0';
+ }
+ } else {
+ memcpy(target, utf8Str, len + 1);
+ }
+
+exit:
+ if (selection_data->target == GDK_SELECTION_TYPE_STRING) {
+ free(utf8Str);
+ }
+ gWaitingOnGuestSelection = FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteSelectionGetCB --
+ *
+ * Callback for the gtk signal "selection_get".
+ * This is called when some other app requests the copy/paste selection,
+ * probably because we declare oursleves the selection owner on mouse
+ * grab. In text copy/paste case, we simply respond with contents of
+ * gHostClipboardBuf, which should have been set on mouse grab. In file
+ * copy/paste case, send file transfer request to host vmx, then return
+ * file list with right format according to different request.
+ * For host->guest copy/paste (both text and file).
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * An X message is sent to the requesting app containing the data, it
+ * will likely act on it in some way. In FCP case, may first start a
+ * host->guest file transfer. Add block if blocking driver is available,
+ * otherwise wait till file copy done.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteSelectionGetCB(GtkWidget *widget, // IN: unused
+ GtkSelectionData *selection_data, // IN: requested type
+ // OUT:the data to be sent
+ guint info, // IN: unused
+ guint time_stamp, // IN: unsued
+ gpointer data) // IN: unused
+{
+ const char *begin = NULL;
+ const char *end = NULL;
+ const char *next = NULL;
+ const char *pre = NULL;
+ const char *post = NULL;
+ size_t preLen = 0;
+ size_t postLen = 0;
+ size_t len = 0;
+ char *text = NULL;
+ size_t textLen = 1;
+ Bool blockAdded = FALSE;
+ Bool gnomeFCP = FALSE;
+ VmTimeType curTime;
+
+ if ((widget == NULL) || (selection_data == NULL)) {
+ Debug("CopyPasteSelectionGetCB: Error, widget or selection_data is invalid\n");
+ return;
+ }
+
+ /* If it is text copy paste, return gHostClipboardBuf. */
+ if (GDK_SELECTION_TYPE_STRING == selection_data->target ||
+ GDK_SELECTION_TYPE_UTF8_STRING == selection_data->target) {
+ char *outBuf = gHostClipboardBuf;
+ size_t len = strlen(gHostClipboardBuf);
+
+ /*
+ * If target is GDK_SELECTION_TYPE_STRING, assume encoding is local code
+ * set. Convert from utf8 to local one.
+ */
+ if (GDK_SELECTION_TYPE_STRING == selection_data->target &&
+ !CodeSet_Utf8ToCurrent(gHostClipboardBuf,
+ strlen(gHostClipboardBuf),
+ &outBuf,
+ &len)) {
+ Debug("CopyPasteSelectionGetCB: can not convert to current codeset\n");
+ return;
+ }
+
+ gtk_selection_data_set(selection_data, selection_data->target, 8,
+ outBuf, len);
+ Debug("CopyPasteSelectionGetCB: Set text [%s]\n", outBuf);
+
+ if (GDK_SELECTION_TYPE_STRING == selection_data->target) {
+ free(outBuf);
+ }
+
+ return;
+ }
+
+ if (selection_data->target != gFCPAtom[FCP_TARGET_INFO_URI_LIST] &&
+ selection_data->target != gFCPAtom[FCP_TARGET_INFO_GNOME_COPIED_FILES]) {
+ Debug("CopyPasteSelectionGetCB: Got unknown target\n");
+ return;
+ }
+
+ if (!gHGIsClipboardFCP) {
+ Debug("CopyPasteSelectionGetCB: no file list available\n");
+ return;
+ }
+
+ /*
+ * KDE may ask for clipboard content right after clipboard owner changed,
+ * and cause unexpected HG file copy. So HG FCP will return nothing for 1
+ * second after switch from host OS to guest OS. Please refer to bug 301971.
+ */
+ Hostinfo_GetTimeOfDay(&curTime);
+ if (curTime - gHGGetListTime < FCP_COPY_DELAY) {
+ Debug("%s: waiting for delay\n", __FUNCTION__);
+ return;
+ }
+
+ if (gHGFCPFileTransferStatus == FCP_FILE_TRANSFER_NOT_YET) {
+ if (GuestInfo_GetAvailableDiskSpace(gFileRoot) < gHGFCPTotalSize) {
+ Debug("CopyPasteSelectionGetCB no enough space to copy file from host.\n");
+ return;
+ }
+ /* Send host a rpc to start file transfer. */
+ if (!GuestApp_RpcSendOneCPName("copypaste.hg.copy.files", ' ',
+ gFileRoot, gFileRootSize)) {
+ Debug("CopyPasteSelectionGetCB: failed sending copypaste.hg.copy.files "
+ "with CPName");
+ return;
+ }
+ gHGFCPFileTransferStatus = FCP_FILE_TRANSFERRING;
+ }
+
+ if (gBlockFd > 0) {
+ /* Add a block on the staging directory for this command. */
+ if (DnD_AddBlock(gBlockFd, gFileRoot)) {
+ Debug("CopyPasteSelectionGetCB: add block [%s].\n", gFileRoot);
+ blockAdded = TRUE;
+ } else {
+ Warning("CopyPasteSelectionGetCB: Unable to add block [%s].\n", gFileRoot);
+ }
+ }
+
+ if (!blockAdded) {
+ /*
+ * If there is no blocking driver, wait here till file copy is done.
+ * 2 reasons to keep this:
+ * 1. If run vmware-user stand-alone as non-root, blocking driver can not
+ * be opened. Debug purpose only.
+ * 2. Other platforms (Solaris, FreeBSD, etc) may also use this code, and there
+ * is no blocking driver yet.
+ */
+ Debug("CopyPasteSelectionGetCB no blocking driver, waiting for "
+ "HG file copy done ...\n");
+ while (gHGFCPFileTransferStatus != FCP_FILE_TRANSFERRED) {
+ struct timeval tv;
+ int nr;
+
+ tv.tv_sec = 0;
+ nr = EventManager_ProcessNext(gEventQueue, (uint64 *)&tv.tv_usec);
+ if (nr != 1) {
+ Debug("CopyPasteSelectionGetCB unexpected end of loop: returned "
+ "value is %d.\n", nr);
+ return;
+ }
+ if (select(0, NULL, NULL, NULL, &tv) == -1) {
+ Debug("CopyPasteSelectionGetCB error in select (%s).\n",
+ strerror(errno));
+ return;
+ }
+ }
+
+ Debug("CopyPasteSelectionGetCB file transfer done!\n");
+ }
+
+ /* Setup the format string components */
+ if (selection_data->target == gFCPAtom[FCP_TARGET_INFO_URI_LIST]) {
+ Debug("CopyPasteSelectionGetCB Got uri_list request!\n");
+ pre = DND_URI_LIST_PRE_KDE;
+ preLen = sizeof DND_URI_LIST_PRE_KDE - 1;
+ post = DND_URI_LIST_POST;
+ postLen = sizeof DND_URI_LIST_POST - 1;
+ }
+ if (selection_data->target == gFCPAtom[FCP_TARGET_INFO_GNOME_COPIED_FILES]) {
+ Debug("CopyPasteSelectionGetCB Got gnome_copied request!\n");
+ pre = FCP_GNOME_LIST_PRE;
+ preLen = sizeof FCP_GNOME_LIST_PRE - 1;
+ post = FCP_GNOME_LIST_POST;
+ postLen = sizeof FCP_GNOME_LIST_POST - 1;
+ gnomeFCP = TRUE;
+
+ textLen += 5;
+ text = Util_SafeRealloc(text, textLen);
+ Str_Snprintf(text, 6, "copy\n");
+ }
+
+ if (!pre) {
+ Debug("CopyPasteSelectionGetCB: invalid drag target info\n");
+ return;
+ }
+
+
+ /*
+ * Set begin to first non-NUL character and end to last NUL character to
+ * prevent errors in calling CPName_GetComponent().
+ */
+ for(begin = gHostClipboardBuf; *begin == '\0'; begin++)
+ ;
+ end = CPNameUtil_Strrchr(gHostClipboardBuf, gGHFCPListSize + 1, '\0');
+ ASSERT(end);
+
+ /* Build up selection data */
+ while ((len = CPName_GetComponent(begin, end, &next)) != 0) {
+ const size_t origTextLen = textLen;
+ Bool freeBegin = FALSE;
+
+ if (len < 0) {
+ Debug("CopyPasteSelectionGetCB: error getting next component\n");
+ if (text) {
+ free(text);
+ }
+ return;
+ }
+
+ /*
+ * A URI list will expect the provided path to be escaped. If we cannot
+ * escape the path for some reason we just use the unescaped version and
+ * hope that it works.
+ */
+ if (selection_data->target == gFCPAtom[FCP_TARGET_INFO_URI_LIST]) {
+ size_t newLen;
+ char *escapedComponent;
+ int escIndex;
+ int bytesToEsc[256] = { 0, };
+
+ /* We escape the following characters based on RFC 1630. */
+ bytesToEsc['#'] = 1;
+ bytesToEsc['?'] = 1;
+ bytesToEsc['*'] = 1;
+ bytesToEsc['!'] = 1;
+ bytesToEsc['%'] = 1; /* Escape character */
+
+ /* Escape non-ASCII characters so we can pass UTF-8 filenames */
+ for (escIndex = 0x80; escIndex < 0x100; escIndex++) {
+ bytesToEsc[escIndex] = 1;
+ }
+
+ escapedComponent = Escape_Do('%', bytesToEsc, begin, len, &newLen);
+ if (escapedComponent) {
+ begin = escapedComponent;
+ len = newLen;
+ freeBegin = TRUE;
+ }
+ }
+
+ /*
+ * Append component. NUL terminator was accounted for by initializing
+ * textLen to one above.
+ */
+ textLen += preLen + len + postLen;
+ text = Util_SafeRealloc(text, textLen);
+
+ /*
+ * Bug 143147: Gnome FCP does not like the trailing newlines. We don't
+ * have this problem for targets that ask for URI lists. So we don't see
+ * this problem on:
+ * - KDE which asks for URI lists during FCP
+ * - DnD in both Gnome and KDE since they ask for URI lists.
+ *
+ * This is a problem only for Gnome FCP which expects a specially
+ * formatted 'copy' command string containing the file list which it then
+ * converts into a URI list internally.
+ */
+ Str_Snprintf(text + origTextLen - 1,
+ textLen - origTextLen + 1,
+ "%s%s%s", pre, begin, gnomeFCP && next == end ? "" : post);
+
+ if (freeBegin) {
+ free((void *)begin);
+ }
+
+ /* Iterate to next component */
+ begin = next;
+ }
+
+ /*
+ * Send out the data using the selection system. When sending a string, GTK will
+ * ensure that a null terminating byte is added to the end so we do not need to
+ * add it. GTK also copies the data so the original will never be modified.
+ */
+ Debug("CopyPasteSelectionGetCB: set file list [%s]\n", text);
+ gtk_selection_data_set(selection_data, selection_data->target,
+ 8, /* 8 bits per character. */
+ text, textLen);
+ free(text);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteSelectionClearCB --
+ *
+ * Callback for the gtk signal "selection_clear".
+ *
+ * Results:
+ * Always TRUE.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gint
+CopyPasteSelectionClearCB(GtkWidget *widget, // IN: unused
+ GdkEventSelection *event, // IN: unused
+ gpointer data) // IN: unused
+{
+ Debug("CopyPasteSelectionClearCB got clear signal\n");
+ gIsOwner = FALSE;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteSetBackdoorSelections --
+ *
+ * Set the clipboard one of two ways, the old way or the new way.
+ * The old way uses GuestApp_SetSel and there's only one selection.
+ * Set backdoor selection with either primary selection or clipboard.
+ * The primary selection is the first priority, then clipboard.
+ * If both unavailable, set backdoor selection length to be 0.
+ * This will be used by older VMXs or VMXs on Windows hosts (which
+ * has only one clipboard). Doing this gives us backwards
+ * compatibility.
+ *
+ * The new way uses new sets both PRIMARY and CLIPBOARD. Newer Linux
+ * VMXs will use these rather than the above method and have the two
+ * selections set separately.
+ *
+ * XXX: The "new way" doesn't exist yet, the vmx has no support for it.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The VMX probably changes some string buffers.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteSetBackdoorSelections(void)
+{
+ uint32 const *p;
+ size_t len;
+ size_t aligned_len;
+ size_t primaryLen;
+ size_t clipboardLen;
+ unsigned int i;
+
+ primaryLen = strlen(gGuestSelPrimaryBuf);
+ clipboardLen = strlen(gGuestSelClipboardBuf);
+
+ if (primaryLen) {
+ /*
+ * Send primary selection to backdoor if it exists.
+ */
+ p = (uint32 const *)gGuestSelPrimaryBuf;
+ } else if (clipboardLen) {
+ /*
+ * Otherwise send clipboard to backdoor if it exists.
+ */
+ p = (uint32 const *)gGuestSelClipboardBuf;
+ } else {
+ /*
+ * Neither selection is set
+ */
+ p = NULL;
+ }
+
+ if (p == NULL) {
+ GuestApp_SetSelLength(0);
+ Debug("CopyPasteSetBackdoorSelections Set empty text.\n");
+ } else {
+ len = strlen((char *)p);
+ Debug("CopyPasteSetBackdoorSelections Set text [%s].\n", (char *)p);
+ aligned_len = (len + 4) & ~3;
+
+ /* Here long string should already be truncated. */
+ ASSERT(aligned_len <= MAX_SELECTION_BUFFER_LENGTH);
+
+ GuestApp_SetSelLength(len);
+ for (i = 0; i < len; i += 4, p++) {
+ GuestApp_SetNextPiece(*p);
+ }
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPaste_GetBackdoorSelections --
+ *
+ * Get the clipboard "the old way".
+ * The old way uses GuestApp_SetSel and there's only one selection.
+ * We don't have to do anything for the "new way", since the host
+ * will just push PRIMARY and/or CLIPBOARD when they are available
+ * on the host.
+ *
+ * XXX: the "new way" isn't availble yet because the vmx doesn't
+ * implement separate clipboards. Even when it does this
+ * function will still exist for backward compatibility
+ *
+ * Results:
+ * TRUE if selection length>=0, FLASE otherwise.
+ *
+ * Side effects:
+ * This application becomes the selection owner for PRIMARY and/or
+ CLIPBOARD selections.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+CopyPaste_GetBackdoorSelections(void)
+{
+ int selLength;
+ int iAtom;
+
+ if (gVmxCopyPasteVersion > 1) {
+ return TRUE;
+ }
+
+ selLength = GuestApp_GetHostSelectionLen();
+ if (selLength < 0) {
+ return FALSE;
+ } else if (selLength > 0) {
+ memset(gHostClipboardBuf, 0, sizeof (gHostClipboardBuf));
+ GuestApp_GetHostSelection(selLength, gHostClipboardBuf);
+ Debug("CopyPaste_GetBackdoorSelections Get text [%s].\n", gHostClipboardBuf);
+ gtk_selection_owner_set(gUserMainWidget,
+ GDK_SELECTION_CLIPBOARD,
+ GDK_CURRENT_TIME);
+ gtk_selection_owner_set(gUserMainWidget,
+ GDK_SELECTION_PRIMARY,
+ GDK_CURRENT_TIME);
+ gIsOwner = TRUE;
+ gHGIsClipboardFCP = FALSE;
+ for (iAtom = 0; iAtom < NR_FCP_TARGETS; iAtom++) {
+ CopyPasteSelectionRemoveTarget(gUserMainWidget,
+ GDK_SELECTION_PRIMARY,
+ gFCPAtom[iAtom]);
+ CopyPasteSelectionRemoveTarget(gUserMainWidget,
+ GDK_SELECTION_CLIPBOARD,
+ gFCPAtom[iAtom]);
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteRpcInGHSetDataCB --
+ *
+ * Handler function for the "copypaste.gh.data.get" RPC command. Host is
+ * asking for clipboard contents for guest->host copy/paste. If both primary
+ * selection and clipboard are empty, the empty list should also be sent back
+ * because Host should release clipboard owner.
+ *
+ * For Guest->Host copy/paste operations only.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * The owner of the clipboard will get requests from our application.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+CopyPasteRpcInGHSetDataCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // Ignored
+{
+ int iAtom;
+ GdkAtom activeSelection = GDK_SELECTION_PRIMARY;
+ char *source = gGuestSelPrimaryBuf;
+ char format[256];
+ char *rpcBody = NULL;
+ size_t rpcBodySize = 0;
+
+ gGuestSelPrimaryBuf[0] = '\0';
+ gGuestSelClipboardBuf[0] = '\0';
+
+ if (gIsOwner) {
+ Debug("CopyPasteRpcInGHSetDataCB Send empty buf to host\n");
+ return RpcIn_SetRetVals(result, resultLen, "", TRUE);
+ }
+
+ /* First check which one is newer, primary selection or clipboard. */
+ gGuestSelPrimaryTime = 0;
+ gGuestSelClipboardTime = 0;
+
+ gWaitingOnGuestSelection = TRUE;
+ gtk_selection_convert(gUserMainWidget,
+ GDK_SELECTION_PRIMARY,
+ GDK_SELECTION_TYPE_TIMESTAMP,
+ GDK_CURRENT_TIME);
+ while (gWaitingOnGuestSelection) gtk_main_iteration();
+
+ gWaitingOnGuestSelection = TRUE;
+ gtk_selection_convert(gUserMainWidget,
+ GDK_SELECTION_CLIPBOARD,
+ GDK_SELECTION_TYPE_TIMESTAMP,
+ GDK_CURRENT_TIME);
+ while (gWaitingOnGuestSelection) gtk_main_iteration();
+
+ if (gGuestSelPrimaryTime < gGuestSelClipboardTime) {
+ activeSelection = GDK_SELECTION_CLIPBOARD;
+ source = gGuestSelClipboardBuf;
+ }
+
+try_again:
+ /* Check if it is file list in the active selection. */
+ for (iAtom = 0; iAtom < NR_FCP_TARGETS; iAtom++) {
+ gWaitingOnGuestSelection = TRUE;
+ gtk_selection_convert(gUserMainWidget,
+ activeSelection,
+ gFCPAtom[iAtom],
+ GDK_CURRENT_TIME);
+ while (gWaitingOnGuestSelection) gtk_main_iteration();
+ if (source[0] != '\0') {
+ if (gVmxCopyPasteVersion < 2) {
+ /* Only vmx version greater than 2 support file copy/paste. */
+ Debug("CopyPasteRpcInGHSetDataCB invalid operation\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "invalid operation", FALSE);
+ }
+ break;
+ }
+ }
+
+ if (source[0] != '\0') {
+ char *currName;
+ size_t currSize;
+ size_t index = 0;
+ char *ghFileList = NULL;
+ size_t ghFileListSize = 0;
+
+ /*
+ * In gnome, before file list there may be a extra line indicating it
+ * is a copy or cut.
+ */
+ if (strncmp(source, "copy", 4) == 0) {
+ source += 4;
+ }
+ if (strncmp(source, "cut", 3) == 0) {
+ source += 3;
+ }
+
+ while (*source == '\n' || *source == '\r' || *source == ' ') {
+ source++;
+ }
+
+ /*
+ * Get the the full filenames and last components from the URI list. The
+ * body of the RPC message will be these last components delimited with
+ * NUL characters; the Guest->Host file list will be the full paths
+ * delimited by NUL characters.
+ */
+ while ((currName = DnD_UriListGetNextFile(source,
+ &index,
+ &currSize))) {
+ size_t lastComponentSize;
+ char *lastComponentStart;
+
+ /* Append current filename to Guest->Host list */
+ ghFileList = Util_SafeRealloc(ghFileList,
+ ghFileListSize + currSize + 1);
+ memcpy(ghFileList + ghFileListSize, currName, currSize);
+ ghFileListSize += currSize;
+ ghFileList[ghFileListSize] = '\0';
+ ghFileListSize++;
+
+ /* Append last component to RPC body */
+ lastComponentStart = CPNameUtil_Strrchr(currName, currSize, DIRSEPC);
+ if (!lastComponentStart) {
+ /*
+ * This shouldn't happen since filenames are absolute, but handle
+ * it as if the file name is the last component
+ */
+ lastComponentStart = currName;
+ } else {
+ /* Skip the last directory separator */
+ lastComponentStart++;
+ }
+
+ lastComponentSize = currName + currSize - lastComponentStart;
+ rpcBody = Util_SafeRealloc(rpcBody, rpcBodySize + lastComponentSize + 1);
+ memcpy(rpcBody + rpcBodySize, lastComponentStart, lastComponentSize);
+ rpcBodySize += lastComponentSize;
+ rpcBody[rpcBodySize] = '\0';
+ rpcBodySize++;
+
+ free(currName);
+ }
+
+ if (!ghFileList || !rpcBody) {
+ Warning("CopyPasteRpcInGHSetDataCB: no filenames retrieved "
+ "from URI list\n");
+ free(ghFileList);
+ free(rpcBody);
+ return RpcIn_SetRetVals(result, resultLen,
+ "error retrieving file name", FALSE);
+ }
+
+ /* Set the list of full paths */
+ CopyPasteGHFileListSet(ghFileList, ghFileListSize);
+
+ /* rpcBody (and its size) will always contain a trailing NUL character */
+ rpcBodySize--;
+ Debug("CopyPasteRpcInGHSetDataCB: Sending: [%s] (%zu)\n",
+ CPName_Print(rpcBody, rpcBodySize), rpcBodySize);
+
+ Str_Sprintf(format, sizeof format, "%d ", CPFORMAT_FILELIST);
+ *resultLen = rpcBodySize + strlen(format);
+
+ free(gGHFCPRpcResultBuffer);
+ gGHFCPRpcResultBuffer = Util_SafeCalloc(1, rpcBodySize + strlen(format));
+
+ memcpy(gGHFCPRpcResultBuffer, format, strlen(format));
+ memcpy(gGHFCPRpcResultBuffer + strlen(format), rpcBody, rpcBodySize);
+ free(rpcBody);
+ *result = gGHFCPRpcResultBuffer;
+ return TRUE;
+ } else {
+ /* Try to get utf8 text from active selection. */
+ gWaitingOnGuestSelection = TRUE;
+ gtk_selection_convert(gUserMainWidget,
+ activeSelection,
+ GDK_SELECTION_TYPE_UTF8_STRING,
+ GDK_CURRENT_TIME);
+ while (gWaitingOnGuestSelection) gtk_main_iteration();
+
+ if (source[0] == '\0') {
+ /* Try to get text from active selection. */
+ gWaitingOnGuestSelection = TRUE;
+ gtk_selection_convert(gUserMainWidget,
+ activeSelection,
+ GDK_SELECTION_TYPE_STRING,
+ GDK_CURRENT_TIME);
+ while (gWaitingOnGuestSelection) gtk_main_iteration();
+ }
+
+ /*
+ * With 'cut' operation OpenOffice will put data into clipboard but
+ * set same timestamp for both clipboard and primary selection.
+ * If primary timestamp is same as clipboard timestamp, we should try
+ * clipboard again if primary selection is empty. For details please
+ * refer to bug 300780.
+ */
+ if (source[0] == '\0' &&
+ gGuestSelPrimaryTime == gGuestSelClipboardTime &&
+ gGuestSelPrimaryTime != 0) {
+ gGuestSelPrimaryTime = 0;
+ gGuestSelClipboardTime = 0;
+ activeSelection = GDK_SELECTION_CLIPBOARD;
+ source = gGuestSelClipboardBuf;
+ goto try_again;
+ }
+
+ if (source[0] != '\0') {
+ free(gGHFCPRpcResultBuffer);
+
+ gGHFCPRpcResultBuffer =
+ Str_Asprintf(NULL, "%d %s", CPFORMAT_TEXT, source);
+
+ if (!gGHFCPRpcResultBuffer) {
+ Debug("CopyPasteRpcInGHSetDataCB failed to alloc memory.\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "error allocating memory", FALSE);
+ }
+
+ *result = gGHFCPRpcResultBuffer;
+ *resultLen = strlen(gGHFCPRpcResultBuffer);
+
+ Debug("CopyPasteRpcInGHSetDataCB creating text: %s\n", source);
+
+ return TRUE;
+ }
+ /* Neither file list nor text is available, send empty list back. */
+ Debug("CopyPasteRpcInGHSetDataCB Send empty buf to host\n");
+ return RpcIn_SetRetVals(result, resultLen, "", TRUE);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPasteRpcInGHFinishCB --
+ *
+ * For Guest->Host operations only.
+ *
+ * Invoked when host side of copyPaste operation has finished.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+CopyPasteRpcInGHFinishCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // IN
+{
+ char *effect = NULL;
+ unsigned int index = 0;
+
+ gFcpGHState.fileListNext = gFcpGHState.fileList;
+
+ effect = StrUtil_GetNextToken(&index, args, " ");
+ if (!effect) {
+ Warning("CopyPasteRpcInGHFinishCB: no drop effect provided\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "drop effect not provided", FALSE);
+ }
+
+ Debug("CopyPasteRpcInGHFinishCB got effect %s\n", effect);
+
+ free(effect);
+ return RpcIn_SetRetVals(result, resultLen, "", TRUE);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPasteGHFileListClear --
+ *
+ * Clears existing Guest->Host file list, releasing any used resources.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+CopyPasteGHFileListClear(void)
+{
+ Debug("CopyPasteGHFileListClear: clearing G->H file list\n");
+ if (gFcpGHState.fileList) {
+ free(gFcpGHState.fileList);
+ gFcpGHState.fileList = NULL;
+ }
+ gFcpGHState.fileListSize = 0;
+ gFcpGHState.fileListNext = NULL;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPasteGHFileListSet --
+ *
+ * Sets the Guest->Host file list that is accessed through
+ * CopyPasteGHFileListGetNext().
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Clears the existing Guest->Host file list if it exists.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+CopyPasteGHFileListSet(char *fileList, // IN: new Guest->Host file list
+ size_t fileListSize) // IN: size of the provided list
+{
+ CopyPasteGHFileListClear();
+ gFcpGHState.fileList = fileList;
+ gFcpGHState.fileListSize = fileListSize;
+ gFcpGHState.fileListNext = fileList;
+
+ Debug("CopyPasteGHFileListSet: [%s] (%"FMTSZ"u)\n",
+ CPName_Print(gFcpGHState.fileList, gFcpGHState.fileListSize),
+ gFcpGHState.fileListSize);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPasteGHFileListGetNext --
+ *
+ * Retrieves the next file in the Guest->Host file list.
+ *
+ * Note that this function may only be called after calling
+ * CopyPasteGHFileListSet() and before calling CopyPasteGHFileListClear().
+ *
+ * Results:
+ * TRUE on success, FALSE on failure. If TRUE is returned, fileName is
+ * given a pointer to the filename's location or NULL if there are no more
+ * files, and fileNameSize is given the length of fileName.
+ *
+ * Side effects:
+ * The fileListNext value of the Guest->Host global state is updated.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CopyPasteGHFileListGetNext(char **fileName, // OUT: fill with filename location
+ size_t *fileNameSize) // OUT: fill with filename length
+{
+ char const *end;
+ char const *next;
+ int len;
+
+ ASSERT(gFcpGHState.fileList);
+ ASSERT(gFcpGHState.fileListNext);
+ ASSERT(gFcpGHState.fileListSize > 0);
+
+ /* Ensure end is the last NUL character */
+ end = CPNameUtil_Strrchr(gFcpGHState.fileList,
+ gFcpGHState.fileListSize,
+ '\0');
+ ASSERT(end);
+
+ /* Get the length of this filename and a pointer to the next one */
+ len = CPName_GetComponent(gFcpGHState.fileListNext, end, &next);
+ if (len < 0) {
+ Warning("CopyPasteGHFileListGetNext: error retrieving next component\n");
+ return FALSE;
+ }
+
+ /* No more entries in the list */
+ if (len == 0) {
+ Debug("CopyPasteGHFileListGetNext: no more entries\n");
+ *fileName = NULL;
+ *fileNameSize = 0;
+ gFcpGHState.fileListNext = gFcpGHState.fileList;
+ return TRUE;
+ }
+
+ Debug("CopyPasteGHFileListGetNext: returning [%s] (%d)\n",
+ gFcpGHState.fileListNext, len);
+
+ *fileName = gFcpGHState.fileListNext;
+ *fileNameSize = len;
+ gFcpGHState.fileListNext = (char *)next;
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteHGSetData --
+ *
+ * Host is sending text for copy/paste.
+ *
+ * RPC command format:
+ * 1. Format
+ * 2. Size of text
+ * 3. If text size > 0, then followed by text, otherwise nothing
+ *
+ * For Host->Guest operations only.
+ *
+ * Results:
+ * TRUE on success, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+CopyPasteHGSetData(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *args) // IN
+{
+ char *format = NULL;
+ char *sSize = NULL;
+ uint32 textSize;
+ unsigned int index = 0;
+ Bool ret = FALSE;
+ int iAtom;
+
+ /* Parse value string. */
+ format = StrUtil_GetNextToken(&index, args, " ");
+ index++; /* Ignore leading space before data. */
+ sSize = StrUtil_GetNextToken(&index, args, " ");
+ index++;
+ if (!format || !sSize) {
+ Debug("CopyPasteHGSetData failed to parse format & size\n");
+ ret = RpcIn_SetRetVals(result, resultLen,
+ "format and size is not completed", FALSE);
+ goto exit;
+ }
+
+ textSize = atoi(sSize);
+ gHostClipboardBuf[0] = '\0';
+
+ if (textSize > 0) {
+ if (textSize >= MAX_SELECTION_BUFFER_LENGTH) {
+ textSize = MAX_SELECTION_BUFFER_LENGTH - 1;
+ }
+ memcpy(gHostClipboardBuf, args + index, textSize);
+ gHostClipboardBuf[textSize] = '\0';
+ Debug("CopyPasteHGSetData: Set text [%s]\n", gHostClipboardBuf);
+ }
+
+ gtk_selection_owner_set(gUserMainWidget,
+ GDK_SELECTION_CLIPBOARD,
+ GDK_CURRENT_TIME);
+ gtk_selection_owner_set(gUserMainWidget,
+ GDK_SELECTION_PRIMARY,
+ GDK_CURRENT_TIME);
+ gIsOwner = TRUE;
+ gHGIsClipboardFCP = FALSE;
+
+ /* We put text into selection, so remove file target types from list. */
+ for (iAtom = 0; iAtom < NR_FCP_TARGETS; iAtom++) {
+ CopyPasteSelectionRemoveTarget(gUserMainWidget,
+ GDK_SELECTION_PRIMARY,
+ gFCPAtom[iAtom]);
+ CopyPasteSelectionRemoveTarget(gUserMainWidget,
+ GDK_SELECTION_CLIPBOARD,
+ gFCPAtom[iAtom]);
+ }
+
+ ret = RpcIn_SetRetVals(result, resultLen, "", TRUE);
+
+exit:
+ free(format);
+ free(sSize);
+ return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteRpcInHGDataFinishCB --
+ *
+ * For Host->Guest operations only.
+ * Host has finished transferring copyPaste data to the guest. We do any
+ * post H->G operation cleanup here, like picking a new file root.
+ *
+ * Results:
+ * TRUE on success, FALSE otherwise
+ *
+ * Side effects:
+ * Copied files will be deleted in error or cancel case.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+CopyPasteRpcInHGDataFinishCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // IN: pointer to mainWnd
+{
+ unsigned int index = 0;
+ char *state;
+
+ Debug("CopyPasteRpcInHGDataFinishCB received copypaste data finish\n");
+
+ state = StrUtil_GetNextToken(&index, args, " ");
+
+ if (!state) {
+ Debug("CopyPasteRpcInHGDataFinishCB failed to parse data state\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "must specify data finish state", FALSE);
+ }
+
+ if (strcmp(state, "success") != 0) {
+ Debug("CopyPasteRpcInHGDataFinishCB data transfer error\n");
+ /*
+ * Delete staging directory in error or cancel case, otherwise
+ * target application may still try to get copied files because
+ * the file list is provided right after adding block to staging
+ * directory.
+ */
+ File_DeleteDirectoryTree(gFileRoot);
+ }
+
+ free(state);
+
+ ASSERT(gHGFCPFileTransferStatus == FCP_FILE_TRANSFERRING);
+ gHGFCPFileTransferStatus = FCP_FILE_TRANSFERRED;
+
+ if (gBlockFd > 0 && !DnD_RemoveBlock(gBlockFd, gFileRoot)) {
+ Warning("CopyPasteRpcInHGDataFinishCB: Unable to remove block [%s].\n",
+ gFileRoot);
+ }
+
+ /* get new root dir for next FCP operation. */
+ gFileRootSize = DnD_GetNewFileRoot(gFileRoot, sizeof gFileRoot);
+
+ Debug("CopyPasteRpcInHGDataFinishCB create staging dir [%s]\n", gFileRoot);
+
+ return RpcIn_SetRetVals(result, resultLen, "", TRUE);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteHGSetFileList --
+ *
+ * Host is sending file list for FCP (file copy/paste).
+ *
+ * RPC command format:
+ * 1. Format
+ * 2. Total size of all files in the list
+ * 3. Size of file list string
+ * 4. If list size > 0, then followed by file list, otherwise nothing
+ *
+ * For Host->Guest FCP operations only.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+CopyPasteHGSetFileList(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *args) // IN
+{
+ char *format = NULL;
+ char *data = NULL;
+ char *sListSize = NULL;
+ size_t listSize;
+ char *sTotalSize = NULL;
+ char *stagingDirName = NULL;
+ char mountDirName[DND_MAX_PATH];
+ unsigned int index = 0;
+ Bool ret = FALSE;
+ char *retStr;
+ int iAtom;
+
+ gHGFCPFileTransferStatus = FCP_FILE_TRANSFER_NOT_YET;
+ /* Parse value string. */
+ format = StrUtil_GetNextToken(&index, args, " ");
+ index++; /* Ignore leading space before data. */
+ sTotalSize = StrUtil_GetNextToken(&index, args, " ");
+ index++;
+ sListSize = StrUtil_GetNextToken(&index, args, " ");
+ index++;
+ if (!format || !sTotalSize || !sListSize) {
+ Debug("CopyPasteHGSetFileList failed to parse format & size\n");
+ retStr = "format or size is not completed";
+ goto exit;
+ }
+
+ listSize = atoi(sListSize);
+ /*
+ * Total file size in selection list. This is used to check if there is enough
+ * space in guest OS for host->guest file transfer.
+ */
+ gHGFCPTotalSize = atol(sTotalSize);
+
+ if (listSize <= 0) {
+ Debug("CopyPasteHGSetFileList: got empty list\n");
+ gHostClipboardBuf[0] = '\0';
+ retStr = "";
+ ret = TRUE;
+ goto exit;
+ }
+
+ /*
+ * XXX Should do code set convertion here from utf8 to current for file list,
+ * but right now should not do that. The reason is that the hgfs server
+ * always puts utf8 file name into guest, which is not right if local guest
+ * encoding is non-utf8. DnD has same problem.
+ */
+
+ data = (char *)Util_SafeCalloc(1, listSize + 1);
+ memcpy(data, args + index, listSize);
+ data[listSize] = '\0';
+
+ if (gBlockFd > 0) {
+ /*
+ * Here we take the last component of the actual file root, which is
+ * a temporary directory for this DnD operation, and append it to the
+ * mount point for vmblock. This is where we want the target application
+ * to access the file since it will enable vmblock to block that
+ * application's progress if necessary.
+ */
+ stagingDirName = DnD_GetLastDirName(gFileRoot);
+ if (!stagingDirName) {
+ Debug("CopyPasteHGSetFileList: error construct stagingDirName\n");
+ retStr = "error construct stagingDirName";
+ goto exit;
+ }
+ if (sizeof VMBLOCK_MOUNT_POINT - 1 +
+ (sizeof DIRSEPS - 1) * 2 + strlen(stagingDirName) >= sizeof mountDirName) {
+ Debug("CopyPasteHGSetFileList: directory name too large.\n");
+ retStr = "directory name too large";
+ goto exit;
+ }
+ Str_Sprintf(mountDirName, sizeof mountDirName,
+ VMBLOCK_MOUNT_POINT DIRSEPS"%s"DIRSEPS, stagingDirName);
+ }
+
+ /* Add the file root to the relative paths received from host */
+ if (!DnD_PrependFileRoot(gBlockFd > 0 ? mountDirName : gFileRoot,
+ &data, &listSize)) {
+ Debug("CopyPasteHGSetFileList: error prepending guest file root\n");
+ retStr = "error prepending file root";
+ goto exit;
+ }
+
+ if (listSize + 1 > sizeof gHostClipboardBuf) {
+ Debug("CopyPasteHGSetFileList: data too large\n");
+ retStr = "data too large";
+ goto exit;
+ }
+
+ memcpy(gHostClipboardBuf, data, listSize + 1);
+ gGHFCPListSize = listSize;
+ gHGIsClipboardFCP = TRUE;
+ Debug("CopyPasteHGSetFileList: get file list [%s] (%zu)\n",
+ CPName_Print(gHostClipboardBuf, gGHFCPListSize), gGHFCPListSize);
+
+ for (iAtom = 0; iAtom < NR_FCP_TARGETS; iAtom++) {
+ gtk_selection_add_target(gUserMainWidget, GDK_SELECTION_PRIMARY,
+ gFCPAtom[iAtom], 0);
+ gtk_selection_add_target(gUserMainWidget, GDK_SELECTION_CLIPBOARD,
+ gFCPAtom[iAtom], 0);
+ }
+
+ Debug("CopyPasteHGSetFileList: added targets\n");
+ gtk_selection_owner_set(gUserMainWidget,
+ GDK_SELECTION_CLIPBOARD,
+ GDK_CURRENT_TIME);
+ gtk_selection_owner_set(gUserMainWidget,
+ GDK_SELECTION_PRIMARY,
+ GDK_CURRENT_TIME);
+ gIsOwner = TRUE;
+
+ retStr = "";
+ ret = TRUE;
+
+exit:
+ free(format);
+ free(data);
+ free(sTotalSize);
+ free(sListSize);
+ free(stagingDirName);
+ Hostinfo_GetTimeOfDay(&gHGGetListTime);
+ return RpcIn_SetRetVals(result, resultLen, retStr, ret);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteRpcInHGSetDataCB --
+ *
+ * Host is sending data for copy/paste. The data can be text, file list, etc.
+ *
+ * For Host->Guest operations only.
+ *
+ * Results:
+ * TRUE if success, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+CopyPasteRpcInHGSetDataCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // IN: ignored
+{
+ char *formatStr = NULL;
+ DND_CPFORMAT format;
+ Bool ret = FALSE;
+
+ unsigned int index = 0;
+
+ if (gHGFCPFileTransferStatus == FCP_FILE_TRANSFERRING) {
+ return RpcIn_SetRetVals(result, resultLen,
+ "", TRUE);
+ }
+
+ /* Parse value string. */
+ formatStr = StrUtil_GetNextToken(&index, args, " ");
+ index++; /* Ignore leading space before data. */
+
+ if (!formatStr) {
+ Debug("CopyPasteTcloHGDataSet failed to parse format\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "format and size is not completed", FALSE);
+ }
+
+ format = (DND_CPFORMAT)atoi(formatStr);
+ free(formatStr);
+
+ switch (format) {
+ case CPFORMAT_TEXT:
+ ret = CopyPasteHGSetData(result, resultLen, args);
+ break;
+ case CPFORMAT_FILELIST:
+ /* Only vmx version greater than 2 support file copy/paste. */
+ if (gVmxCopyPasteVersion < 2) {
+ Debug("CopyPasteRpcInHGSetDataCB invalid operation\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "invalid operation", FALSE);
+ }
+ ret = CopyPasteHGSetFileList(result, resultLen, args);
+ break;
+ default:
+ Debug("CopyPasteTcloHGDataSet unknown format\n");
+ ret = RpcIn_SetRetVals(result, resultLen,
+ "unknown format", FALSE);
+ break;
+ }
+
+ return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPasteRpcInGHGetNextFileCB --
+ *
+ * For Guest->Host operations only.
+ *
+ * Invoked when the host is compiling its list of files to copy from the
+ * guest. Here we provide the path of the next file in our Guest->Host file
+ * list in guest path format (for display purposes) and CPName format (for
+ * file copy operation).
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * Iterator pointer within file list of GH state is iterated to next list
+ * entry (through call to CopyPasteGHFileListGetNext()).
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+CopyPasteRpcInGHGetNextFileCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // IN
+{
+ static char resultBuffer[DND_MAX_PATH];
+ char *fileName;
+ size_t fileNameSize;
+ uint32 cpNameSize;
+ Bool res;
+
+ /*
+ * Retrieve a pointer to the next filename and its size from the list stored
+ * in the G->H DnD state. Note that fileName should not be free(3)d here
+ * since an additional copy is not allocated.
+ */
+ res = CopyPasteGHFileListGetNext(&fileName, &fileNameSize);
+
+ if (!res) {
+ Warning("CopyPasteRpcInGHGetNextFileCB: error retrieving file name\n");
+ return RpcIn_SetRetVals(result, resultLen, "error getting file", FALSE);
+ }
+
+ if (!fileName) {
+ /* There are no more files to send */
+ Debug("CopyPasteRpcInGHGetNextFileCB: reached end of Guest->Host file list\n");
+ return RpcIn_SetRetVals(result, resultLen, "|end|", TRUE);
+ }
+
+ if (fileNameSize + 1 + fileNameSize > sizeof resultBuffer) {
+ Warning("CopyPasteRpcInGHGetNextFileCB: filename too large (%"FMTSZ"u)\n", fileNameSize);
+ return RpcIn_SetRetVals(result, resultLen, "filename too large", FALSE);
+ }
+
+ /*
+ * Construct a reply message of the form:
+ * <file name in guest format><NUL><filename in CPName format>
+ */
+ memcpy(resultBuffer, fileName, fileNameSize);
+ resultBuffer[fileNameSize] = '\0';
+
+ cpNameSize = CPNameUtil_ConvertToRoot(fileName,
+ sizeof resultBuffer - (fileNameSize + 1),
+ resultBuffer + fileNameSize + 1);
+ if (cpNameSize < 0) {
+ Warning("CopyPasteRpcInGHGetNextFileCB: could not convert to CPName\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "error on CPName conversion", FALSE);
+ }
+
+ /* Set manually because RpcIn_SetRetVals() assumes no NUL characters */
+ *result = resultBuffer;
+ *resultLen = fileNameSize + 1 + cpNameSize;
+
+ Debug("CopyPasteRpcInGHGetNextFileCB: [%s] (%"FMTSZ"u)\n",
+ CPName_Print(*result, *resultLen), *resultLen);
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPaste_GetVmxCopyPasteVersion --
+ *
+ * Ask the vmx for it's copy/paste version.
+ *
+ * Results:
+ * The copy/paste version the vmx supports, 1 if the vmx doesn't know
+ * what we're talking about.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int32
+CopyPaste_GetVmxCopyPasteVersion(void)
+{
+ char *reply = NULL;
+ size_t replyLen;
+
+ if (!RpcOut_sendOne(&reply, &replyLen, "vmx.capability.copypaste_version")) {
+ Debug("CopyPaste_GetVmxCopyPasteVersion: could not get VMX copyPaste "
+ "version capability: %s\n", reply ? reply : "NULL");
+ gVmxCopyPasteVersion = 1;
+ } else {
+ gVmxCopyPasteVersion = atoi(reply);
+ }
+
+ free(reply);
+ Debug("CopyPaste_GetVmxCopyPasteVersion: got version %d\n", gVmxCopyPasteVersion);
+ return gVmxCopyPasteVersion;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPaste_RegisterCapability --
+ *
+ * Register the "copypaste" capability. Sometimes this needs to be done
+ * separately from the rest of copy/paste registration, so we provide it
+ * separately here.
+ *
+ * Results:
+ * TRUE on success
+ * FALSE on failure
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+CopyPaste_RegisterCapability(void)
+{
+ /* Tell the VMX about the copyPaste version we support. */
+ if (!RpcOut_sendOne(NULL, NULL, "tools.capability.copypaste_version 2")) {
+ Debug("CopyPaste_RegisterCapability: could not set guest copypaste "
+ "version capability\n");
+ gVmxCopyPasteVersion = 1;
+ return FALSE;
+ }
+ Debug("CopyPaste_RegisterCapability: set copypaste version 2\n");
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPaste_Register --
+ *
+ * Setup callbacks, initialize.
+ *
+ * Results:
+ * Always TRUE.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+CopyPaste_Register(GtkWidget* mainWnd)
+{
+ /* Text copy/paste initialization for all versions. */
+#ifndef GDK_SELECTION_CLIPBOARD
+ GDK_SELECTION_CLIPBOARD = gdk_atom_intern("CLIPBOARD", FALSE);
+#endif
+
+#ifndef GDK_SELECTION_TYPE_TIMESTAMP
+ GDK_SELECTION_TYPE_TIMESTAMP = gdk_atom_intern("TIMESTAMP", FALSE);
+#endif
+
+#ifndef GDK_SELECTION_TYPE_UTF8_STRING
+ GDK_SELECTION_TYPE_UTF8_STRING = gdk_atom_intern("UTF8_STRING", FALSE);
+#endif
+
+ gFCPAtom[FCP_TARGET_INFO_GNOME_COPIED_FILES] =
+ gdk_atom_intern(FCP_TARGET_NAME_GNOME_COPIED_FILES, FALSE);
+ gFCPAtom[FCP_TARGET_INFO_URI_LIST] =
+ gdk_atom_intern(FCP_TARGET_NAME_URI_LIST, FALSE);
+
+ /*
+ * String is always in supported list. FCP atoms will dynamically be
+ * added and removed.
+ */
+ gtk_selection_add_target(mainWnd, GDK_SELECTION_PRIMARY,
+ GDK_SELECTION_TYPE_STRING, 0);
+ gtk_selection_add_target(mainWnd, GDK_SELECTION_CLIPBOARD,
+ GDK_SELECTION_TYPE_STRING, 0);
+ gtk_selection_add_target(mainWnd, GDK_SELECTION_PRIMARY,
+ GDK_SELECTION_TYPE_UTF8_STRING, 0);
+ gtk_selection_add_target(mainWnd, GDK_SELECTION_CLIPBOARD,
+ GDK_SELECTION_TYPE_UTF8_STRING, 0);
+
+ gtk_signal_connect(GTK_OBJECT(mainWnd), "selection_received",
+ GTK_SIGNAL_FUNC(CopyPasteSelectionReceivedCB), mainWnd);
+ gtk_signal_connect(GTK_OBJECT(mainWnd), "selection_get",
+ GTK_SIGNAL_FUNC(CopyPasteSelectionGetCB), mainWnd);
+ gtk_signal_connect(GTK_OBJECT(mainWnd), "selection_clear_event",
+ GTK_SIGNAL_FUNC(CopyPasteSelectionClearCB), mainWnd);
+
+ RpcIn_RegisterCallback(gRpcIn, "copypaste.hg.data.set",
+ CopyPasteRpcInHGSetDataCB, NULL);
+ RpcIn_RegisterCallback(gRpcIn, "copypaste.hg.data.finish",
+ CopyPasteRpcInHGDataFinishCB, NULL);
+ RpcIn_RegisterCallback(gRpcIn, "copypaste.gh.data.get",
+ CopyPasteRpcInGHSetDataCB, NULL);
+ RpcIn_RegisterCallback(gRpcIn, "copypaste.gh.get.next.file",
+ CopyPasteRpcInGHGetNextFileCB, NULL);
+ RpcIn_RegisterCallback(gRpcIn, "copypaste.gh.finish",
+ CopyPasteRpcInGHFinishCB, NULL);
+
+ CopyPasteStateInit();
+ Wiper_Init(NULL);
+
+ return CopyPaste_RegisterCapability();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPaste_Unregister --
+ *
+ * Cleanup copy/paste related things.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * copy/paste is stopped, the rpc channel to the vmx is closed.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPaste_Unregister(GtkWidget* mainWnd)
+{
+ gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd),
+ GTK_SIGNAL_FUNC(CopyPasteSelectionReceivedCB),
+ mainWnd);
+ gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd),
+ GTK_SIGNAL_FUNC(CopyPasteSelectionGetCB),
+ mainWnd);
+ gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd),
+ GTK_SIGNAL_FUNC(CopyPasteSelectionClearCB),
+ mainWnd);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPaste_OnReset --
+ *
+ * Handles reinitializing Copy Paste state on a reset.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPaste_OnReset(void)
+{
+ if (gHGFCPFileTransferStatus == FCP_FILE_TRANSFERRING) {
+ File_DeleteDirectoryTree(gFileRoot);
+ if (gBlockFd > 0 && !DnD_RemoveBlock(gBlockFd, gFileRoot)) {
+ Warning("CopyPasteRpcInHGDataFinishCB: Unable to remove block [%s].\n",
+ gFileRoot);
+ }
+ gFileRootSize = DnD_GetNewFileRoot(gFileRoot, sizeof gFileRoot);
+ }
+
+ CopyPasteStateInit();
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPaste_InProgress --
+ *
+ * Indicates whether a copy/paste data transfer is currently in progress.
+ *
+ * Results:
+ * TRUE if in progress, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+CopyPaste_InProgress(void)
+{
+ /* XXX We currently have no way to determine if a G->H FCP is ongoing. */
+ return gHGFCPFileTransferStatus == FCP_FILE_TRANSFERRING;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPaste_IsRpcCPSupported --
+ *
+ * Check if RPC copy/paste is supported by vmx or not.
+ *
+ * Results:
+ * TRUE if RPC copy/paste is supported, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+CopyPaste_IsRpcCPSupported(void)
+{
+ return gVmxCopyPasteVersion > 1;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPasteStateInit --
+ *
+ * Initalialize CopyPaste State.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteStateInit(void)
+{
+ gHostClipboardBuf[0] = '\0';
+ gGuestSelPrimaryBuf[0] = '\0';
+ gGuestSelClipboardBuf[0] = '\0';
+ gIsOwner = FALSE;
+ gGHFCPRpcResultBuffer = NULL;
+ gHGFCPPending = FALSE;
+ gHGFCPFileTransferStatus = FCP_FILE_TRANSFER_NOT_YET;
+
+ if (CopyPaste_GetVmxCopyPasteVersion() >= 2) {
+ /*
+ * Create staging directory for file copy/paste. This is for vmx with version 2
+ * or greater.
+ */
+ gFileRootSize = DnD_GetNewFileRoot(gFileRoot, sizeof gFileRoot);
+ Debug("CopyPaste_Register create file root [%s]\n", gFileRoot);
+ }
+}
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * copyPasteUI.cpp --
+ *
+ * This class implements the methods that allows CopyPaste between host
+ * and guest.
+ *
+ * For a perspective on X copy/paste, see
+ * http://www.jwz.org/doc/x-cut-and-paste.html
+ */
+
+#include <sys/time.h>
+#include <time.h>
+#include "copyPasteUI.h"
+#include "dndFileList.hh"
+
+extern "C" {
+ #include "vmblock.h"
+ #include "vm_app.h"
+ #include "file.h"
+ #include "dnd.h"
+ #include "dndMsg.h"
+ #include "dndClipboard.h"
+ #include "cpName.h"
+ #include "debug.h"
+ #include "cpNameUtil.h"
+ #include "rpcout.h"
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::CopyPasteUI --
+ *
+ * Constructor.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+CopyPasteUI::CopyPasteUI()
+ : mClipboardEmpty(true),
+ mHGStagingDir(""),
+ mIsClipboardOwner(false),
+ mClipTimePrev(0),
+ mPrimTimePrev(0)
+{
+ Gtk::TargetEntry gnome(FCP_TARGET_NAME_GNOME_COPIED_FILES);
+ Gtk::TargetEntry kde(FCP_TARGET_NAME_URI_LIST);
+ gnome.set_info(FCP_TARGET_INFO_GNOME_COPIED_FILES);
+ kde.set_info(FCP_TARGET_INFO_URI_LIST);
+
+ mListTargets.push_back(gnome);
+ mListTargets.push_back(kde);
+
+ CPClipboard_Init(&mClipboard);
+
+ /* Tell the VMX about the copyPaste version we support. */
+ if (!RpcOut_sendOne(NULL, NULL, "tools.capability.copypaste_version 3")) {
+ Debug("%s: could not set guest copypaste version capability\n",
+ __FUNCTION__);
+ return;
+ }
+ Debug("%s: set copypaste version 3\n", __FUNCTION__);
+
+ mCP.newClipboard.connect(
+ sigc::mem_fun(this, &CopyPasteUI::GetRemoteClipboardCB));
+ mCP.localGetClipboard.connect(
+ sigc::mem_fun(this, &CopyPasteUI::GetLocalClipboard));
+ mCP.localGetFilesDoneChanged.connect(
+ sigc::mem_fun(this, &CopyPasteUI::GetLocalFilesDone));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::~CopyPaste --
+ *
+ * Destructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+CopyPasteUI::~CopyPasteUI()
+{
+ CPClipboard_Destroy(&mClipboard);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::VmxCopyPasteVersionChanged --
+ *
+ * Update version information in mCP.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::VmxCopyPasteVersionChanged(struct RpcIn *rpcIn, // IN
+ uint32 version) // IN
+{
+ Debug("%s: new version is %d\n", __FUNCTION__, version);
+ mCP.VmxCopyPasteVersionChanged(rpcIn, version);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::GetLocalClipboard --
+ *
+ * Retrives the data from local clipboard and sends it to host. Send empty
+ * data back if there is no data or can not get data successfully. For
+ * guest->host copy/paste.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+CopyPasteUI::GetLocalClipboard(CPClipboard *clip) // OUT
+{
+ Debug("%s: enter.\n", __FUNCTION__);
+
+ if (mIsClipboardOwner) {
+ Debug("%s: is clipboard owner, set changed to false and return.\n", __FUNCTION__);
+ CPClipboard_SetChanged(clip, FALSE);
+ return true;
+ }
+
+ if (!mCP.IsCopyPasteAllowed()) {
+ Debug("%s: copyPaste is not allowed\n", __FUNCTION__);
+ return true;
+ }
+
+ Glib::RefPtr<Gtk::Clipboard> refClipboard =
+ Gtk::Clipboard::get(GDK_SELECTION_CLIPBOARD);
+
+ mClipTime = 0;
+ mPrimTime = 0;
+ mGHSelection = GDK_SELECTION_CLIPBOARD;
+ Debug("%s: retrieving timestamps\n", __FUNCTION__);
+ refClipboard->request_contents(TARGET_NAME_TIMESTAMP,
+ sigc::mem_fun(this, &CopyPasteUI::LocalClipboardTimestampCB));
+ return false;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::GetCurrentTime --
+ *
+ * Get current time in microseconds.
+ *
+ * Results:
+ * Time in microseconds.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VmTimeType
+CopyPasteUI::GetCurrentTime(void)
+{
+ struct timeval tv;
+ VmTimeType curTime;
+
+ if (gettimeofday(&tv, NULL) != 0) {
+ Debug("%s: gettimeofday failed!\n", __FUNCTION__);
+ return (VmTimeType) 0;
+ }
+ curTime = (tv.tv_sec * 1000000 + tv.tv_usec);
+ return curTime;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::LocalGetFileRequestCB --
+ *
+ * Callback from a file paste request from another host application.
+ * Begins copying the files from guest to host and return the file list.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::LocalGetFileRequestCB(Gtk::SelectionData& sd, // IN:
+ guint info) // IN:
+{
+ Debug("%s: enter.\n", __FUNCTION__);
+ mHGCopiedUriList = "";
+ VmTimeType curTime;
+
+ curTime = GetCurrentTime();
+
+ /*
+ * Some applications may ask for clipboard contents right after clipboard
+ * owner changed. So GH FCP will return nothing for some time after switch
+ * from guest OS to host OS.
+ */
+ if ((curTime - mHGGetListTime) < FCP_COPY_DELAY) {
+ return;
+ }
+
+ if (!mIsClipboardOwner || !mCP.IsCopyPasteAllowed()) {
+ return;
+ }
+
+ Debug("%s: Got paste request, target is %s\n", __FUNCTION__,
+ sd.get_target().c_str());
+
+ /* Copy the files. */
+ if (!mHGGetFilesInitated) {
+ utf::string str;
+ utf::string hgStagingDir;
+ utf::string stagingDirName;
+ utf::string pre;
+ utf::string post;
+ size_t index = 0;
+
+ hgStagingDir = static_cast<utf::string>(mCP.GetFiles());
+ Debug("%s: Getting files. Staging dir: %s", __FUNCTION__,
+ hgStagingDir.c_str());
+
+ if (0 == hgStagingDir.bytes()) {
+ Debug("%s: Can not create staging directory\n", __FUNCTION__);
+ return;
+ }
+ mHGGetFilesInitated = true;
+
+ /* Provide URIs for each path in the guest's file list. */
+ if (FCP_TARGET_INFO_GNOME_COPIED_FILES == info) {
+ mHGCopiedUriList = "copy\n";
+ pre = FCP_GNOME_LIST_PRE;
+ post = FCP_GNOME_LIST_POST;
+ } else if (FCP_TARGET_INFO_URI_LIST == info) {
+ pre = DND_URI_LIST_PRE_KDE;
+ post = DND_URI_LIST_POST;
+ } else {
+ Debug("%s: Unknown request target: %s\n", __FUNCTION__,
+ sd.get_target().c_str());
+ return;
+ }
+
+ /* Provide path within vmblock file system instead of actual path. */
+ stagingDirName = GetLastDirName(hgStagingDir);
+ if (0 == stagingDirName.bytes()) {
+ Debug("%s: Can not get staging directory name\n", __FUNCTION__);
+ return;
+ }
+
+ while ((str = GetNextPath(mHGFCPData, index).c_str()).bytes() != 0) {
+ Debug("%s: Path: %s", __FUNCTION__, str.c_str());
+ mHGCopiedUriList += pre;
+ mHGCopiedUriList += VMBLOCK_MOUNT_POINT;
+ mHGCopiedUriList += DIRSEPS + stagingDirName + DIRSEPS + str + post;
+ }
+
+ /* Nautilus does not expect FCP_GNOME_LIST_POST after the last uri. See bug 143147. */
+ if (FCP_TARGET_INFO_GNOME_COPIED_FILES == info) {
+ mHGCopiedUriList.erase(mHGCopiedUriList.size() - 1, 1);
+ }
+ }
+
+ if (0 == mHGCopiedUriList.bytes()) {
+ Debug("%s: Can not get uri list\n", __FUNCTION__);
+ return;
+ }
+
+ Debug("%s: providing file list [%s]\n", __FUNCTION__,
+ mHGCopiedUriList.c_str());
+
+ sd.set(sd.get_target().c_str(), mHGCopiedUriList.c_str());
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPaste::LocalClearClipboardCB --
+ *
+ * Clear clipboard request from another host application.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::LocalClearClipboardCB(void)
+{
+ Debug("%s: got clear callback\n", __FUNCTION__);
+ mIsClipboardOwner = FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPasteUI::LocalClipboardTimestampCB --
+ *
+ * Got the local clipboard timestamp. Ask for the primary timestamp.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::LocalClipboardTimestampCB(const Gtk::SelectionData& sd) // IN
+{
+ int length = sd.get_length();
+ Debug("%s: enter sd.get_length() %d.\n", __FUNCTION__,
+ length);
+ if (length == 4) {
+ mClipTime = ((uint32*) sd.get_data())[0];
+ Debug("%s: mClipTime: %"FMT64"u.", __FUNCTION__, mClipTime);
+ } else if (length == 8) {
+ mClipTime = ((uint64*) sd.get_data())[0];
+ Debug("%s: mClipTime: %"FMT64"u.", __FUNCTION__, mClipTime);
+ } else {
+ Debug("%s: Unable to get mClipTime.", __FUNCTION__);
+ }
+
+ Glib::RefPtr<Gtk::Clipboard> refClipboard
+ = Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
+ refClipboard->request_contents(TARGET_NAME_TIMESTAMP,
+ sigc::mem_fun(this, &CopyPasteUI::LocalPrimTimestampCB));
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPasteUI::LocalPrimTimestampCB --
+ *
+ * Got the local primary timestamp. Choose the most recently changed
+ * clipboard and get the selection from it.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::LocalPrimTimestampCB(const Gtk::SelectionData& sd) // IN
+{
+ bool unchanged = FALSE;
+ int length = sd.get_length();
+ Debug("%s: enter sd.get_length() is %d.\n", __FUNCTION__, length);
+ if (length == 4) {
+ mPrimTime = ((uint32*) sd.get_data())[0];
+ Debug("%s: mPrimTime: %"FMT64"u.", __FUNCTION__, mPrimTime);
+ } else if (length == 8) {
+ mPrimTime = ((uint64*) sd.get_data())[0];
+ Debug("%s: mPrimTime: %"FMT64"u.", __FUNCTION__, mPrimTime);
+ } else {
+ Debug("%s: Unable to get mPrimTime.", __FUNCTION__);
+ }
+
+ /* After got both timestamp, choose latest one as active selection. */
+ mGHSelection = GDK_SELECTION_PRIMARY;
+ if (mClipTime > mPrimTime) {
+ mGHSelection = GDK_SELECTION_CLIPBOARD;
+ Debug("%s: mClipTimePrev: %"FMT64"u.", __FUNCTION__, mClipTimePrev);
+ unchanged = mClipTime <= mClipTimePrev;
+ } else {
+ Debug("%s: mPrimTimePrev: %"FMT64"u.", __FUNCTION__, mPrimTimePrev);
+ unchanged = mPrimTime <= mPrimTimePrev;
+ }
+
+ if (unchanged) {
+ Debug("%s: clipboard is unchanged, get out\n", __FUNCTION__);
+ CPClipboard_SetChanged(&mClipboard, FALSE);
+ return;
+ }
+
+ mPrimTimePrev = mPrimTime;
+ mClipTimePrev = mClipTime;
+
+ /* Ask for available targets from active selection. */
+ Glib::RefPtr<Gtk::Clipboard> refClipboard =
+ Gtk::Clipboard::get(mGHSelection);
+
+ refClipboard->request_targets(
+ sigc::mem_fun(this, &CopyPasteUI::LocalReceivedTargetsCB));
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPasteUI::LocalReceivedTargetsCB --
+ *
+ * Received targets. Check if any desired target available. If so,
+ * ask for all supported contents.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Clipboard owner may send us file list.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::LocalReceivedTargetsCB(const Glib::StringArrayHandle& targetsArray) // IN
+{
+ std::list<utf::string> targets = targetsArray;
+ Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get(mGHSelection);
+
+ Debug("%s: enter", __FUNCTION__);
+ CPClipboard_Clear(&mClipboard);
+
+ if (std::find(targets.begin(),
+ targets.end(),
+ FCP_TARGET_NAME_GNOME_COPIED_FILES) != targets.end()) {
+ Debug("%s: gnome copy file list available\n", __FUNCTION__);
+ refClipboard->request_contents(FCP_TARGET_NAME_GNOME_COPIED_FILES,
+ sigc::mem_fun(this,
+ &CopyPasteUI::LocalReceivedFileListCB));
+ return;
+ }
+
+ if (std::find(targets.begin(),
+ targets.end(),
+ FCP_TARGET_NAME_URI_LIST) != targets.end()) {
+ Debug("%s: KDE copy file list available\n", __FUNCTION__);
+ refClipboard->request_contents(FCP_TARGET_NAME_URI_LIST,
+ sigc::mem_fun(this,
+ &CopyPasteUI::LocalReceivedFileListCB));
+ return;
+ }
+
+ Debug("%s: ask for text\n", __FUNCTION__);
+ refClipboard->request_text(sigc::mem_fun(this,
+ &CopyPasteUI::LocalReceivedTextCB));
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPasteUI::LocalReceivedFileListCB --
+ *
+ * Got clipboard or primary selection file list. Parse it and add
+ * it to the crossplaform clipboard. Send clipboard to the guest.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::LocalReceivedFileListCB(const Gtk::SelectionData& sd) // IN
+{
+ Debug("%s: enter", __FUNCTION__);
+ const utf::string target = sd.get_target().c_str();
+
+ if (target == FCP_TARGET_NAME_GNOME_COPIED_FILES ||
+ target == FCP_TARGET_NAME_URI_LIST) {
+ LocalGetSelectionFileList(sd);
+ mCP.SetRemoteClipboard(&mClipboard);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CopyPasteUI::LocalReceivedTextCB --
+ *
+ * Got clipboard (or primary selection) text, add to local clipboard
+ * cache and send clipboard to guest.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::LocalReceivedTextCB(const Glib::ustring& text) // IN
+{
+ Debug("%s: enter", __FUNCTION__);
+ utf::string source = text;
+
+ /*
+ * With 'cut' operation OpenOffice will put data into clipboard but
+ * set same timestamp for both clipboard and primary selection.
+ * If primary timestamp is same as clipboard timestamp, we should try
+ * clipboard again if primary selection is empty. For details please
+ * refer to bug 300780.
+ */
+ if (0 == source.bytes() &&
+ mClipTime == mPrimTime &&
+ mClipTime != 0) {
+ mClipTime = 0;
+ mPrimTime = 0;
+ mGHSelection = GDK_SELECTION_CLIPBOARD;
+
+ /* Ask for available targets from active selection. */
+ Glib::RefPtr<Gtk::Clipboard> refClipboard =
+ Gtk::Clipboard::get(mGHSelection);
+
+ refClipboard->request_targets(
+ sigc::mem_fun(this, &CopyPasteUI::LocalReceivedTargetsCB));
+ return;
+ }
+
+ Debug("%s: Got text: %s", __FUNCTION__, source.c_str());
+
+ /* Add NUL terminator. */
+ CPClipboard_SetItem(&mClipboard, CPFORMAT_TEXT, source.c_str(),
+ source.bytes() + 1);
+ mCP.SetRemoteClipboard(&mClipboard);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::LocalGetSelectionFileList --
+ *
+ * Contruct local file list and remote file list from selection data.
+ * Called by both DnD and FCP.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::LocalGetSelectionFileList(const Gtk::SelectionData& sd) // IN
+{
+ utf::string source;
+ char *newPath;
+ char *newRelPath;
+ size_t newPathLen;
+ size_t index = 0;
+ DnDFileList fileList;
+ DynBuf buf;
+
+ /*
+ * Turn the uri list into two \0 delimited lists. One for full paths and
+ * one for just the last path component.
+ */
+ source = sd.get_data_as_string().c_str();
+ Debug("%s: Got file list: [%s]\n", __FUNCTION__, source.c_str());
+
+ /*
+ * In gnome, before file list there may be a extra line indicating it
+ * is a copy or cut.
+ */
+ if (source.startsWith("copy\n")) {
+ source = source.erase(0, 5);
+ }
+
+ if (source.startsWith("cut\n")) {
+ source = source.erase(0, 4);
+ }
+
+ while (source.bytes() > 0 &&
+ (source[0] == '\n' || source[0] == '\r' || source[0] == ' ')) {
+ source = source.erase(0, 1);
+ }
+
+ while ((newPath = DnD_UriListGetNextFile(source.c_str(),
+ &index,
+ &newPathLen)) != NULL) {
+
+ /*
+ * Parse relative path.
+ */
+ newRelPath = Str_Strrchr(newPath, DIRSEPC) + 1; // Point to char after '/'
+
+ fileList.AddFile(newPath, newRelPath);
+ free(newPath);
+ }
+
+ DynBuf_Init(&buf);
+ fileList.ToCPClipboard(&buf, true);
+ CPClipboard_SetItem(&mClipboard, CPFORMAT_FILELIST, DynBuf_Get(&buf),
+ DynBuf_GetSize(&buf));
+ DynBuf_Destroy(&buf);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::GetNextPath --
+ *
+ * Provides a substring containing the next path from the provided
+ * NUL-delimited string starting at the provided index.
+ *
+ * Results:
+ * A string with the next path or "" if there are no more paths.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+utf::utf8string
+CopyPasteUI::GetNextPath(utf::utf8string& str, // IN: NUL-delimited path list
+ size_t& index) // IN/OUT: current index into string
+{
+ utf::utf8string ret;
+ size_t start;
+
+ if (index >= str.length()) {
+ return "";
+ }
+
+ for (start = index; str[index] != '\0' && index < str.length(); index++) {
+ /*
+ * Escape reserved characters according to RFC 1630. We'd use
+ * Escape_Do() if this wasn't a utf::string, but let's use the same table
+ * replacement approach.
+ */
+ static char const Dec2Hex[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
+ };
+
+ unsigned char ubyte = str[index];
+
+ if (ubyte == '#' || /* Fragment identifier delimiter */
+ ubyte == '?' || /* Query string delimiter */
+ ubyte == '*' || /* "Special significance within specific schemes" */
+ ubyte == '!' || /* "Special significance within specific schemes" */
+ ubyte == '%' || /* Escape character */
+ ubyte >= 0x80) { /* UTF-8 encoding bytes */
+ str.replace(index, 1, "%");
+ str.insert(index + 1, 1, Dec2Hex[ubyte >> 4]);
+ str.insert(index + 2, 1, Dec2Hex[ubyte & 0xF]);
+ index += 2;
+ }
+ }
+
+ ret = str.substr(start, index - start);
+ Debug("%s: nextpath: %s", __FUNCTION__, ret.c_str());
+ index++;
+ return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::GetLastDirName --
+ *
+ * Try to get last directory name from a full path name.
+ *
+ * Results:
+ * Last dir name in the full path name if sucess, empty str otherwise
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+utf::string
+CopyPasteUI::GetLastDirName(const utf::string &str) // IN
+{
+ utf::string ret;
+ size_t start;
+ size_t end;
+
+ end = str.bytes() - 1;
+ if (end >= 0 && DIRSEPC == str[end]) {
+ end--;
+ }
+
+ if (end <= 0 || str[0] != DIRSEPC) {
+ return "";
+ }
+
+ start = end;
+
+ while (str[start] != DIRSEPC) {
+ start--;
+ }
+
+ return str.substr(start + 1, end - start);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::GetRemoteClipboardCB --
+ *
+ * Invoked when got data from host. Update the internal data to get the file
+ * names or the text that needs to be transferred.
+ *
+ * Method for copy and paste from host to guest.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::GetRemoteClipboardCB(const CPClipboard *clip) // IN
+{
+ Glib::RefPtr<Gtk::Clipboard> refClipboard =
+ Gtk::Clipboard::get(GDK_SELECTION_CLIPBOARD);
+ Glib::RefPtr<Gtk::Clipboard> refPrimary =
+ Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
+ void *buf;
+ size_t sz;
+
+ if (!clip) {
+ Debug("%s: No clipboard contents.", __FUNCTION__);
+ return;
+ }
+
+ /* Clear the clipboard contents if we are the owner. */
+ if (mIsClipboardOwner) {
+ refClipboard->clear();
+ refPrimary->clear();
+ mIsClipboardOwner = FALSE;
+ Debug("%s: Cleared local clipboard", __FUNCTION__);
+ }
+
+ if (CPClipboard_GetItem(clip, CPFORMAT_TEXT, &buf, &sz)) {
+ Debug("%s: Text data: %s.\n", __FUNCTION__, (char *)buf);
+ refClipboard->set_text((const char *) buf);
+ refPrimary->set_text((const char *) buf);
+ }
+ if (CPClipboard_GetItem(clip, CPFORMAT_FILELIST, &buf, &sz)) {
+ Debug("%s: File data.\n", __FUNCTION__);
+ DnDFileList flist;
+ flist.FromCPClipboard(buf, sz);
+ mHGFCPData = flist.GetRelPathsStr();
+
+ refClipboard->set(mListTargets,
+ sigc::mem_fun(this, &CopyPasteUI::LocalGetFileRequestCB),
+ sigc::mem_fun(this, &CopyPasteUI::LocalClearClipboardCB));
+ refPrimary->set(mListTargets,
+ sigc::mem_fun(this, &CopyPasteUI::LocalGetFileRequestCB),
+ sigc::mem_fun(this, &CopyPasteUI::LocalClearClipboardCB));
+
+ mIsClipboardOwner = TRUE;
+ mHGGetListTime = GetCurrentTime();
+ mHGGetFilesInitated = FALSE;
+ mHGCopiedUriList = "";
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::GetLocalFiles --
+ *
+ * Invoke the copy files from host to guest.
+ *
+ * Results:
+ * true if the request was sent. false otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+CopyPasteUI::GetLocalFiles(void)
+{
+ Debug("%s: enter try to start HG file copy.\n", __FUNCTION__);
+#if defined(NOT_YET)
+ ASSERT_IN_SAFE_CONTEXT(mSyncWnd);
+#endif
+
+ mHGStagingDir = mCP.GetFiles();
+
+#if defined(NOT_YET)
+ if (mHGStagingDir.empty()) {
+ mDataObject->NotifyGetFilesDone(false);
+ return false;
+ }
+ mDataObject->SetStagingDir(mHGStagingDir);
+#endif
+ return true;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::GetLocalFilesDone --
+ *
+ * Callback when CopyPasteUI::GetLocalFiles is done, which finishes the file
+ * copying from host to guest staging directory. This function notifies
+ * the Copy/Paste data object and end its waiting state in order to continue
+ * the file copying from local staging directory to local target directory.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::GetLocalFilesDone(bool success)
+{
+ Debug("%s: enter success %d\n", __FUNCTION__, success);
+ if (success) {
+ /*
+ * Mark current staging dir to be deleted on next reboot for FCP. The
+ * file will not be deleted after reboot if it is moved to another
+ * location by target application.
+ */
+ DnD_DeleteStagingFiles(mHGStagingDir.c_str(), TRUE);
+ } else {
+ /* Copied files are already removed in common layer. */
+ mHGStagingDir.clear();
+ }
+#if defined(NOT_YET)
+ mDataObject->NotifyGetFilesDone(success);
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::Reset --
+ *
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::Reset(void)
+{
+ Debug("%s: enter\n", __FUNCTION__);
+ /* Cancel any pending file transfer. */
+}
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file copyPasteUI.h
+ *
+ * This class implements the methods that allows Copy/Paste
+ * between host and guest using version 3+ of the protocol.
+ *
+ */
+
+#ifndef COPYPASTE_UI_H
+#define COPYPASTE_UI_H
+
+#include "stringxx/string.hh"
+
+extern "C" {
+ #include "dnd.h"
+ #include "debug.h"
+ #include "str.h"
+}
+
+#include "unicodeOperations.h"
+
+#include "copyPaste.hh"
+
+#include <gtkmm.h>
+#include <list>
+
+class CopyPasteUI : public sigc::trackable
+{
+public:
+ CopyPasteUI();
+ virtual ~CopyPasteUI();
+ void VmxCopyPasteVersionChanged(struct RpcIn *rpcIn,
+ uint32 version);
+ void SetCopyPasteAllowed(bool isCopyPasteAllowed)
+ { mCP.SetCopyPasteAllowed(isCopyPasteAllowed); }
+ void Reset(void);
+ bool GetLocalFiles(void);
+
+private:
+
+ /* hg */
+ void GetRemoteClipboardCB(const CPClipboard *clip);
+ void RemoteGetFilesDone(void);
+ void LocalGetFileRequestCB(Gtk::SelectionData& selection_data, guint info);
+ void LocalClearClipboardCB(void);
+
+ /* gh */
+ bool GetLocalClipboard(CPClipboard *clip);
+ void LocalClipboardTimestampCB(const Gtk::SelectionData& sd);
+ void LocalPrimTimestampCB(const Gtk::SelectionData& sd);
+ void LocalReceivedTargetsCB(const Glib::StringArrayHandle& targets_array);
+ void LocalReceivedFileListCB(const Gtk::SelectionData& selection_data);
+ void LocalReceivedTextCB(const Glib::ustring& text);
+ void GetLocalFilesDone(bool success);
+
+ /* Conversion methods. */
+ void LocalGetSelectionFileList(const Gtk::SelectionData& sd);
+ utf::utf8string GetNextPath(utf::utf8string &str, size_t& index);
+ utf::string GetLastDirName(const utf::string &str);
+
+ VmTimeType GetCurrentTime(void);
+
+ // Member variables
+ CopyPaste mCP;
+ bool mClipboardEmpty;
+ std::string mHGStagingDir;
+ std::list<Gtk::TargetEntry> mListTargets;
+ bool mIsClipboardOwner;
+ uint64 mClipTime;
+ uint64 mPrimTime;
+ uint64 mClipTimePrev;
+ uint64 mPrimTimePrev;
+ GdkAtom mGHSelection;
+ CPClipboard mClipboard;
+
+ /* File vars. */
+ bool mHGGetFilesInitated;
+ VmTimeType mHGGetListTime;
+ utf::string mHGCopiedUriList;
+ utf::utf8string mHGFCPData;
+};
+
+#endif // COPYPASTE_UI_H
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2007 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-/*
- * copyPaste.h --
- *
- * Handles the linux specific copy paste operations.
- *
- * TODO: Data conversion out into another class to be shared between dnd
- * and copypaste.
- */
-
-#ifndef LUI_COPYPASTE_HH
-#define LUI_COPYPASTE_HH
-
-#include "cui/dnd/copyPaste.hh"
-#include "cui/vm.hh"
-
-extern "C" {
-#include "dnd.h"
-#include "../dnd/dndClipboard.h"
-}
-
-namespace lui {
- class CopyPaste
- : public sigc::trackable
- {
- public:
- CopyPaste(cui::dnd::CopyPaste *cp);
- ~CopyPaste(void);
-
- void UpdateLocalClipboard(void);
- void UpdateRemoteClipboard(void);
-
- private:
- /* gh */
- void GetRemoteClipboardCB(const CPClipboard *clip);
- void RemoteGetFilesDone(void);
- /* clipboard stuff */
- void LocalGetFileRequestCB(Gtk::SelectionData& selection_data, guint info);
- void LocalClearClipboardCB(void);
-
- /* hg */
- /* Clipboard stuff */
- void LocalClipboardTimestampCB(const Gtk::SelectionData& sd);
- void LocalPrimTimestampCB(const Gtk::SelectionData& sd);
- void LocalReceivedTargetsCB(const Glib::StringArrayHandle& targets_array);
- void LocalReceivedFileListCB(const Gtk::SelectionData& selection_data);
- void LocalReceivedTextCB(const Glib::ustring& text);
-
- /* Convertion methods. */
- void LocalGetSelectionFileList(const Gtk::SelectionData& sd);
- utf::utf8string GetNextPath(utf::utf8string &str, size_t& index);
- utf::string GetLastDirName(const utf::string &str);
-
- cui::dnd::CopyPaste * const mCP;
-
- CPClipboard mClipboard;
- bool mIsClipboardOwner;
- uint64 mClipTime;
- uint64 mPrimTime;
- GdkAtom mHGSelection;
-
- /* File vars. */
- bool mGHGetFilesInitated;
- VmTimeType mGHGetListTime;
- utf::string mGHCopiedUriList;
- utf::utf8string mGHFCPData;
-
- std::list<Gtk::TargetEntry> mListTargets;
- };
-
-} //namespace lui
-
-#endif // LUI_COPYPASTE_HH
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file copyPasteWrapper.cpp
+ *
+ * This singleton class implements a wrapper around various versions of
+ * copy and paste protocols, and provides some convenience functions that
+ * help to make VMwareUser a bit cleaner.
+ */
+
+#include "copyPasteWrapper.h"
+extern "C" {
+#include "vmwareuserInt.h"
+#include "debug.h"
+}
+
+
+/**
+ * CopyPasteWrapper is a singleton, here is a pointer to its only instance.
+ */
+CopyPasteWrapper *CopyPasteWrapper::m_instance = 0;
+
+/**
+ *
+ * Get an instance of CopyPasteWrapper, which is an application singleton.
+ *
+ * @return a pointer to the singleton CopyPasteWrapper object, or NULL if
+ * for some reason it could not be allocated.
+ */
+
+CopyPasteWrapper *
+CopyPasteWrapper::GetInstance()
+{
+ if (!m_instance) {
+ m_instance = new CopyPasteWrapper;
+ }
+ return m_instance;
+}
+
+
+/**
+ *
+ * Constructor.
+ */
+
+CopyPasteWrapper::CopyPasteWrapper() :
+#if defined(HAVE_GTKMM)
+ m_copyPasteUI(NULL),
+#endif
+ m_isRegistered(FALSE),
+ m_userData(NULL),
+ m_version(-1)
+{
+}
+
+
+/**
+ *
+ * Destructor.
+ */
+
+CopyPasteWrapper::~CopyPasteWrapper()
+{
+ if (IsRegistered()) {
+ Unregister();
+ }
+}
+
+
+/**
+ *
+ * Attach implementation-specific data (in reality, a GtkWidget * that is
+ * needed by the legacy copy paste code. Going forward, any new protocol
+ * versions should be implemented as classes, and should not need such a
+ * crutch).
+ *
+ * @param[in] userData a GtkWidget created by VMwareUser and used by the
+ * legacy copy and paste implementation.
+ */
+
+void
+CopyPasteWrapper::SetUserData(const void *userData)
+{
+ m_userData = userData;
+}
+
+
+/**
+ *
+ * Register copy and paste capabilities with the VMX. Try newest version
+ * first, then fall back to the legacy implementation.
+ *
+ * @return TRUE on success, FALSE on failure
+ */
+
+bool
+CopyPasteWrapper::Register()
+{
+ if (IsRegistered()) {
+ return TRUE;
+ }
+
+ /*
+ * Try to get version 3, and if that fails, go for the compatibility
+ * versions (1 and 2).
+ */
+
+#if defined(HAVE_GTKMM)
+ Debug("%s: enter\n", __FUNCTION__);
+ m_copyPasteUI = new CopyPasteUI();
+ if (m_copyPasteUI) {
+ SetIsRegistered(TRUE);
+ int version = GetVersion();
+ Debug("%s: version is %d\n", __FUNCTION__, version);
+ if (version >= 3) {
+ m_copyPasteUI->VmxCopyPasteVersionChanged(gRpcIn, version);
+ m_copyPasteUI->SetCopyPasteAllowed(TRUE);
+ } else {
+ Debug("%s: version < 3, unregistering.\n", __FUNCTION__);
+ Unregister();
+ }
+ }
+#endif
+ if (!IsRegistered()) {
+ SetIsRegistered(CopyPaste_Register((GtkWidget *)m_userData));
+ if (IsRegistered()) {
+ if (!CopyPaste_RegisterCapability()) {
+ Unregister();
+ }
+ }
+ }
+ return IsRegistered();
+}
+
+/**
+ *
+ * Unregister copy paste capabilities and do general cleanup.
+ */
+
+void
+CopyPasteWrapper::Unregister()
+{
+ if (!IsRegistered()) {
+ return;
+ }
+#if defined(HAVE_GTKMM)
+ if (m_copyPasteUI) {
+ delete m_copyPasteUI;
+ m_copyPasteUI = NULL;
+ } else {
+#endif
+ CopyPaste_Unregister((GtkWidget *)m_userData);
+#if defined(HAVE_GTKMM)
+ }
+#endif
+ SetIsRegistered(FALSE);
+ m_version = -1;
+}
+
+
+/**
+ *
+ * Get the version of the copy paste protocol being wrapped.
+ *
+ * @return copy paste protocol version.
+ */
+
+int
+CopyPasteWrapper::GetVersion()
+{
+ if (IsRegistered()) {
+ m_version = CopyPaste_GetVmxCopyPasteVersion();
+ }
+ Debug("%s: got version %d\n", __FUNCTION__, m_version);
+ return m_version;
+}
+
+/**
+ *
+ * Set a flag indicating that we are wrapping an initialized and registered
+ * copy paste implementation, or not.
+ *
+ * @param[in] isRegistered If TRUE, protocol is registered, otherwise FALSE.
+ */
+
+void
+CopyPasteWrapper::SetIsRegistered(bool isRegistered)
+{
+ m_isRegistered = isRegistered;
+}
+
+/**
+ *
+ * Get the flag indication that we are wrapping an initialized and registered
+ * copy paste implementation, or not.
+ *
+ * @return TRUE if copy paste is initialized, otherwise FALSE.
+ */
+
+bool
+CopyPasteWrapper::IsRegistered()
+{
+ return m_isRegistered;
+}
+
+
+/**
+ *
+ * Handle reset by calling protocol dependent handlers.
+ */
+
+void
+CopyPasteWrapper::OnReset()
+{
+ Debug("%s: enter\n", __FUNCTION__);
+ if (IsRegistered()) {
+ Unregister();
+ }
+ Register();
+ if (!IsRegistered()) {
+ Debug("%s: unable to reset!\n", __FUNCTION__);
+ }
+}
+
+
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file copyPasteWrapper.h
+ *
+ * This singleton class implements a wrapper around various versions of
+ * copy and paste.
+ *
+ */
+
+#ifndef COPYPASTEWRAPPER_H
+#define COPYPASTEWRAPPER_H
+
+#if defined(HAVE_GTKMM)
+#include "copyPasteUI.h"
+#endif
+
+class CopyPasteWrapper
+{
+public:
+ ~CopyPasteWrapper();
+ void SetUserData(const void *userData);
+ bool Register();
+ void Unregister();
+ static CopyPasteWrapper *GetInstance();
+ int GetVersion();
+ void SetIsRegistered(bool isRegistered);
+ bool IsRegistered();
+ void OnReset();
+private:
+ /*
+ * We're a singleton, so it is a compile time error to call these.
+ */
+ CopyPasteWrapper();
+ CopyPasteWrapper(const CopyPasteWrapper &wrapper);
+ CopyPasteWrapper& operator=(const CopyPasteWrapper &wrapper);
+private:
+#if defined(HAVE_GTKMM)
+ CopyPasteUI *m_copyPasteUI;
+#endif
+ bool m_isRegistered;
+ const void *m_userData;
+ int m_version;
+ static CopyPasteWrapper *m_instance;
+};
+
+#endif // COPYPASTEWRAPPER_H
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2005 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * dnd.c --
+ *
+ * Handles the guest side of host<->guest DnD operations.
+ *
+ * Guest->Host DnD
+ * ---------------
+ *
+ * The DnD process within the guest starts when we receive a "dnd.ungrab" RPC
+ * message from the host, which invokes DnDRpcInMouseUngrabCB(). The MKS
+ * sends this RPC when it sees the mouse stray outside of the clip (guest's
+ * viewable area). RpcInMouseUngrabCB() will determine whether a DnD is
+ * pending by calling DnDDragPending():
+ * o if a DnD is not pending, it replies with a "dnd.notpending" RPC and we
+ * are done,
+ * o if a DnD is pending, we send fake X events to the X server that place
+ * our invisible window at the location of the mouse pointer and generate
+ * mouse movements over the window.
+ *
+ * Faking mouse movement over our window causes Gtk to send us a "drag_motion"
+ * signal, which invokes DnDGtkDragMotionCB(). Here we find a common target
+ * (drop type) and request the data from the drag source via
+ * gtk_drag_get_data().
+ *
+ * When the data is ready, Gtk signals us with a "data_received" signal. We
+ * parse the provided data and send the file names to the host with
+ * a "dnd.data.set" RPC. Then we start the DnD operation with a "dnd.enter"
+ * RPC. Upon receiving the "dnd.enter", the MKS will allow the ungrab of the
+ * mouse from the guest window and the user will be able to select a location
+ * to drop the files.
+ *
+ * (Note that it is important that the guest reply to the "dnd.ungrab" with
+ * either a "dnd.notpending" or a "dnd.enter" in a timely manner, since the
+ * MKS will delay mouse packets until it has received a reply from the
+ * guest.)
+ *
+ * When the user drops the files, the host will send us a "dnd.data.get.file"
+ * for each file, which invokes DnDRpcInGetNextFileCB(). On each invocation,
+ * we reply with the next file from the Guest->Host file list (obtained from
+ * DnDGHFileListGetNext()), and "|end|" when there are no more files. With
+ * this information, the host copies the files from the guest using HGFS.
+ *
+ * When the host has finished copying the files, it sends us a "dnd.finish"
+ * RPC, which invokes DnDRpcInFinishCB(). At this point, we fake X events
+ * that cause a mouse button release over our window.
+ *
+ * This button release causes Gtk to send us a "drag_drop" signal, which
+ * invokes DnDGtkDragDropCB(). Here we simply clean up our state and
+ * indicate that the drag finished successfully by calling gtk_drag_finish().
+ *
+ * If an error occurs at any point, the host sends us a "dnd.finish cancel"
+ * RPC. We will fake an ESC key press and release to cancel the pending DnD
+ * in the guest.
+ *
+ *
+ * Host->Guest DnD
+ * ---------------
+ *
+ * A host->guest DnD begins with a "dnd.data.set" from the vmx to provide the
+ * list of files being dragged into the guest, then a "dnd.enter" to begin the
+ * DnD operation. When the "dnd.enter" is received, this process will send
+ * a fake mouse button press and mouse movement on its window, starting the
+ * DnD operation within the guest. At this point the mouse still has not been
+ * grabbed by the guest and all mouse movements go only to the host.
+ *
+ * As part of the normal DnD protocol on the host, the UI in the host will
+ * receive updates on the location of the mouse within its target window.
+ * This location is translated to guest coordinates and sent to us via the
+ * "dnd.move" RPC, at which point we fake additional mouse movements to that
+ * location. When the user releases the mouse, the host UI is again notified
+ * and sends us a "dnd.drop" RPC.
+ *
+ * When the drop occurs, we add a block (via vmblock) on the directory
+ * containing the files to be given to the target application, then fake
+ * a mouse release at the location of the drop. This will cause the target
+ * application to request the data, which we provide through our
+ * "drag_data_get" handler (DnDGtkDataRequestCB()). When the application
+ * attempts to access these files it will be blocked by vmblock.
+ *
+ * After the drop is sent, the host will send the files to the hgfs server
+ * running inside this process, and will notify us when that transfer is
+ * complete via the "dnd.data.finish" RPC. If the transfer is successful, we
+ * remove the block to allow the target application to access the files. If
+ * the transfer is unsuccessful, we remove any partially copied files then
+ * remove the block; this has the effect of failing the DnD operation since
+ * the target cannot access the necessary files. Once this is done, we
+ * generate a new file root within the staging directory and send that to the
+ * host for the next DnD operation.
+ *
+ * Note that we used to fake the mouse release only after the data transfer
+ * completed (and Windows guests still behave that way), but this was changed
+ * since the Linux UI was modified to allow guest interaction while the
+ * progress dialog (for the file transfer) was displayed and updating. This
+ * caused a lot of instability since the mouse was no longer in a predictable
+ * state when the fake release was sent. vmblock let us work around this by
+ * changing where the block occurred.
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <X11/extensions/XTest.h> /* for XTest*() */
+#include <X11/keysym.h> /* for XK_Escape */
+#include <X11/Xatom.h> /* for XA_WINDOW */
+
+#include "vmwareuserInt.h"
+#include "vm_app.h"
+#include "vm_assert.h"
+#include "vm_basic_defs.h"
+#include "eventManager.h"
+#include "debug.h"
+#include "strutil.h"
+#include "str.h"
+#include "file.h"
+#include "guestApp.h"
+#include "cpName.h"
+#include "cpNameUtil.h"
+#include "dnd.h"
+#include "util.h"
+#include "hgfsVirtualDir.h"
+#include "hgfsServerPolicy.h"
+#include "vmblock.h"
+#include "escape.h"
+
+
+#define DND_MAX_PATH 6144
+#define DRAG_TARGET_NAME_URI_LIST "text/uri-list"
+#define DRAG_TARGET_INFO_URI_LIST 0
+#define DRAG_TARGET_NAME_TEXT_PLAIN "text/plain"
+#define DRAG_TARGET_INFO_TEXT_PLAIN 1
+#define DRAG_TARGET_NAME_STRING "STRING"
+#define DRAG_TARGET_INFO_STRING 2
+/*
+ * We support all three drag targets from Host->Guest since we can present
+ * filenames in any of these forms if an application requests. However, we
+ * only support file drag targets (text/uri-list) from Guest->Host since we
+ * can only DnD files across the backdoor.
+ */
+#define NR_DRAG_TARGETS 3
+#define NR_GH_DRAG_TARGETS 1
+
+#define DROPEFFECT_NONE 0
+#define DROPEFFECT_COPY 1
+#define DROPEFFECT_MOVE 2
+#define DROPEFFECT_LINK 4
+
+/*
+ * More friendly names for calling DnDFakeXEvents(). This is really ugly but
+ * it allows us to keep all of the X fake event code in one place.
+ *
+ * Operation | showWidget | buttonEvent | buttonPress | moveWindow | coordsProvided
+ * ----------+------------+-------------+-------------+------------+---------------
+ * G->H Drag | Yes | No | n/a | Yes | No
+ * G->H Drop | No | Yes | Release | Yes | No
+ * H->G Drag | Yes | Yes | Press | Yes | No
+ * H->G Move | No | No | n/a | No | Yes
+ * H->G Drop | No | Yes | Release | No | Yes
+ * ----------+------------+-------------+-------------+------------+---------------
+ */
+#define DnDGHFakeDrag(widget) \
+ DnDFakeXEvents(widget, TRUE, FALSE, FALSE, TRUE, FALSE, 0, 0)
+#define DnDGHFakeDrop(widget) \
+ DnDFakeXEvents(widget, FALSE, TRUE, FALSE, TRUE, FALSE, 0, 0)
+#define DnDHGFakeDrag(widget) \
+ DnDFakeXEvents(widget, TRUE, TRUE, TRUE, TRUE, FALSE, 0, 0)
+#define DnDHGFakeMove(widget, x, y) \
+ DnDFakeXEvents(widget, FALSE, FALSE, FALSE, FALSE, TRUE, x, y)
+#define DnDHGFakeDrop(widget, x, y) \
+ DnDFakeXEvents(widget, FALSE, TRUE, FALSE, FALSE, TRUE, x, y)
+
+#ifdef GTK2
+# define GDKATOM_TO_ATOM(gdkAtom) gdk_x11_atom_to_xatom(gdkAtom)
+#else
+# define GDKATOM_TO_ATOM(gdkAtom) gdkAtom
+#endif
+
+/*
+ * Forward Declarations
+ */
+static Bool DnDRpcInEnterCB (char const **result, size_t *resultLen,
+ const char *name, const char *args,
+ size_t argsSize,void *clientData);
+static Bool DnDRpcInDataSetCB (char const **result, size_t *resultLen,
+ const char *name, const char *args,
+ size_t argsSize,void *clientData);
+static Bool DnDRpcInMoveCB (char const **result, size_t *resultLen,
+ const char *name, const char *args,
+ size_t argsSize,void *clientData);
+static Bool DnDRpcInDataFinishCB (char const **result, size_t *resultLen,
+ const char *name, const char *args,
+ size_t argsSize,void *clientData);
+static Bool DnDRpcInDropCB (char const **result, size_t *resultLen,
+ const char *name, const char *args,
+ size_t argsSize,void *clientData);
+static Bool DnDRpcInMouseUngrabCB(char const **result, size_t *resultLen,
+ const char *name, const char *args,
+ size_t argsSize,void *clientData);
+static Bool DnDRpcInGetNextFileCB(char const **result, size_t *resultLen,
+ const char *name, const char *args,
+ size_t argsSize,void *clientData);
+static Bool DnDRpcInFinishCB (char const **result, size_t *resultLen,
+ const char *name, const char *args,
+ size_t argsSize,void *clientData);
+
+/*
+ * Gtk DnD specific event/signal callbacks.
+ */
+/* For Host->Guest DnD */
+static void DnDGtkBeginCB(GtkWidget *widget, GdkDragContext *dc, gpointer data);
+static void DnDGtkEndCB(GtkWidget *widget, GdkDragContext *dc, gpointer data);
+static void DnDGtkDataRequestCB(GtkWidget *widget, GdkDragContext *dc,
+ GtkSelectionData *selection_data,
+ guint info, guint time, gpointer data);
+
+/* For Guest->Host DnD */
+static gboolean DnDGtkDragMotionCB(GtkWidget *widget, GdkDragContext *dc, gint x,
+ gint y, guint time, gpointer data);
+static void DnDGtkDragDataReceivedCB(GtkWidget *widget, GdkDragContext *dc,
+ gint x, gint y, GtkSelectionData *dragData,
+ guint info, guint time, gpointer data);
+static gboolean DnDGtkDragDropCB(GtkWidget *widget, GdkDragContext *dc,
+ gint x, gint y, guint time, gpointer data);
+
+/*
+ * Utility
+ */
+static Bool DnDSendVmxNewFileRoot(char *rpcCmd);
+static Bool DnDFakeXEvents(GtkWidget *widget, Bool showWidget,
+ Bool buttonEvent, Bool buttonPress,
+ Bool moveWindow,
+ Bool coordsProvided, int x, int y);
+static void DnDSendEscapeKey(GtkWidget *mainWnd);
+static INLINE Bool DnDGHDragPending(GtkWidget *widget);
+static INLINE Bool DnDGHXdndDragPending(GtkWidget *widget);
+static INLINE void DnDGHXdndClearPending(GtkWidget *widget);
+static INLINE Bool DnDGHMotifDragPending(GtkWidget *widget);
+static INLINE void DnDGHFileListClear(void);
+static INLINE void DnDGHFileListSet(char *fileList, size_t fileListSize);
+static INLINE Bool DnDGHFileListGetNext(char **fileName, size_t *fileNameSize);
+static INLINE void DnDGHStateInit(GtkWidget *widget);
+static INLINE void DnDHGStateInit(void);
+static INLINE Bool DnDGHCancel(GtkWidget *widget);
+static Bool DnDGHXEventTimeout(void *clientData);
+
+/*
+ * Globals
+ */
+struct ghState {
+ Bool dragInProgress;
+ Bool ungrabReceived;
+ char *dndFileList;
+ char *dndFileListNext;
+ size_t dndFileListSize;
+ GdkDragContext *dragContext;
+ guint time;
+ Event *event;
+} gGHState;
+static Bool gHGDnDInProgress;
+static Bool gDoneDragging;
+static Bool gHGDataPending;
+static char gDnDData[1024];
+static GdkDragContext *gDragCtx;
+static GtkTargetEntry gTargetEntry[NR_DRAG_TARGETS];
+static GdkAtom gTargetEntryAtom[NR_GH_DRAG_TARGETS];
+static char gFileRoot[DND_MAX_PATH];
+static size_t gFileRootSize;
+static size_t gDnDDataSize;
+static Bool gUnity;
+
+/*
+ * From vmwareuserInt.h
+ */
+RpcIn *gRpcIn;
+Display *gXDisplay;
+Window gXRoot;
+
+
+/*
+ * Host->Guest RPC callback implementations
+ */
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDRpcInEnterCB --
+ *
+ * For Host->Guest operations only.
+ * User has dragged something over this guest's MKS window
+ *
+ * Results:
+ * TRUE on success, FALSE otherwise
+ *
+ * Side effects:
+ * Some GdkEvents are generated which will "drag" the mouse. A directory
+ * is created.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDRpcInEnterCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // IN
+{
+ char *numFormats;
+ char *pFormat;
+ unsigned int index = 0;
+ int nFormats;
+ int i;
+ GtkWidget *mainWnd;
+
+ Debug("Got DnDRpcInEnterCB\n");
+ mainWnd = GTK_WIDGET(clientData);
+ if (mainWnd == NULL) {
+ return RpcIn_SetRetVals(result, resultLen,
+ "bad clientData passed to callback", FALSE);
+ }
+
+ if (gBlockFd < 0) {
+ Debug("DnDRpcInEnterCB: cannot allow H->G DnD without vmblock.\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "blocking file system unavailable", FALSE);
+ }
+
+ numFormats = StrUtil_GetNextToken(&index, args, " ");
+ if (!numFormats) {
+ Debug("DnDRpcInEnterCB: Failed to parse numformats\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "must specify number of formats", FALSE);
+ }
+
+ /* Skip whitespace character. */
+ index++;
+
+ nFormats = atoi(numFormats);
+ free(numFormats);
+
+ for (i = 0; i < nFormats; i++) {
+ pFormat = StrUtil_GetNextToken(&index, args, ",");
+
+ if (!pFormat) {
+ Debug("DnDRpcInEnterCB: Failed to parse format list\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "Failed to read format list", FALSE);
+ } else {
+ /*
+ * TODO: check that formats are ok for us to handle. For now, this is
+ * ok since there should only be a CF_HDROP. But, we really should figure
+ * out a much more cross-platform format scheme
+ */
+ free(pFormat);
+ }
+ }
+
+ if (!DnDHGFakeDrag(mainWnd)) {
+ Debug("DnDRpcInEnterCB: Failed to fake X events\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "failed to fake drag", FALSE);
+ }
+
+ RpcIn_SetRetVals(result, resultLen, "", TRUE);
+ RpcOut_sendOne(NULL, NULL, "dnd.feedback copy");
+ Debug("DnDRpcInEnterCB finished\n");
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDRpcInDataSetCB --
+ *
+ * For Host->Guest operations only.
+ * Host is sending data from a DnD operation.
+ *
+ * Results:
+ * TRUE on success, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDRpcInDataSetCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // IN: Size of args
+ void *clientData) // Ignored
+{
+ char blockDir[DND_MAX_PATH];
+ char *perDnDDir = NULL;
+ char *format;
+ char *data;
+ unsigned int index = 0;
+ size_t dataSize;
+ char *retStr;
+ Bool ret = FALSE;
+
+ Debug("DnDRpcInDataSetCB: enter\n");
+
+ if (gBlockFd < 0) {
+ Debug("DnDRpcInDataSetCB: blocking file system not available.\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "blocking file system not available", FALSE);
+ }
+
+ /* Parse the data type & value string. */
+ format = StrUtil_GetNextToken(&index, args, " ");
+ if (!format) {
+ Debug("DnDRpcInDataSetCB: Failed to parse format\n");
+ return RpcIn_SetRetVals(result, resultLen, "need format", FALSE);
+ }
+
+ index++; /* Ignore leading space before data. */
+ dataSize = argsSize - index;
+ data = Util_SafeMalloc(dataSize);
+ memcpy(data, args + index, dataSize);
+
+ Debug("DnDRpcInDataSetCB: Received data from host: (%s) [%s] (%"FMTSZ"u)\n",
+ format, CPName_Print(data, dataSize), dataSize);
+
+ /*
+ * Here we take the last component of the actual file root, which is
+ * a temporary directory for this DnD operation, and append it to the mount
+ * point for vmblock. This is where we want the target application to
+ * access the file since it will enable vmblock to block that application's
+ * progress if necessary.
+ */
+ perDnDDir = DnD_GetLastDirName(gFileRoot);
+ if (!perDnDDir) {
+ Debug("DnDRpcInDataSetCB: cannot obtain dirname of root.\n");
+ retStr = "error obtaining dirname of root";
+ goto out;
+ }
+
+ if (sizeof VMBLOCK_MOUNT_POINT - 1 +
+ (sizeof DIRSEPS - 1) * 2 + strlen(perDnDDir) >= sizeof blockDir) {
+ Debug("DnDRpcInDataSetCB: blocking directory path too large.\n");
+ retStr = "blocking directory path too large";
+ goto out;
+ }
+
+ Str_Sprintf(blockDir, sizeof blockDir,
+ VMBLOCK_MOUNT_POINT DIRSEPS "%s" DIRSEPS, perDnDDir);
+
+ /* Add the file root to the relative paths received from host */
+ if (!DnD_PrependFileRoot(blockDir, &data, &dataSize)) {
+ Debug("DnDRpcInDataSsetCB: error prepending guest file root\n");
+ retStr = "error prepending file root";
+ goto out;
+ }
+ if (dataSize + 1 > sizeof gDnDData) {
+ Debug("DnDRpcInDataSetCB: data too large\n");
+ retStr = "data too large";
+ goto out;
+ }
+
+ memcpy(gDnDData, data, dataSize + 1);
+ gDnDDataSize = dataSize;
+ Debug("DnDRpcInDataSetCB: prepended file root [%s] (%"FMTSZ"u)\n",
+ CPName_Print(gDnDData, gDnDDataSize), gDnDDataSize);
+
+ retStr = "";
+ ret = TRUE;
+
+out:
+ free(format);
+ free(data);
+ free(perDnDDir);
+ return RpcIn_SetRetVals(result, resultLen, retStr, ret);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDRpcInMoveCB --
+ *
+ * For Host->Guest operations only.
+ * Host user is dragging data over this guest's MKS window
+ *
+ * Results:
+ * TRUE on success, FALSE otherwise.
+ *
+ * Side effects:
+ * Send a gdk event that "moves" the mouse.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDRpcInMoveCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // IN: pointer to mainWnd
+{
+ GtkWidget *mainWnd;
+ char *sXCoord;
+ char *sYCoord;
+ unsigned int index = 0;
+ int xCoord, yCoord;
+
+ mainWnd = GTK_WIDGET(clientData);
+ if (mainWnd == NULL) {
+ return RpcIn_SetRetVals(result, resultLen,
+ "bad clientData passed to callback", FALSE);
+ }
+
+ sXCoord = StrUtil_GetNextToken(&index, args, " ");
+ sYCoord = StrUtil_GetNextToken(&index, args, " ");
+
+ if (!sXCoord || !sYCoord) {
+ Debug("DnDRpcInMove: Failed to parse coords\n");
+ free(sXCoord);
+ free(sYCoord);
+ return RpcIn_SetRetVals(result, resultLen,
+ "error reading mouse move data", FALSE);
+ }
+
+ xCoord = atoi(sXCoord);
+ yCoord = atoi(sYCoord);
+
+ free(sXCoord);
+ free(sYCoord);
+
+ /* Fake a mouse move */
+ if (!DnDHGFakeMove(mainWnd, xCoord, yCoord)) {
+ Debug("DnDRpcInMove: Failed to fake mouse movement\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "failed to move mouse", FALSE);
+ }
+
+ return RpcIn_SetRetVals(result, resultLen, "", TRUE);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDRpcInDataFinishCB --
+ *
+ * For Host->Guest operations only.
+ * Host has finished transferring DnD data to the guest. We do any post
+ * H->G operation cleanup here, like removing the block on the staging
+ * directory, picking a new file root, and informing the host of the new
+ * root.
+ *
+ * Results:
+ * TRUE on success, FALSE otherwise
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDRpcInDataFinishCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // Ignored
+{
+ unsigned int index = 0;
+ char *state;
+
+ Debug("DnDRpcInDataFinishCB: enter\n");
+
+ state = StrUtil_GetNextToken(&index, args, " ");
+ if (!state) {
+ Debug("DnDRpcInDataFinishCB: could not get dnd finish state.\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "could not get dnd finish state", FALSE);
+ }
+
+ /*
+ * If the guest doesn't support vmblock, we'll have bailed out of
+ * DndRpcInDropCB before setting gHGDataPending. Thus, it doesn't make sense
+ * to pop a warning here, but let's keep the message around just in case
+ * there can be a failure worth hearing about.
+ */
+ if (!gHGDataPending) {
+ Debug("DnDRpcInDataFinishCB: expected gHGDataPending to be set.\n");
+ }
+
+ gHGDataPending = FALSE;
+
+ /*
+ * The host will send us "success" or "error", depending on whether the
+ * transfer finished successfully. In either case we remove the pending
+ * block, but in the "error" case we also need to delete all the files so
+ * the destination application doesn't access the partially copied files and
+ * mistake them for a successful drop.
+ */
+ if (strcmp(state, "success") != 0) {
+ /* On any non-success input, delete the files. */
+ DnD_DeleteStagingFiles(gFileRoot, FALSE);
+ }
+
+ free(state);
+
+ if (gBlockFd >= 0 && !DnD_RemoveBlock(gBlockFd, gFileRoot)) {
+ Warning("DnDRpcInDataFinishCB: could not remove block on %s\n",
+ gFileRoot);
+ }
+
+ /* Pick a new file root and send that to the host for the next DnD. */
+ if (!DnDSendVmxNewFileRoot("dnd.setGuestFileRoot")) {
+ Debug("DnDRpcInDataFinishCB: Failed to send dnd.setGuestFileRoot "
+ "message to host\n");
+ return RpcIn_SetRetVals(result, resultLen, "could not send guest root", FALSE);
+ }
+
+ return RpcIn_SetRetVals(result, resultLen, "", TRUE);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDRpcInDropCB --
+ *
+ * For Host->Guest operations only.
+ * Host user has dropped data over this guest's MKS window. We add
+ * a block on the staging directory then send a fake mouse release to
+ * invoke the drop completion (from Gtk's point of view).
+ *
+ * Results:
+ * TRUE on success, FALSE otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDRpcInDropCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // IN: Gtk window widget
+{
+ GtkWidget *mainWnd;
+ char *sXCoord;
+ char *sYCoord;
+ unsigned int index = 0;
+ int xCoord, yCoord;
+
+ Debug("DnDRpcInDropCB: enter\n");
+
+ gDoneDragging = TRUE;
+
+ mainWnd = GTK_WIDGET(clientData);
+ if (mainWnd == NULL) {
+ return RpcIn_SetRetVals(result, resultLen,
+ "bad clientData passed to callback", FALSE);
+ }
+
+ sXCoord = StrUtil_GetNextToken(&index, args, " ");
+ sYCoord = StrUtil_GetNextToken(&index, args, " ");
+
+ if (!sXCoord || !sYCoord) {
+ Debug("DnDRpcInDropCB: Failed to parse coords\n");
+ free(sXCoord);
+ free(sYCoord);
+ return RpcIn_SetRetVals(result, resultLen,
+ "must specify drop coordinates", FALSE);
+ }
+
+ xCoord = atoi(sXCoord);
+ yCoord = atoi(sYCoord);
+
+ free(sXCoord);
+ free(sYCoord);
+
+ Debug("DnDRpcInDropCB: Received drop notification at (%d,%d)\n",
+ xCoord, yCoord);
+
+ /*
+ * Add a block on the guest file root, warp the pointer, then fake the mouse
+ * release. Make sure we'll succeed before modifying any mouse state in the
+ * guest.
+ */
+ if (gBlockFd < 0) {
+ /*
+ * We shouldn't get here since DnDRpcInEnterCB() checks this, but we'll
+ * check rather than ASSERT just in case.
+ */
+ return RpcIn_SetRetVals(result, resultLen,
+ "blocking file system unavailable", FALSE);
+ }
+
+ if (!DnD_AddBlock(gBlockFd, gFileRoot)) {
+ return RpcIn_SetRetVals(result, resultLen, "could not add block", FALSE);
+ }
+
+ /* Update state before causing faking any mouse or keyboard changes. */
+ gHGDataPending = TRUE;
+
+
+ if (!DnDHGFakeDrop(mainWnd, xCoord, yCoord)) {
+ Debug("DnDRpcInDropCB: failed to fake drop\n");
+ return RpcIn_SetRetVals(result, resultLen, "failed to fake drop", FALSE);
+ }
+
+ return RpcIn_SetRetVals(result, resultLen, "", TRUE);
+}
+
+
+/*
+ * Guest->Host RPC callback implementations
+ */
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDRpcInMouseUngrabCB --
+ *
+ * For Guest->Host operations only.
+ *
+ * Called when a mouse ungrab is attempted with the mouse button down. When
+ * the MKS sees mouse movements outside of the clip (the viewable portion of
+ * the guest's display) while a mouse button is down, this function is
+ * called so we can inform the MKS whether to allow the ungrab (and start
+ * a DnD if one is pending).
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * The GDK window is moved and resized, and the mouse is moved over it.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDRpcInMouseUngrabCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // IN
+{
+ unsigned int index = 0;
+ GtkWidget *mainWnd;
+ int32 xPos;
+ int32 yPos;
+
+ Debug("Got DnDRpcInMouseUngrabCB\n");
+ mainWnd = GTK_WIDGET(clientData);
+ if (mainWnd == NULL) {
+ Warning("DnDRpcInMouseUngrabCB: invalid clientData\n");
+ return RpcIn_SetRetVals(result, resultLen,
+ "bad clientData passed to callback", FALSE);
+ }
+
+ /*
+ * If there is already a DnD or copy/paste in progress (including the file
+ * transfer), don't allow another.
+ */
+ if (gHGDataPending || gGHState.dragInProgress || CopyPaste_InProgress()) {
+ RpcOut_sendOne(NULL, NULL, "dnd.notpending");
+ return RpcIn_SetRetVals(result, resultLen,
+ "dnd already in progress", FALSE);
+ }
+
+ if (!StrUtil_GetNextIntToken(&xPos, &index, args, " ")) {
+ Warning("DnDRpcInMouseUngrabCB: could not parse x coordinate\n");
+ RpcOut_sendOne(NULL, NULL, "dnd.notpending");
+ return RpcIn_SetRetVals(result, resultLen,
+ "Failed to parse x coordinate", FALSE);
+ }
+
+ if (!StrUtil_GetNextIntToken(&yPos, &index, args, " ")) {
+ Warning("DnDRpcInMouseUngrabCB: could not parse y coordinate\n");
+ RpcOut_sendOne(NULL, NULL, "dnd.notpending");
+ return RpcIn_SetRetVals(result, resultLen,
+ "Failed to parse y coordinate", FALSE);
+ }
+
+ Debug("DnDRpcInMouseUngrabCB: Received (%d,%d)\n", xPos, yPos);
+
+ /*
+ * If there is no DnD pending, inform the host so the MKS can start sending
+ * mouse packets again.
+ */
+ if (!DnDGHDragPending(mainWnd)) {
+ RpcOut_sendOne(NULL, NULL, "dnd.notpending");
+ return RpcIn_SetRetVals(result, resultLen, "DnD not pending", TRUE);
+ }
+
+ /* The host only gives us coordinates within our screen */
+ ASSERT(xPos >= 0);
+ ASSERT(yPos >= 0);
+
+ /*
+ * Fake mouse movements over the window to try and generate a "drag_motion"
+ * signal from GTK. If a drag is pending, that signal will be sent to our
+ * widget and DnDGtkDragMotionCB will be invoked to start the DnD
+ * operation.
+ */
+ if (!DnDGHFakeDrag(mainWnd)) {
+ Warning("DnDRpcInMouseUngrabCB: could not fake X events\n");
+ RpcOut_sendOne(NULL, NULL, "dnd.notpending");
+ return RpcIn_SetRetVals(result, resultLen,
+ "error faking X events", FALSE);
+ }
+
+ /*
+ * Add event to fire and hide our widget if a DnD is not pending. Note that
+ * this is here in case our drag pending heuristic for Xdnd and Motif does
+ * not encompass all cases, or if the X events we generate don't cause the
+ * "drag_motion" for some other reason.
+ */
+ gGHState.event = EventManager_Add(gEventQueue, RPCIN_POLL_TIME * 100,
+ DnDGHXEventTimeout, mainWnd);
+ if (!gGHState.event) {
+ Warning("DnDRpcInMouseUngrabCB: could not create event\n");
+ RpcOut_sendOne(NULL, NULL, "dnd.notpending");
+ return RpcIn_SetRetVals(result, resultLen,
+ "could not create timeout event", FALSE);
+ }
+
+ gGHState.dragInProgress = FALSE;
+ gGHState.ungrabReceived = TRUE;
+
+ Debug("DnDRpcInMouseUngrabCB finished\n");
+ return RpcIn_SetRetVals(result, resultLen, "", TRUE);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDRpcInGetNextFileCB --
+ *
+ * For Guest->Host operations only.
+ *
+ * Invoked when the host is compiling its list of files to copy from the
+ * guest. Here we provide the path of the next file in our Guest->Host file
+ * list in guest path format (for display purposes) and CPName format (for
+ * file copy operation).
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * Iterator pointer within file list of GH state is iterated to next list
+ * entry (through call to DnDGHFileListGetNext()).
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDRpcInGetNextFileCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // IN
+{
+ static char resultBuffer[DND_MAX_PATH];
+ char *fileName;
+ size_t fileNameSize;
+ uint32 cpNameSize;
+ GtkWidget *mainWnd;
+ Bool res;
+
+ mainWnd = GTK_WIDGET(clientData);
+ if (mainWnd == NULL) {
+ DnDGHCancel(NULL);
+ return RpcIn_SetRetVals(result, resultLen,
+ "bad clientData passed to callback", FALSE);
+ }
+
+ /*
+ * Retrieve a pointer to the next filename and its size from the list stored
+ * in the G->H DnD state. Note that fileName should not be free(3)d here
+ * since an additional copy is not allocated.
+ */
+ res = DnDGHFileListGetNext(&fileName, &fileNameSize);
+
+ if (!res) {
+ Warning("DnDRpcInGetNextFileCB: error retrieving file name\n");
+ DnDGHCancel(mainWnd);
+ return RpcIn_SetRetVals(result, resultLen, "error getting file", FALSE);
+ }
+
+ if (!fileName) {
+ /* There are no more files to send */
+ Debug("DnDRpcInGetNextFileCB: reached end of Guest->Host file list\n");
+ return RpcIn_SetRetVals(result, resultLen, "|end|", TRUE);
+ }
+
+ if (fileNameSize + 1 + fileNameSize > sizeof resultBuffer) {
+ Warning("DnDRpcInGetNextFileCB: filename too large (%"FMTSZ"u)\n", fileNameSize);
+ DnDGHCancel(mainWnd);
+ return RpcIn_SetRetVals(result, resultLen, "filename too large", FALSE);
+ }
+
+ /*
+ * Construct a reply message of the form:
+ * <file name in guest format><NUL><filename in CPName format>
+ */
+ memcpy(resultBuffer, fileName, fileNameSize);
+ resultBuffer[fileNameSize] = '\0';
+
+ cpNameSize = CPNameUtil_ConvertToRoot(fileName,
+ sizeof resultBuffer - (fileNameSize + 1),
+ resultBuffer + fileNameSize + 1);
+ if (cpNameSize < 0) {
+ Warning("DnDRpcInGetNextFileCB: could not convert to CPName\n");
+ DnDGHCancel(mainWnd);
+ return RpcIn_SetRetVals(result, resultLen,
+ "error on CPName conversion", FALSE);
+ }
+
+ /* Set manually because RpcIn_SetRetVals() assumes no NUL characters */
+ *result = resultBuffer;
+ *resultLen = fileNameSize + 1 + cpNameSize;
+
+ Debug("DnDRpcInGetNextFileCB: [%s] (%"FMTSZ"u)\n",
+ CPName_Print(*result, *resultLen), *resultLen);
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDRpcInFinishCB --
+ *
+ * For Guest->Host operations only.
+ *
+ * Invoked when host side of DnD operation has finished.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDRpcInFinishCB(char const **result, // OUT
+ size_t *resultLen, // OUT
+ const char *name, // IN
+ const char *args, // IN
+ size_t argsSize, // Ignored
+ void *clientData) // IN
+{
+ GtkWidget *mainWnd;
+ char *effect = NULL;
+ unsigned int index = 0;
+ char *retStr;
+ Bool ret = FALSE;
+
+ mainWnd = GTK_WIDGET(clientData);
+ if (mainWnd == NULL) {
+ retStr = "bad clientData passed to callback";
+ goto exit;
+ }
+
+ effect = StrUtil_GetNextToken(&index, args, " ");
+ if (!effect) {
+ Warning("DnDRpcInFinishCB: no drop effect provided\n");
+ retStr = "drop effect not provided";
+ goto exit;
+ }
+
+ if (strcmp(effect, "cancel") == 0) {
+ DnDSendEscapeKey(mainWnd);
+ DnDGHCancel(mainWnd);
+ } else {
+ /*
+ * The drop happened on the host. Fake X events such that our window is
+ * placed at the mouse's coordinates and raised, then fake a button
+ * release on the window. This causes us to get a "drag_drop" signal
+ * from GTK on our widget.
+ */
+ if (!DnDGHFakeDrop(mainWnd)) {
+ Warning("DnDRpcInFinishCB: could not fake X events\n");
+ retStr = "error faking X events";
+ goto exit;
+ }
+
+ gGHState.event = EventManager_Add(gEventQueue, RPCIN_POLL_TIME * 10,
+ DnDGHXEventTimeout, mainWnd);
+ if (!gGHState.event) {
+ Warning("DnDRpcInFinishCB: could not create event\n");
+ retStr = "could not create timeout event";
+ goto exit;
+ }
+ }
+
+ retStr = "";
+ ret = TRUE;
+
+exit:
+ if (!ret) {
+ DnDGHCancel(mainWnd);
+ }
+
+ free(effect);
+ gGHState.dragInProgress = FALSE;
+ return RpcIn_SetRetVals(result, resultLen, retStr, ret);
+}
+
+
+/*
+ * Host->Guest (drop source) Gtk callback implementations
+ */
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDGtkBeginCB --
+ *
+ * "drag_begin" signal handler for GTK. This signal will be received
+ * after the fake mouse press sent in DnDRpcInEnterCB() is performed.
+ * Here we simply initialize our state variables.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+DnDGtkBeginCB(GtkWidget *widget, // IN: the widget under the drag
+ GdkDragContext *dc, // IN: the drag context maintained by gdk
+ gpointer data) // IN: unused
+{
+ GtkWidget *mainWnd = GTK_WIDGET(data);
+
+ Debug("DnDGtkBeginCB: entry\n");
+
+ if ((widget == NULL) || (mainWnd == NULL) || (dc == NULL)) {
+ return;
+ }
+
+ gHGDnDInProgress = TRUE;
+ gDoneDragging = FALSE;
+ gHGDataPending = FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDGtkEndCB --
+ *
+ * "drag_end" signal handler for GTK. This is called when a drag and drop has
+ * completed. So this function is the last one to be called in any given DnD
+ * operation.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+DnDGtkEndCB(GtkWidget *widget, // IN: the widget under the drag
+ GdkDragContext *dc, // IN: the drag context maintained by gdk
+ gpointer data) // IN: unused
+{
+
+ GtkWidget *mainWnd = GTK_WIDGET(data);
+
+ Debug("DnDGtkEndCB: enter\n");
+
+ if (mainWnd == NULL || dc == NULL) {
+ return;
+ }
+
+ /*
+ * Do not set gHGDataPending to FALSE since DnD operation completes before
+ * the data transfer.
+ */
+ gDoneDragging = FALSE;
+ gHGDnDInProgress = FALSE;
+
+ RpcOut_sendOne(NULL, NULL, "dnd.finish %d", DROPEFFECT_COPY);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnDGtkDataRequestCB --
+ * DnD "drag_data_get" handler, for handling requests for DnD data on the
+ * specified widget. This function is called when there is need for DnD data
+ * on thesource, so this function is responsible for setting up the dynamic
+ * data exchange buffer and sending it out.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Data is avaiable to drop target.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+DnDGtkDataRequestCB(GtkWidget *widget, // IN
+ GdkDragContext *dc, // IN
+ GtkSelectionData *selection_data, // IN/OUT: buffer for the data
+ guint info, // IN: the requested fo the data
+ guint time, // IN: unused
+ gpointer data) // IN: unused
+{
+ const char *begin;
+ const char *end;
+ const char *next;
+ const char *pre;
+ const char *post;
+ size_t preLen;
+ size_t postLen;
+ size_t len;
+ Bool insertSpace;
+ char *text = NULL;
+ size_t textLen = 1;
+
+ Debug("DnDGtkDataRequestCB: enter\n");
+
+ if ((widget == NULL) || (dc == NULL) || (selection_data == NULL)) {
+ Debug("DnDGtkDataRequestCB: Error, widget or dc or selection_data is invalid\n");
+ return;
+ }
+
+ /* Do nothing if we have not finished dragging yet */
+ if (!gDoneDragging) {
+ Debug("DnDGtkDataRequestCB: not done dragging yet\n");
+ return;
+ }
+
+ /* Setup the format string components */
+ switch (info) {
+ case DRAG_TARGET_INFO_URI_LIST: /* text/uri-list */
+ pre = DND_URI_LIST_PRE;
+ preLen = sizeof DND_URI_LIST_PRE - 1;
+ post = DND_URI_LIST_POST;
+ postLen = sizeof DND_URI_LIST_POST - 1;
+ insertSpace = FALSE;
+ break;
+ case DRAG_TARGET_INFO_TEXT_PLAIN: /* text/plain */
+ pre = DND_TEXT_PLAIN_PRE;
+ preLen = sizeof DND_TEXT_PLAIN_PRE - 1;
+ post = DND_TEXT_PLAIN_POST;
+ postLen = sizeof DND_TEXT_PLAIN_POST - 1;
+ insertSpace = TRUE;
+ break;
+ case DRAG_TARGET_INFO_STRING: /* STRING */
+ pre = DND_STRING_PRE;
+ preLen = sizeof DND_STRING_PRE - 1;
+ post = DND_STRING_POST;
+ postLen = sizeof DND_STRING_POST - 1;
+ insertSpace = TRUE;
+ break;
+ default:
+ Log("DnDGtkDataRequestCB: invalid drag target info\n");
+ return;
+ }
+
+
+ /*
+ * Set begin to first non-NUL character and end to last NUL character to
+ * prevent errors in calling CPName_GetComponent().
+ */
+ for(begin = gDnDData; *begin == '\0'; begin++)
+ ;
+ end = CPNameUtil_Strrchr(gDnDData, gDnDDataSize + 1, '\0');
+ ASSERT(end);
+
+ /* Build up selection data */
+ while ((len = CPName_GetComponent(begin, end, &next)) != 0) {
+ const size_t origTextLen = textLen;
+ Bool freeBegin = FALSE;
+
+ if (len < 0) {
+ Log("DnDGtkDataRequestCB: error getting next component\n");
+ if (text) {
+ free(text);
+ }
+ return;
+ }
+
+ /*
+ * A URI list will expect the provided path to be escaped. If we cannot
+ * escape the path for some reason we just use the unescaped version and
+ * hope that it works.
+ */
+ if (info == DRAG_TARGET_INFO_URI_LIST) {
+ size_t newLen;
+ char *escapedComponent;
+ int escIndex;
+ int bytesToEsc[256] = { 0, };
+
+ /* We escape the following characters based on RFC 1630. */
+ bytesToEsc['#'] = 1;
+ bytesToEsc['?'] = 1;
+ bytesToEsc['*'] = 1;
+ bytesToEsc['!'] = 1;
+ bytesToEsc['%'] = 1; /* Escape character */
+
+ /* Escape non-ASCII characters so we can pass UTF-8 filenames */
+ for (escIndex = 0x80; escIndex < 0x100; escIndex++) {
+ bytesToEsc[escIndex] = 1;
+ }
+
+ escapedComponent = Escape_Do('%', bytesToEsc, begin, len, &newLen);
+ if (escapedComponent) {
+ begin = escapedComponent;
+ len = newLen;
+ freeBegin = TRUE;
+ }
+ }
+
+ /*
+ * Append component. NUL terminator was accounted for by initializing
+ * textLen to one above.
+ */
+ textLen += preLen + len + postLen + (insertSpace ? 1 : 0);
+ text = Util_SafeRealloc(text, textLen);
+ Str_Snprintf(text + origTextLen - 1,
+ textLen - origTextLen + 1,
+ "%s%s%s", pre, begin, post);
+
+ if (insertSpace && next != end) {
+ ASSERT(textLen - 2 >= 0);
+ text[textLen - 2] = ' ';
+ text[textLen - 1] = '\0';
+ }
+
+ if (freeBegin) {
+ free((void *)begin);
+ }
+
+ /* Iterate to next component */
+ begin = next;
+ }
+
+ /*
+ * Send out the data using the selection system. When sending a string, GTK will
+ * ensure that a null terminating byte is added to the end so we do not need to
+ * add it. GTK also copies the data so the original will never be modified.
+ */
+ Debug("DnDGtkDataRequestCB: calling gtk_selection_data_set with [%s]\n", text);
+ gtk_selection_data_set(selection_data, selection_data->target,
+ 8, /* 8 bits per character. */
+ text, textLen);
+ free(text);
+}
+
+
+/*
+ * Guest->Host (drop target) Gtk callback implementations
+ */
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGtkDragMotionCB --
+ *
+ * "drag_motion" signal handler for GTK. This is invoked each time the
+ * mouse moves over the drag target (destination) window when a DnD is
+ * pending.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * RPC messages are sent to the host to proxy the DnD over.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static gboolean
+DnDGtkDragMotionCB(GtkWidget *widget, // IN: target widget
+ GdkDragContext *dc, // IN: the GDK drag context
+ gint x, // IN: x position of mouse
+ gint y, // IN: y position of mouse
+ guint time, // IN: time of event
+ gpointer data) // IN: our private data
+{
+ GdkAtom commonTarget = 0;
+ Bool found = FALSE;
+ uint32 i;
+
+ ASSERT(widget);
+ ASSERT(widget == data);
+ ASSERT(dc);
+
+ Debug("DnDGtkDragMotionCB: entry (x=%d, y=%d, time=%d)\n", x, y, time);
+
+ /*
+ * We'll get a number of these and should only carry on these operations on
+ * the first one.
+ *
+ * XXX Unity mode needs to know if there is a g->h->g dnd operation by
+ * detecting if the mouse has left the detection window. This code is
+ * currently not in the guest and should be ported from the host.
+ */
+ if (gGHState.dragInProgress && !gUnity) {
+ Debug("DnDGtkDragMotionCB: drag already in progress\n");
+ return FALSE;
+ }
+
+ /*
+ * Sometimes (rarely) real user mouse movements will trigger "drag_motion"
+ * signals after we have already handled them. Prevent resetting the data
+ * and trying to start a new DnD operation.
+ */
+ if (!gGHState.ungrabReceived && !gUnity) {
+ Debug("DnDGtkDragMotionCB: extra drag motion without ungrab\n");
+ return FALSE;
+ }
+
+ gGHState.ungrabReceived = FALSE;
+
+ /* Remove event that hides our widget out of band from the DnD protocol. */
+ if (gGHState.event) {
+ Debug("DnDGtkDragMotionCB: removed pending event\n");
+ EventManager_Remove(gGHState.event);
+ gGHState.event = NULL;
+ }
+
+ /*
+ * Note that gdk_drag_status() is called for us by GTK since we passed in
+ * GTK_DEST_DEFAULT_MOTION to gtk_drag_dest_set(). We'd handle it
+ * ourselves, but GTK 1.2.10 has a "bug" that requires us to provide this
+ * flag to get drag_leave and drag_drop signals.
+ */
+
+ /*
+ * We need to try and find a common target format with the list of formats
+ * offered by the drag source. This list is stored in the drag context's
+ * targets field, and each list member's data variable is a GdkAtom. We
+ * translated our supported targets into GdkAtoms in gTargetEntryAtom at
+ * initialization. Note that the GdkAtom value is an index into a table of
+ * strings maintained by the X server, so if they are equivalent then
+ * a common mime type is found.
+ */
+ for (i = 0; i < ARRAYSIZE(gTargetEntryAtom) && !found; i++) {
+ GList *currContextTarget = dc->targets;
+
+ while (currContextTarget) {
+ if (gTargetEntryAtom[i] == (GdkAtom)currContextTarget->data) {
+ commonTarget = gTargetEntryAtom[i];
+ found = TRUE;
+ break;
+ }
+ currContextTarget = currContextTarget->next;
+ }
+ }
+
+ if (!found) {
+ Warning("DnDGtkDragMotionCB: could not find a common target format\n");
+ DnDGHCancel(widget);
+ return FALSE;
+ }
+
+ /*
+ * Request the data. A "drag_data_received" signal will be sent to widget
+ * (that's us) upon completion.
+ */
+ gtk_drag_get_data(widget, dc, commonTarget, time);
+
+
+ gGHState.dragInProgress = TRUE;
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGtkDragDataReceivedCB --
+ *
+ * "drag_data_received" signal handler for GTK. Invoked when the data
+ * requested by a gtk_drag_get_data() call is ready.
+ *
+ * This function actually begins the drag operation with the host by first
+ * setting the data ("dnd.data.set" RPC command) and then starting the DnD
+ * ("dnd.enter" RPC command).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+DnDGtkDragDataReceivedCB(GtkWidget *widget, // IN
+ GdkDragContext *dc, // IN
+ gint x, // IN
+ gint y, // IN
+ GtkSelectionData *dragData, // IN
+ guint info, // IN
+ guint time, // IN
+ gpointer data) // IN
+{
+ const char rpcHeader[] = "dnd.data.set CF_HDROP ";
+ const size_t rpcHeaderSize = sizeof rpcHeader - 1;
+ char *rpcBody = NULL;
+ size_t rpcBodySize = 0;
+ char *rpc;
+ size_t rpcSize;
+
+
+ Debug("DnDGtkDragDataReceivedCB: entry\n");
+
+ if (dragData->length < 0) {
+ Warning("DnDGtkDragDataReceivedCB: received length < 0 error\n");
+ goto error;
+ }
+
+ gGHState.dragContext = dc;
+ gGHState.time = time;
+
+ /*
+ * Construct the body of the RPC message and our Guest->Host file list.
+ */
+ if (dragData->target == gTargetEntryAtom[DRAG_TARGET_INFO_URI_LIST]) {
+ char *currName;
+ size_t currSize;
+ size_t index = 0;
+ char *ghFileList = NULL;
+ size_t ghFileListSize = 0;
+
+ Debug("DnDGtkDragDataReceivedCB: uri-list [%s]\n", dragData->data);
+
+ /*
+ * Get the the full filenames and last components from the URI list. The
+ * body of the RPC message will be these last components delimited with
+ * NUL characters; the Guest->Host file list will be the full paths
+ * delimited by NUL characters.
+ */
+ while ((currName = DnD_UriListGetNextFile(dragData->data,
+ &index,
+ &currSize))) {
+ size_t lastComponentSize;
+ char *lastComponentStart;
+
+ /* Append current filename to Guest->Host list */
+ ghFileList = Util_SafeRealloc(ghFileList,
+ ghFileListSize + currSize + 1);
+ memcpy(ghFileList + ghFileListSize, currName, currSize);
+ ghFileListSize += currSize;
+ ghFileList[ghFileListSize] = '\0';
+ ghFileListSize++;
+
+ /* Append last component to RPC body */
+ lastComponentStart = CPNameUtil_Strrchr(currName, currSize, DIRSEPC);
+ if (!lastComponentStart) {
+ /*
+ * This shouldn't happen since filenames are absolute, but handle
+ * it as if the file name is the last component
+ */
+ lastComponentStart = currName;
+ } else {
+ /* Skip the last directory separator */
+ lastComponentStart++;
+ }
+
+ lastComponentSize = currName + currSize - lastComponentStart;
+ rpcBody = Util_SafeRealloc(rpcBody, rpcBodySize + lastComponentSize + 1);
+ memcpy(rpcBody + rpcBodySize, lastComponentStart, lastComponentSize);
+ rpcBodySize += lastComponentSize;
+ rpcBody[rpcBodySize] = '\0';
+ rpcBodySize++;
+
+ free(currName);
+ }
+
+ if (!ghFileList || !rpcBody) {
+ Warning("DnDGtkDragDataReceivedCB: no filenames retrieved "
+ "from URI list\n");
+ free(ghFileList);
+ free(rpcBody);
+ goto error;
+ }
+
+ /* Set the list of full paths for use in the "dnd.data.get.file" callback */
+ DnDGHFileListSet(ghFileList, ghFileListSize);
+
+ /* rpcBody (and its size) will always contain a trailing NUL character */
+ rpcBodySize--;
+ } else {
+ Warning("DnDGtkDragDataReceivedCB: unknown target format used [%s]\n",
+ dragData->data);
+ goto error;
+ }
+
+ /*
+ * Set the drag data on the host, followed by sending the drag enter
+ */
+ rpcSize = rpcHeaderSize + rpcBodySize;
+ rpc = Util_SafeMalloc(rpcSize);
+ memcpy(rpc, rpcHeader, rpcHeaderSize);
+ memcpy(rpc + rpcHeaderSize, rpcBody, rpcBodySize);
+ free(rpcBody);
+
+ Debug("DnDGtkDragMotionCB: Sending: [%s] (%"FMTSZ"u)\n",
+ CPName_Print(rpc, rpcSize), rpcSize);
+ if (!RpcOut_SendOneRaw(rpc, rpcSize, NULL, NULL)) {
+ Warning("DnDGtkDragMotionCB: failed to send dnd.data.set message\n");
+ free(rpc);
+ goto error;
+ }
+
+ free(rpc);
+
+ if (!RpcOut_sendOne(NULL, NULL, "dnd.enter 1 CF_HDROP")) {
+ Warning("DnDGtkDragMotionCB: failed to send dnd.enter message\n");
+ goto error;
+ }
+
+ return;
+
+error:
+ RpcOut_sendOne(NULL, NULL, "dnd.notpending");
+ DnDGHCancel(widget);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGtkDragDropCB --
+ *
+ * "drag_drop" signal handler for GTK. This is invoked when a mouse button
+ * release occurs on our widget. We generate that mouse button release in
+ * DnDRpcInFinishCB() when the host indicates that the drop has occurred and
+ * the files have been successfully transferred to the guest.
+ *
+ * Results:
+ * TRUE indicates to GTK that it need not run other handlers, FALSE
+ * otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static gboolean
+DnDGtkDragDropCB(GtkWidget *widget, // IN: widget event occurred on
+ GdkDragContext *dc, // IN: Destination drag context
+ gint x, // IN: x coordinate of drop
+ gint y, // IN: y coordinate of drop
+ guint time, // IN: time of event
+ gpointer data) // IN: our private data
+{
+ ASSERT(widget);
+ ASSERT(widget == data);
+
+ Debug("DnDGtkDragDropCB: entry (%d, %d)\n", x, y);
+
+ /* Remove timeout callback that was set in case we didn't get here */
+ if (gGHState.event) {
+ Debug("DnDGtkDragDropCB: removed pending event\n");
+ EventManager_Remove(gGHState.event);
+ gGHState.event = NULL;
+ }
+
+ /* Hide our window so we don't receive stray signals */
+ if (!gUnity) {
+ gtk_widget_hide(widget);
+ }
+
+ gtk_drag_finish(dc, TRUE, FALSE, time);
+
+ /* Reset all Guest->Host state */
+ DnDGHStateInit(widget);
+
+ return FALSE;
+}
+
+
+/*
+ * Utility functions
+ */
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnD_GetNewFileRoot --
+ *
+ * Convenience function that gets a new file root for use on a single DnD
+ * operation and sets the global file root variable accordingly.
+ *
+ * Results:
+ * Size of root string (not including NUL terminator).
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+DnD_GetNewFileRoot(char *fileRoot, // IN/OUT
+ int bufSize) // IN: sizeof fileRoot
+{
+ char *newDir = NULL;
+ size_t fileRootSize;
+
+ newDir = DnD_CreateStagingDirectory();
+ if (newDir == NULL) {
+ /*
+ * Fallback on base of file root if we couldn't create a staging
+ * directory for this DnD operation. This is what Windows DnD does.
+ */
+ Str_Strcpy(fileRoot, DnD_GetFileRoot(), bufSize);
+ return strlen(fileRoot);
+ } else {
+ fileRootSize = strlen(newDir);
+ ASSERT(fileRootSize < bufSize);
+ memcpy(fileRoot, newDir, fileRootSize);
+ fileRoot[fileRootSize] = '\0';
+ free(newDir);
+ return fileRootSize;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDSendVmxNewFileRoot --
+ *
+ * Sends the VMX a new file root with the provided RPC command.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure
+ *
+ * Side effects:
+ * gFileRoot is repopulated.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDSendVmxNewFileRoot(char *rpcCmd) // IN: RPC command
+{
+ int32 rpcCommandSize;
+ int32 cpNameSize;
+ int32 rpcMessageSize;
+ char *rpcMessage;
+ char *cur;
+
+ /* Repopulate gFileRoot */
+ gFileRootSize = DnD_GetNewFileRoot(gFileRoot, sizeof gFileRoot);
+
+ /*
+ * Here we must convert the file root before sending it across the
+ * backdoor. We can only communicate with new VMXs (v2 DnD), so we only
+ * need to handle that case here.
+ *
+ * <rpcCmd> <file root in local format><NUL><file root in CPName>
+ */
+ rpcCommandSize = strlen(rpcCmd);
+
+ /*
+ * ConvertToRoot below will append the root share name, so we need to
+ * make room for it in our buffer.
+ */
+ rpcMessageSize = rpcCommandSize + 1 +
+ gFileRootSize + 1 +
+ HGFS_STR_LEN(HGFS_SERVER_POLICY_ROOT_SHARE_NAME) + 1 +
+ gFileRootSize + 1;
+
+ rpcMessage = Util_SafeCalloc(1, rpcMessageSize);
+ memcpy(rpcMessage, rpcCmd, rpcCommandSize);
+ rpcMessage[rpcCommandSize] = ' ';
+ cur = rpcMessage + rpcCommandSize + 1;
+
+ memcpy(cur, gFileRoot, gFileRootSize);
+ cur += gFileRootSize;
+ *cur = '\0';
+ cur++;
+
+ Debug("DnDSendVmxNewFileRoot: calling CPNameUtil_ConvertToRoot(%s, %"FMTSZ"u, %p)\n",
+ gFileRoot, rpcMessageSize - (cur - rpcMessage), cur);
+ cpNameSize = CPNameUtil_ConvertToRoot(gFileRoot,
+ rpcMessageSize - (cur - rpcMessage),
+ cur);
+ if (cpNameSize < 0) {
+ Debug("DnDSendVmxNewFileRoot: Could not convert file root to CPName\n");
+ free(rpcMessage);
+ return FALSE;
+ }
+
+ /* Readjust message size for actual length */
+ rpcMessageSize = rpcCommandSize + 1 +
+ gFileRootSize + 1 +
+ cpNameSize + 1;
+
+ Debug("DnDSendVmxNewFileRoot: sending root [%s] (%d)\n",
+ CPName_Print(rpcMessage, rpcMessageSize), rpcMessageSize);
+
+ /*
+ * We must use RpcOut_SendOneRaw() here since RpcOut_sendOne() assumes a
+ * string and we are using CPName format.
+ */
+ if (!RpcOut_SendOneRaw(rpcMessage, rpcMessageSize, NULL, NULL)) {
+ Debug("DnDSendVmxNewFileRoot: Failed to send %s message to host\n", rpcCmd);
+ free(rpcMessage);
+ return FALSE;
+ }
+
+ free(rpcMessage);
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDFakeXEvents --
+ *
+ * Fake X mouse events and window movement for the provided Gtk widget.
+ *
+ * This function will optionally show the widget, move the provided widget
+ * to either the provided location or the current mouse position if no
+ * coordinates are provided, and cause a button press or release event.
+ *
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * Other X events should be generated from those faked here.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDFakeXEvents(GtkWidget *widget, // IN: the Gtk widget
+ Bool showWidget, // IN: whether to show Gtk widget
+ Bool buttonEvent, // IN: whether to send a button event
+ Bool buttonPress, // IN: whether to press or release mouse
+ Bool moveWindow, // IN: whether to move our window too
+ Bool coordsProvided,// IN: whether coordinates provided
+ int xCoord, // IN: x coordinate
+ int yCoord) // IN: y coordinate
+{
+ Window rootWnd;
+ Bool ret;
+ Display *dndXDisplay;
+ Window dndXWindow;
+
+ ASSERT(widget);
+
+ dndXDisplay = GDK_WINDOW_XDISPLAY(widget->window);
+ dndXWindow = GDK_WINDOW_XWINDOW(widget->window);
+
+ /*
+ * Turn on X synchronization in order to ensure that our X events occur in
+ * the order called. In particular, we want the window movement to occur
+ * before the mouse movement so that the events we are coercing do in fact
+ * happen.
+ */
+ XSynchronize(dndXDisplay, True);
+
+ if (showWidget) {
+ Debug("DnDFakeXEvents: showing Gtk widget\n");
+ gtk_widget_show(widget);
+ gdk_window_show(widget->window);
+ }
+
+ /* Get the current location of the mouse if coordinates weren't provided. */
+ if (!coordsProvided) {
+ Window rootReturn;
+ Window childReturn;
+ int rootXReturn;
+ int rootYReturn;
+ int winXReturn;
+ int winYReturn;
+ unsigned int maskReturn;
+
+ rootWnd = RootWindow(dndXDisplay, DefaultScreen(dndXDisplay));
+ ret = XQueryPointer(dndXDisplay, rootWnd, &rootReturn, &childReturn,
+ &rootXReturn, &rootYReturn, &winXReturn, &winYReturn,
+ &maskReturn);
+ if (ret == False) {
+ Warning("DnDFakeXEvents: XQueryPointer() returned False.\n");
+ XSynchronize(dndXDisplay, False);
+ return FALSE;
+ }
+
+ Debug("DnDFakeXEvents: mouse is at (%d, %d)\n", rootXReturn, rootYReturn);
+
+ xCoord = rootXReturn;
+ yCoord = rootYReturn;
+ }
+
+ if (moveWindow) {
+ /*
+ * Make sure the window is at this point and at the top (raised). The
+ * window is resized to be a bit larger than we would like to increase
+ * the likelihood that mouse events are attributed to our window -- this
+ * is okay since the window is invisible and hidden on cancels and DnD
+ * finish.
+ */
+ XMoveResizeWindow(dndXDisplay, dndXWindow, xCoord, yCoord, 25, 25);
+ XRaiseWindow(dndXDisplay, dndXWindow);
+ }
+
+ /*
+ * Generate mouse movements over the window. The second one makes ungrabs
+ * happen more reliably on KDE, but isn't necessary on GNOME.
+ */
+ XTestFakeMotionEvent(dndXDisplay, -1, xCoord, yCoord, CurrentTime);
+ XTestFakeMotionEvent(dndXDisplay, -1, xCoord + 1, yCoord + 1, CurrentTime);
+
+ if (buttonEvent) {
+ Debug("DnDFakeXEvents: faking left mouse button %s\n",
+ buttonPress ? "press" : "release");
+ XTestFakeButtonEvent(dndXDisplay, 1, buttonPress, CurrentTime);
+ }
+
+ XSynchronize(dndXDisplay, False);
+
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDSendEscapeKey --
+ *
+ * Sends the escape key, canceling any pending drag and drop on the guest.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+DnDSendEscapeKey(GtkWidget *mainWnd) // IN
+{
+ Display *dndXDisplay;
+ uint32 escKeycode;
+
+ Debug("DnDRpcInFinishCB: faking ESC key press/release\n");
+
+ dndXDisplay = GDK_WINDOW_XDISPLAY(mainWnd->window);
+ escKeycode = XKeysymToKeycode(dndXDisplay, XK_Escape);
+
+ XTestFakeKeyEvent(dndXDisplay, escKeycode, TRUE, CurrentTime);
+ XTestFakeKeyEvent(dndXDisplay, escKeycode, FALSE, CurrentTime);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGHDragPending --
+ *
+ * Determine whether a drag is currently pending within the guest by
+ * inspecting the internal state of the X server. Note that Gtk supports
+ * both the Xdnd and Motif protocols, so we check each one of those.
+ *
+ * Results:
+ * TRUE if a Drag operation is pending (waiting for a drop), FALSE
+ * otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+DnDGHDragPending(GtkWidget *widget) // IN: our widget
+{
+ /* Xdnd is much more prevalent, so call it first */
+ return DnDGHXdndDragPending(widget) || DnDGHMotifDragPending(widget);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGHXdndDragPending --
+ *
+ * Determines whether an Xdnd protocol drag is pending.
+ *
+ * Results:
+ * TRUE is a drag is pending, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+DnDGHXdndDragPending(GtkWidget *widget) // IN: our widget
+{
+ GdkAtom xDnDSelection;
+ Window owner;
+
+ xDnDSelection = gdk_atom_intern("XdndSelection", TRUE);
+ if (xDnDSelection == None) {
+ Warning("DnDGHXdndDragPending: could not obtain Xdnd selection atom\n");
+ return FALSE;
+ }
+
+ /*
+ * The XdndSelection atom will only have an owner if there is a drag in
+ * progress.
+ */
+ owner = XGetSelectionOwner(GDK_WINDOW_XDISPLAY(widget->window),
+ GDKATOM_TO_ATOM(xDnDSelection));
+
+ Debug("DnDGHXdndDragPending: an Xdnd drag is %spending\n",
+ owner != None ? "" : "not ");
+
+ return owner != None;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGHXdndClearPending --
+ *
+ * Clear the ownership of the XdndSelection selection atom that we use to
+ * determine if a Xdnd drag is pending.
+ *
+ * Note that this function should only be called when a DnD is not in
+ * progress.
+ *
+ * Also note that this is function is only necessary to handle desktop
+ * environments that don't clear the selection owner themselves (read KDE).
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+DnDGHXdndClearPending(GtkWidget *widget) // IN: program's widget
+{
+ GdkAtom xDnDSelection;
+
+ ASSERT(!gGHState.dragInProgress);
+
+ xDnDSelection = gdk_atom_intern("XdndSelection", TRUE);
+ if (xDnDSelection == None) {
+ return;
+ }
+
+ /* Clear current owner by setting owner to None */
+ XSetSelectionOwner(GDK_WINDOW_XDISPLAY(widget->window),
+ GDKATOM_TO_ATOM(xDnDSelection), None, CurrentTime);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDMotifDragPending --
+ *
+ * Determines whether a Motif protocol drag is pending.
+ *
+ * XXX This has not yet been tested (looking for an app that actually uses
+ * the Motif protocol)
+ *
+ * Results:
+ * TRUE if a drag is pending, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+DnDGHMotifDragPending(GtkWidget *widget) // IN: our widget
+{
+ GdkAtom motifDragWindow;
+ Display *dndXDisplay;
+ int ret;
+ Window rootXWindow;
+ Atom type;
+ int format;
+ unsigned long nitems;
+ unsigned long bytesAfter;
+ unsigned char *prop;
+
+ motifDragWindow = gdk_atom_intern("_MOTIF_DRAG_WINDOW", TRUE);
+ if (motifDragWindow == None) {
+ Warning("DnDGHMotifDragPending: could not obtain Motif "
+ "drag window atom\n");
+ return FALSE;
+ }
+
+ dndXDisplay = GDK_WINDOW_XDISPLAY(widget->window);
+ rootXWindow = RootWindow(dndXDisplay, DefaultScreen(dndXDisplay));
+
+ /*
+ * Try and get the Motif drag window property from X's root window. If one
+ * is provided, a DnD is pending.
+ */
+ ret = XGetWindowProperty(dndXDisplay, rootXWindow, GDKATOM_TO_ATOM(motifDragWindow),
+ 0, 1, False, XA_WINDOW,
+ &type, &format, &nitems, &bytesAfter, &prop);
+ if (ret != Success) {
+ Warning("DnDGHMotifDragPending: XGetWindowProperty() error.\n");
+ return FALSE;
+ }
+
+ if (type == None) {
+ Debug("DnDGHXdndDragPending: a Motif drag is not pending\n");
+ return FALSE;
+ }
+
+ Debug("DnDGHXdndDragPending: a Motif drag is pending\n");
+
+ XFree(prop);
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGHFileListClear --
+ *
+ * Clears existing Guest->Host file list, releasing any used resources.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+DnDGHFileListClear(void)
+{
+ Debug("DnDGHFileListClear: clearing G->H file list\n");
+ if (gGHState.dndFileList) {
+ free(gGHState.dndFileList);
+ gGHState.dndFileList = NULL;
+ }
+ gGHState.dndFileListSize = 0;
+ gGHState.dndFileListNext = NULL;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGHFileListSet --
+ *
+ * Sets the Guest->Host file list that is accessed through
+ * DnDGHFileListGetNext().
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Clears the existing Guest->Host file list if it exists.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+DnDGHFileListSet(char *fileList, // IN: new Guest->Host file list
+ size_t fileListSize) // IN: size of the provided list
+{
+ DnDGHFileListClear();
+ gGHState.dndFileList = fileList;
+ gGHState.dndFileListSize = fileListSize;
+ gGHState.dndFileListNext = fileList;
+
+ Debug("DnDGHFileListSet: [%s] (%"FMTSZ"u)\n",
+ CPName_Print(gGHState.dndFileList, gGHState.dndFileListSize),
+ gGHState.dndFileListSize);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGHFileListGetNext --
+ *
+ * Retrieves the next file in the Guest->Host file list.
+ *
+ * Note that this function may only be called after calling
+ * DnDGHFileListSet() and before calling DnDGHFileListClear().
+ *
+ * Results:
+ * TRUE on success, FALSE on failure. If TRUE is returned, fileName is
+ * given a pointer to the filename's location or NULL if there are no more
+ * files, and fileNameSize is given the length of fileName.
+ *
+ * Side effects:
+ * The fileListNext value of the Guest->Host global state is updated.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+DnDGHFileListGetNext(char **fileName, // OUT: fill with filename location
+ size_t *fileNameSize) // OUT: fill with filename length
+{
+ char const *end;
+ char const *next;
+ int len;
+
+ ASSERT(gGHState.dndFileList);
+ ASSERT(gGHState.dndFileListNext);
+ ASSERT(gGHState.dndFileListSize > 0);
+
+ /* Ensure end is the last NUL character */
+ end = CPNameUtil_Strrchr(gGHState.dndFileList, gGHState.dndFileListSize, '\0');
+ ASSERT(end);
+
+ /* Get the length of this filename and a pointer to the next one */
+ len = CPName_GetComponent(gGHState.dndFileListNext, end, &next);
+ if (len < 0) {
+ Warning("DnDGHFileListGetNext: error retrieving next component\n");
+ return FALSE;
+ }
+
+ /* No more entries in the list */
+ if (len == 0) {
+ Debug("DnDGHFileListGetNext: no more entries\n");
+ *fileName = NULL;
+ *fileNameSize = 0;
+ return TRUE;
+ }
+
+ Debug("DnDGHFileListGetNext: returning [%s] (%d)\n",
+ gGHState.dndFileListNext, len);
+
+ *fileName = gGHState.dndFileListNext;
+ *fileNameSize = len;
+ gGHState.dndFileListNext = (char *)next;
+ return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGHStateInit --
+ *
+ * Initializes the Guest->Host DnD state.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+DnDGHStateInit(GtkWidget *widget) // IN
+{
+ Debug("DnDGHStateInit: initializing guest->host state\n");
+ gGHState.time = 0;
+ gGHState.dragContext = NULL;
+ gGHState.dragInProgress = FALSE;
+ gGHState.ungrabReceived = FALSE;
+ gGHState.event = NULL;
+ DnDGHXdndClearPending(widget);
+ if (!gUnity) {
+ gtk_widget_hide(widget);
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDHGStateInit --
+ *
+ * Initialize the Host->Guest DnD state.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+DnDHGStateInit(void)
+{
+ gHGDnDInProgress = FALSE;
+ gDoneDragging = FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGHCancel --
+ *
+ * Resets state and sends a DnD cancel message to the host.
+ *
+ * Results:
+ * TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ * DnD operation is cancelled.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+DnDGHCancel(GtkWidget *widget) // IN: program's widget
+{
+ /* Hide our widget so we don't receive stray signals */
+ if (widget && !gUnity) {
+ gtk_widget_hide(widget);
+ }
+
+ if (gGHState.dragContext) {
+ gdk_drag_status(gGHState.dragContext, 0, gGHState.time);
+ }
+
+ gGHState.dragInProgress = FALSE;
+
+ /*
+ * We don't initialize Guest->Host state here since an ungrab/grab/ungrab
+ * will cause a cancel but we want the drop of the DnD to still work.
+ */
+ return RpcOut_sendOne(NULL, NULL, "dnd.finish cancel");
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnDGHXEventTimeout --
+ *
+ * Cleans up after fake X events do not cause intended events. Hides the
+ * provided widget and resets all Guest->Host DnD state.
+ *
+ * Note that this is expected to occur on ungrab if there is not a DnD
+ * pending, but may also occur at other times (sometimes we do not receive
+ * the drag drop after the mouse button release is faked on KDE).
+ *
+ * This function is invoked by the event manager; it is added/removed
+ * to/from the queue in both DnDRpcInMouseUngrabCB() and DnDRpcInFinishCB(),
+ * and DnDGtkDragMotionCB() and DnDGtkDragDropCB() respectively.
+ *
+ * Results:
+ * TRUE always, so the event manager doesn't stop running.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+DnDGHXEventTimeout(void *clientData) // IN: our widget
+{
+ GtkWidget *widget = (GtkWidget *)clientData;
+
+ Debug("DnDGHXEventTimeout time out \n");
+
+ RpcOut_sendOne(NULL, NULL, "dnd.notpending");
+
+ if (!gGHState.dragInProgress && !gUnity) {
+ gtk_widget_hide(widget);
+ }
+
+ /* gGHState.event is cleared with the rest of Guest->Host state */
+ DnDGHStateInit(widget);
+
+ return TRUE;
+}
+
+
+/*
+ * Public functions invoked by the rest of vmware-user
+ */
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnD_GetVmxDnDVersion --
+ *
+ * Ask the vmx for it's dnd version.
+ *
+ * Results:
+ * The dnd version the vmx supports, 0 if the vmx doesn't know
+ * what we're talking about.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+uint32
+DnD_GetVmxDnDVersion(void)
+{
+ char *reply = NULL;
+ size_t replyLen;
+ uint32 vmxVersion;
+
+ if (!RpcOut_sendOne(&reply, &replyLen, "vmx.capability.dnd_version")) {
+ Debug("DnD_GetVmxDnDVersion: could not get VMX DnD version "
+ "capability: %s\n", reply ? reply : "NULL");
+ vmxVersion = 0;
+ } else {
+ vmxVersion = atoi(reply);
+ ASSERT(vmxVersion > 1); /* DnD versions start at 2 */
+ }
+
+ free(reply);
+ return vmxVersion;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnD_RegisterCapability --
+ *
+ * Register the "dnd" capability. Sometimes this needs to be done separately
+ * from the rest of DnD registration, so we provide it separately here.
+ *
+ * Results:
+ * TRUE on success
+ * FALSE on failure
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+DnD_RegisterCapability(void)
+{
+ /* Tell the VMX about the DnD version we support. */
+ if (!RpcOut_sendOne(NULL, NULL, "tools.capability.dnd_version 2")) {
+ Debug("DnD_RegisterCapability: could not set guest DnD version capability\n");
+ return FALSE;
+ } else if (!DnDSendVmxNewFileRoot("dnd.ready enable")) {
+ Debug("DnD_RegisterCapability: failed to send dnd.ready message to host\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnD_Register --
+ *
+ * Register the DnD capability, setup callbacks, initialize.
+ *
+ * Results:
+ * TRUE on success, FALSE otherwise.
+ *
+ * Side effects:
+ * mainWnd will be a dragSource in the guest, and dnd will work from
+ * host to guest.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+DnD_Register(GtkWidget *hgWnd, // IN: The widget to register as a drag source.
+ GtkWidget *ghWnd) // IN: The widget to register as a drag target.
+{
+ uint32 i;
+
+ gDragCtx = NULL;
+
+ ASSERT(hgWnd);
+ ASSERT(ghWnd);
+
+ if (DnD_GetVmxDnDVersion() < 2) {
+ goto error;
+ }
+
+ /*
+ * We can't pass in NULL to XTestQueryExtension(), so pass in a dummy
+ * variable to avoid segfaults. If we have a reason to check the major and
+ * minor numbers of the running extension, that would go here.
+ */
+ if (!XTestQueryExtension(GDK_WINDOW_XDISPLAY(hgWnd->window),
+ &i, &i, &i, &i)) {
+ goto error;
+ }
+
+ /* Host->Guest RPC callbacks */
+ RpcIn_RegisterCallback(gRpcIn, "dnd.data.set", DnDRpcInDataSetCB, hgWnd);
+ RpcIn_RegisterCallback(gRpcIn, "dnd.enter", DnDRpcInEnterCB, hgWnd);
+ RpcIn_RegisterCallback(gRpcIn, "dnd.move", DnDRpcInMoveCB, hgWnd);
+ RpcIn_RegisterCallback(gRpcIn, "dnd.drop", DnDRpcInDropCB, hgWnd);
+ RpcIn_RegisterCallback(gRpcIn, "dnd.data.finish", DnDRpcInDataFinishCB,
+ hgWnd);
+
+ /* Guest->Host RPC callbacks */
+ RpcIn_RegisterCallback(gRpcIn, "dnd.ungrab",
+ DnDRpcInMouseUngrabCB, ghWnd);
+ RpcIn_RegisterCallback(gRpcIn, "dnd.data.get.file",
+ DnDRpcInGetNextFileCB, ghWnd);
+ RpcIn_RegisterCallback(gRpcIn, "dnd.finish",
+ DnDRpcInFinishCB, ghWnd);
+
+ /*
+ * Setup mainWnd as a DND source/dest.
+ *
+ * Note that G->H drag targets should come first in this array. Currently
+ * G->H only supports text/uri-list targets.
+ */
+ gTargetEntry[0].target = DRAG_TARGET_NAME_URI_LIST;
+ gTargetEntry[0].info = DRAG_TARGET_INFO_URI_LIST;
+ gTargetEntry[0].flags = 0;
+ gTargetEntry[1].target = DRAG_TARGET_NAME_TEXT_PLAIN;
+ gTargetEntry[1].info = DRAG_TARGET_INFO_TEXT_PLAIN;
+ gTargetEntry[1].flags = 0;
+ gTargetEntry[2].target = DRAG_TARGET_NAME_STRING;
+ gTargetEntry[2].info = DRAG_TARGET_INFO_STRING;
+ gTargetEntry[2].flags = 0;
+
+ /* Populate our GdkAtom table for our supported Guest->Host targets */
+ for (i = 0;
+ i < ARRAYSIZE(gTargetEntry) && i < ARRAYSIZE(gTargetEntryAtom);
+ i++) {
+ gTargetEntryAtom[i] = gdk_atom_intern(gTargetEntry[i].target, FALSE);
+ }
+
+ /* Drag source for Host->Guest */
+ gtk_drag_source_set(hgWnd, GDK_BUTTON1_MASK,
+ gTargetEntry, ARRAYSIZE(gTargetEntry),
+ GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+ gtk_signal_connect(GTK_OBJECT(hgWnd), "drag_begin",
+ GTK_SIGNAL_FUNC(DnDGtkBeginCB), hgWnd);
+ gtk_signal_connect(GTK_OBJECT(hgWnd), "drag_end",
+ GTK_SIGNAL_FUNC(DnDGtkEndCB), hgWnd);
+ gtk_signal_connect(GTK_OBJECT(hgWnd), "drag_data_get",
+ GTK_SIGNAL_FUNC(DnDGtkDataRequestCB), hgWnd);
+
+
+ /*
+ * Drop target (destination) for Guest->Host
+ *
+ * We provide NR_GH_DRAG_TARGETS (rather than ARRAYSIZE(gTargetEntry)) to
+ * gtk_drag_dest_set() since we support less targets for G->H than H->G.
+ */
+ gtk_drag_dest_set(ghWnd,
+ GTK_DEST_DEFAULT_MOTION,
+ gTargetEntry, NR_GH_DRAG_TARGETS,
+ GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+ gtk_signal_connect(GTK_OBJECT(ghWnd), "drag_motion",
+ GTK_SIGNAL_FUNC(DnDGtkDragMotionCB), ghWnd);
+ gtk_signal_connect(GTK_OBJECT(ghWnd), "drag_data_received",
+ GTK_SIGNAL_FUNC(DnDGtkDragDataReceivedCB),
+ ghWnd);
+ gtk_signal_connect(GTK_OBJECT(ghWnd), "drag_drop",
+ GTK_SIGNAL_FUNC(DnDGtkDragDropCB), ghWnd);
+
+ DnD_OnReset(hgWnd, ghWnd);
+
+ if (DnD_RegisterCapability()) {
+ return TRUE;
+ }
+
+ /*
+ * We get here if DnD registration fails for some reason
+ */
+error:
+ DnD_Unregister(hgWnd, ghWnd);
+ return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DnD_Unregister --
+ *
+ * Cleanup dnd related things.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * DnD is stopped, the rpc channel to the vmx is closed.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+DnD_Unregister(GtkWidget *hgWnd, // IN: The widget for hg dnd
+ GtkWidget *ghWnd) // IN: The widget for gh dnd
+{
+ RpcOut_sendOne(NULL, NULL, "dnd.ready disable");
+
+ DnDGHFileListClear();
+
+ /* Unregister source for Host->Guest DnD. */
+ gtk_drag_source_unset(hgWnd);
+ gtk_signal_disconnect_by_func(GTK_OBJECT(hgWnd),
+ GTK_SIGNAL_FUNC(DnDGtkBeginCB),
+ hgWnd);
+ gtk_signal_disconnect_by_func(GTK_OBJECT(hgWnd),
+ GTK_SIGNAL_FUNC(DnDGtkEndCB),
+ hgWnd);
+ gtk_signal_disconnect_by_func(GTK_OBJECT(hgWnd),
+ GTK_SIGNAL_FUNC(DnDGtkDataRequestCB),
+ hgWnd);
+
+ /* Unregister destination for Guest->Host DnD. */
+ gtk_drag_dest_unset(ghWnd);
+ gtk_signal_disconnect_by_func(GTK_OBJECT(ghWnd),
+ GTK_SIGNAL_FUNC(DnDGtkDragMotionCB),
+ ghWnd);
+ gtk_signal_disconnect_by_func(GTK_OBJECT(ghWnd),
+ GTK_SIGNAL_FUNC(DnDGtkDragDataReceivedCB),
+ ghWnd);
+ gtk_signal_disconnect_by_func(GTK_OBJECT(ghWnd),
+ GTK_SIGNAL_FUNC(DnDGtkDragDropCB),
+ ghWnd);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnD_OnReset --
+ *
+ * Handles reinitializing DnD state on a reset.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * DnD is stopped and restarted.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnD_OnReset(GtkWidget *hgWnd, // IN: The widget for hg dnd
+ GtkWidget *ghWnd) // IN: The widget for gh dnd
+
+{
+ Debug("DnD_OnReset: entry\n");
+
+ /* Cancel file transfer. */
+ if (gHGDnDInProgress || gHGDataPending) {
+ DnD_DeleteStagingFiles(gFileRoot, FALSE);
+ if (gBlockFd >= 0 && !DnD_RemoveBlock(gBlockFd, gFileRoot)) {
+ Warning("DnD_OnReset: could not remove block on %s\n",
+ gFileRoot);
+ }
+ }
+
+ /*
+ * If a DnD in either direction was in progress during suspend, send an
+ * escape to cancel the operation and reset the pointer state.
+ */
+ if (gHGDnDInProgress) {
+ Debug("DnD_OnReset: sending hgWnd escape\n");
+ DnDSendEscapeKey(hgWnd);
+ }
+
+ if (gGHState.dragInProgress) {
+ Debug("DnD_OnReset: sending ghWnd escape\n");
+ DnDSendEscapeKey(ghWnd);
+ }
+
+ if (gGHState.dragInProgress) {
+ Debug("DnD_OnReset: canceling host->guest DnD\n");
+ DnDGHCancel(ghWnd);
+ }
+
+ /* Reset DnD state. */
+ DnDHGStateInit();
+ DnDGHStateInit(ghWnd);
+ DnDGHFileListClear();
+ DnD_SetMode(FALSE);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnD_InProgress --
+ *
+ * Indicates whether a DnD (or its data transfer) is currently in progress.
+ *
+ * Results:
+ * TRUE if a DnD is in progress, FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+DnD_InProgress(void)
+{
+ return gGHState.dragInProgress || gHGDnDInProgress || gHGDataPending;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DnD_SetMode --
+ *
+ * Sets dnd mode to single window or unity mode.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Controls if the g->h det window is automatically hidden.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+DnD_SetMode(Bool unity) // IN
+{
+ gUnity = unity;
+}
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2003 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-/*
- * foundryToolsDaemon.c --
- *
- * VIX-specific TCLO cmds that are called through the backdoor
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#if defined(linux)
-#include <sys/wait.h>
-#include <mntent.h>
-#include <paths.h>
-#endif
-
-
-#ifdef _WIN32
-#include <io.h>
-#else
-#include <errno.h>
-#include <unistd.h>
-#endif
-
-#ifdef _MSC_VER
-# include <Windows.h>
-# include <WinSock2.h>
-# include <WinSpool.h>
-# include "win32u.h"
-#elif _WIN32
-# include "win95.h"
-#endif
-
-#include "vmware.h"
-#include "procMgr.h"
-#include "vm_version.h"
-#include "vm_app.h"
-#include "message.h"
-
-#if defined(VMTOOLS_USE_GLIB)
-# include "vixPluginInt.h"
-# include "vmtools.h"
-#else
-# include "debug.h"
-# include "eventManager.h"
-# include "rpcin.h"
-# include "rpcout.h"
-#endif
-
-#include "util.h"
-#include "strutil.h"
-#include "str.h"
-#include "file.h"
-#include "err.h"
-#include "hostinfo.h"
-#include "guest_os.h"
-#include "conf.h"
-#include "vixCommands.h"
-#include "foundryToolsDaemon.h"
-#include "printer.h"
-#include "base64.h"
-#include "syncDriver.h"
-#include "hgfsServer.h"
-#include "hgfs.h"
-#include "system.h"
-#include "codeset.h"
-
-#if defined(linux)
-#include "hgfsDevLinux.h"
-#endif
-
-#ifndef __FreeBSD__
-#include "netutil.h"
-#endif
-
-/* Only Win32 and Linux use impersonation functions. */
-#if !defined(__FreeBSD__) && !defined(sun)
-#include "impersonate.h"
-#endif
-
-#include "vixTools.h"
-#include "vixOpenSource.h"
-
-#if !defined(VMTOOLS_USE_GLIB)
-static DblLnkLst_Links *globalEventQueue; // event queue for main event loop
-#endif
-
-#define GUESTMSG_MAX_IN_SIZE (64 * 1024) /* vmx/main/guest_msg.c */
-#define MAX64_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */
-
-#if defined(linux) || defined(_WIN32)
-
-# if defined(_WIN32)
-# define DECLARE_SYNCDRIVER_ERROR(name) DWORD name = ERROR_SUCCESS
-# define SYNCDRIVERERROR ERROR_GEN_FAILURE
-# else
-# define DECLARE_SYNCDRIVER_ERROR(name) int name = 0
-# define SYNCDRIVERERROR errno
-# endif
-
-static SyncDriverHandle gSyncDriverHandle = SYNCDRIVER_INVALID_HANDLE;
-
-static Bool ToolsDaemonSyncDriverThawCallback(void *clientData);
-#endif
-
-static char *ToolsDaemonTcloGetQuotedString(const char *args,
- const char **endOfArg);
-
-static char * ToolsDaemonTcloGetEncodedQuotedString(const char *args,
- const char **endOfArg);
-
-Bool ToolsDaemonTcloReceiveVixCommand(RpcInData *data);
-
-#if !defined(N_PLAT_NLM)
-Bool ToolsDaemonHgfsImpersonated(RpcInData *data);
-#endif
-
-#if defined(linux) || defined(_WIN32)
-Bool ToolsDaemonTcloSyncDriverFreeze(RpcInData *data);
-
-Bool ToolsDaemonTcloSyncDriverThaw(RpcInData *data);
-#endif
-
-Bool ToolsDaemonTcloMountHGFS(RpcInData *data);
-
-void ToolsDaemonTcloReportProgramCompleted(const char *requestName,
- VixError err,
- int exitCode,
- int64 pid,
- void *clientData);
-
-/*
- * These constants are a bad hack. I really should generate the result
- * strings twice, once to compute the length and then allocate the buffer,
- * and a second time to write the buffer.
- */
-#define DEFAULT_RESULT_MSG_MAX_LENGTH 1024
-
-static Bool thisProcessRunsAsRoot = FALSE;
-
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FoundryToolsDaemonRunProgram --
- *
- * Run a named program on the guest.
- *
- * Return value:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-FoundryToolsDaemonRunProgram(RpcInData *data) // IN
-{
- VixError err = VIX_OK;
- char *requestName = NULL;
- char *commandLine = NULL;
- char *commandLineArgs = NULL;
- char *credentialTypeStr = NULL;
- char *obfuscatedNamePassword = NULL;
- char *directoryPath = NULL;
- char *environmentVariables = NULL;
- static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
- Bool impersonatingVMWareUser = FALSE;
- void *userToken = NULL;
- ProcMgr_Pid pid;
-#if defined(VMTOOLS_USE_GLIB)
- GMainLoop *eventQueue = ((ToolsAppCtx *)data->appCtx)->mainLoop;
-#else
- DblLnkLst_Links *eventQueue = data->clientData;
-#endif
-
- /*
- * Parse the arguments. Some of these are optional, so they
- * may be NULL.
- */
- requestName = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
- commandLine = ToolsDaemonTcloGetEncodedQuotedString(data->args, &data->args);
- commandLineArgs = ToolsDaemonTcloGetEncodedQuotedString(data->args, &data->args);
- credentialTypeStr = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
- obfuscatedNamePassword = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
- directoryPath = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
- environmentVariables = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
-
- /*
- * Make sure we are passed the correct arguments.
- * Some of these arguments (like credentialTypeStr and obfuscatedNamePassword) are optional,
- * so they may be NULL.
- */
- if ((NULL == requestName) || (NULL == commandLine)) {
- err = VIX_E_INVALID_ARG;
- goto abort;
- }
-
- if ((NULL != credentialTypeStr)
- && (*credentialTypeStr)
- && (thisProcessRunsAsRoot)) {
- impersonatingVMWareUser = VixToolsImpersonateUserImpl(credentialTypeStr,
- VIX_USER_CREDENTIAL_NONE,
- obfuscatedNamePassword,
- &userToken);
- if (!impersonatingVMWareUser) {
- err = VIX_E_GUEST_USER_PERMISSIONS;
- goto abort;
- }
- }
-
- err = VixToolsRunProgramImpl(requestName,
- commandLine,
- commandLineArgs,
- 0,
- userToken,
- eventQueue,
- (int64 *) &pid);
-
-abort:
- if (impersonatingVMWareUser) {
- VixToolsUnimpersonateUser(userToken);
- }
- VixToolsLogoutUser(userToken);
-
- /*
- * All VMXI tools commands return results that start with a VMXI error
- * and a guest-OS-specific error.
- */
- Str_Sprintf(resultBuffer,
- sizeof(resultBuffer),
- "%"FMT64"d %d %"FMT64"d",
- err,
- Err_Errno(),
- (int64) pid);
- RPCIN_SETRETVALS(data, resultBuffer, TRUE);
-
- /*
- * These were allocated by ToolsDaemonTcloGetQuotedString.
- */
- free(requestName);
- free(commandLine);
- free(credentialTypeStr);
- free(obfuscatedNamePassword);
- free(directoryPath);
- free(environmentVariables);
- free(commandLineArgs);
-
- return TRUE;
-} // FoundryToolsDaemonRunProgram
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FoundryToolsDaemonGetToolsProperties --
- *
- * Get information about test features.
- *
- * Return value:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-FoundryToolsDaemonGetToolsProperties(RpcInData *data) // IN
-{
- VixError err = VIX_OK;
- int additionalError = 0;
- static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
- char *serializedBuffer = NULL;
- size_t serializedBufferLength = 0;
- char *base64Buffer = NULL;
- size_t base64BufferLength = 0;
- Bool success;
- char *returnBuffer = NULL;
-#if defined(VMTOOLS_USE_GLIB)
- GKeyFile *confDictRef;
-#else
- GuestApp_Dict **confDictRef;
-#endif
-
- /*
- * Collect some values about the host.
- */
- confDictRef = data->clientData;
-
- err = VixTools_GetToolsPropertiesImpl(confDictRef,
- &serializedBuffer,
- &serializedBufferLength);
- if (VIX_OK == err) {
- base64BufferLength = Base64_EncodedLength(serializedBuffer, serializedBufferLength) + 1;
- base64Buffer = Util_SafeMalloc(base64BufferLength);
- success = Base64_Encode(serializedBuffer,
- serializedBufferLength,
- base64Buffer,
- base64BufferLength,
- &base64BufferLength);
- if (!success) {
- base64Buffer[0] = 0;
- err = VIX_E_FAIL;
- goto abort;
- }
- base64Buffer[base64BufferLength] = 0;
- }
-
-
-abort:
- returnBuffer = base64Buffer;
- if (NULL == base64Buffer) {
- returnBuffer = "";
- }
- if (VIX_OK != err) {
- additionalError = Err_Errno();
- }
-
- /*
- * All VMXI tools commands return results that start with a VMXI error
- * and a guest-OS-specific error.
- */
- Str_Sprintf(resultBuffer,
- sizeof(resultBuffer),
- "%"FMT64"d %d %s",
- err,
- additionalError,
- returnBuffer);
- RPCIN_SETRETVALS(data, resultBuffer, TRUE);
-
- free(serializedBuffer);
- free(base64Buffer);
-
- return TRUE;
-} // FoundryToolsDaemonGetToolsProperties
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonTcloCheckUserAccount --
- *
- *
- * Return value:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-ToolsDaemonTcloCheckUserAccount(RpcInData *data) // IN
-{
- VixError err = VIX_OK;
- char *credentialTypeStr = NULL;
- char *obfuscatedNamePassword = NULL;
- static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
- Bool impersonatingVMWareUser = FALSE;
- void *userToken = NULL;
- Debug(">ToolsDaemonTcloCheckUserAccount\n");
-
- /*
- * Parse the argument
- */
- credentialTypeStr = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
- obfuscatedNamePassword = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
-
- /*
- * Make sure we are passed the correct arguments.
- */
- if ((NULL == credentialTypeStr) || (NULL == obfuscatedNamePassword)) {
- err = VIX_E_INVALID_ARG;
- goto abort;
- }
-
- if (thisProcessRunsAsRoot) {
- impersonatingVMWareUser = VixToolsImpersonateUserImpl(credentialTypeStr,
- VIX_USER_CREDENTIAL_NONE,
- obfuscatedNamePassword,
- &userToken);
- if (!impersonatingVMWareUser) {
- err = VIX_E_GUEST_USER_PERMISSIONS;
- goto abort;
- }
- }
-
-abort:
- if (impersonatingVMWareUser) {
- VixToolsUnimpersonateUser(userToken);
- }
- VixToolsLogoutUser(userToken);
-
- /*
- * All VMXI tools commands return results that start with a VMXI error
- * and a guest-OS-specific error.
- */
- Str_Sprintf(resultBuffer,
- sizeof(resultBuffer),
- "%"FMT64"d %d",
- err,
- Err_Errno());
- RPCIN_SETRETVALS(data, resultBuffer, TRUE);
-
- /*
- * These were allocated by ToolsDaemonTcloGetQuotedString.
- */
- free(credentialTypeStr);
- free(obfuscatedNamePassword);
-
- return TRUE;
-} // ToolsDaemonTcloCheckUserAccount
-
-#if defined(VMTOOLS_USE_GLIB)
-
-/**
- * Initializes internal state of the Foundry daemon.
- *
- * @param[in] ctx Application context.
- */
-
-void
-FoundryToolsDaemon_Initialize(ToolsAppCtx *ctx)
-{
- thisProcessRunsAsRoot = (strcmp(ctx->name, VMTOOLS_GUEST_SERVICE) == 0);
- (void) VixTools_Initialize(thisProcessRunsAsRoot,
- ToolsDaemonTcloReportProgramCompleted,
- ctx);
-
-#if defined(linux) || defined(_WIN32)
- if (thisProcessRunsAsRoot) {
- Impersonate_Init();
- }
-#endif
-
-}
-
-#else
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FoundryToolsDaemon_RegisterRoutines --
- *
- * Register the Foundry RPC callbacks
- *
- * Return value:
- * None
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-FoundryToolsDaemon_RegisterRoutines(RpcIn *in, // IN
- GuestApp_Dict **confDictRef, // IN
- DblLnkLst_Links *eventQueue, // IN
- Bool runAsRoot) // IN
-{
- static Bool inited = FALSE;
-#if defined(linux) || defined(_WIN32)
- static Bool sync_driver_inited = FALSE;
-#endif
-
- ASSERT(in);
- ASSERT(confDictRef);
- ASSERT(*confDictRef);
-
- thisProcessRunsAsRoot = runAsRoot;
- globalEventQueue = eventQueue;
-
- (void) VixTools_Initialize(thisProcessRunsAsRoot,
- ToolsDaemonTcloReportProgramCompleted,
- NULL);
-
-#if defined(linux) || defined(_WIN32)
- /*
- * Be careful, Impersonate_Init should only be ever called once per process.
- *
- * We can get back here if the tools re-inits due to an error state,
- * such as hibernation.
- */
- if (!inited && thisProcessRunsAsRoot) {
- Impersonate_Init();
- }
-#endif
-
- RpcIn_RegisterCallbackEx(in,
- VIX_BACKDOORCOMMAND_RUN_PROGRAM,
- FoundryToolsDaemonRunProgram,
- eventQueue);
- RpcIn_RegisterCallbackEx(in,
- VIX_BACKDOORCOMMAND_GET_PROPERTIES,
- FoundryToolsDaemonGetToolsProperties,
- confDictRef);
- RpcIn_RegisterCallbackEx(in,
- VIX_BACKDOORCOMMAND_CHECK_USER_ACCOUNT,
- ToolsDaemonTcloCheckUserAccount,
- NULL);
-#if !defined(N_PLAT_NLM)
- RpcIn_RegisterCallbackEx(in,
- VIX_BACKDOORCOMMAND_SEND_HGFS_PACKET,
- ToolsDaemonHgfsImpersonated,
- NULL);
-#endif
- RpcIn_RegisterCallbackEx(in,
- VIX_BACKDOORCOMMAND_COMMAND,
- ToolsDaemonTcloReceiveVixCommand,
- confDictRef);
- RpcIn_RegisterCallbackEx(in,
- VIX_BACKDOORCOMMAND_MOUNT_VOLUME_LIST,
- ToolsDaemonTcloMountHGFS,
- NULL);
-
-#if defined(linux) || defined(_WIN32)
-
- /*
- * Only init once, but always register the RpcIn.
- */
- if (!sync_driver_inited) {
- sync_driver_inited = SyncDriver_Init();
- }
- if (sync_driver_inited) {
- /*
- * These only get registered if SyncDriver_Init succeeds. We do
- * support running the sync/thaw scripts even on guests where
- * the Sync driver is not supported (Linux, Windows older than
- * Win2k) but the running of the scripts is implemented using
- * VIX_BACKDOORCOMMAND_RUN_PROGRAM.
- */
- RpcIn_RegisterCallbackEx(in,
- VIX_BACKDOORCOMMAND_SYNCDRIVER_FREEZE,
- ToolsDaemonTcloSyncDriverFreeze,
- eventQueue);
- RpcIn_RegisterCallbackEx(in,
- VIX_BACKDOORCOMMAND_SYNCDRIVER_THAW,
- ToolsDaemonTcloSyncDriverThaw,
- NULL);
- } else {
- Debug("FoundryToolsDaemon: Failed to init SyncDriver, skipping command handlers.\n");
- }
-#endif
- inited = TRUE;
-} // FoundryToolsDaemon_RegisterRoutines
-
-#endif
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonTcloGetQuotedString --
- *
- * Extract a quoted string from the middle of an argument string.
- * This is different than normal tokenizing in a few ways:
- * * Whitespace is a separator outside quotes, but not inside quotes.
- * * Quotes always come in pairs, so "" is am empty string. An empty
- * string may appear anywhere in the string, even at the end, so
- * a string that is "" contains 1 empty string, not 2.
- * * The string may use whitespace to separate the op-name from the params,
- * and then quoted params to skip whitespace inside a param.
- *
- * Return value:
- * Allocates the string.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-static char *
-ToolsDaemonTcloGetQuotedString(const char *args, // IN
- const char **endOfArg) // OUT
-{
- char *resultStr = NULL;
- char *endStr;
- Debug(">ToolsDaemonTcloGetQuotedString\n");
-
- while ((*args) && ('\"' != *args)) {
- args++;
- }
- if ('\"' == *args) {
- args++;
- }
-
- resultStr = Util_SafeStrdup(args);
-
- endStr = resultStr;
- while (*endStr) {
- if (('\\' == *endStr) && (*(endStr + 1))) {
- endStr += 2;
- } else if ('\"' == *endStr) {
- *endStr = 0;
- endStr++;
- break;
- } else {
- endStr++;
- }
- }
-
- if (NULL != endOfArg) {
- args += (endStr - resultStr);
- while (' ' == *args) {
- args++;
- }
- *endOfArg = args;
- }
-
- Debug("<ToolsDaemonTcloGetQuotedString\n");
- return resultStr;
-} // ToolsDaemonTcloGetQuotedString
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonTcloGetEncodedQuotedString --
- *
- * This is a wrapper for ToolsDaemonTcloGetQuotedString.
- * It just decoded the string.
- *
- * Return value:
- * Allocates the string.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-static char *
-ToolsDaemonTcloGetEncodedQuotedString(const char *args, // IN
- const char **endOfArg) // OUT
-{
- char *rawResultStr = NULL;
- char *resultStr = NULL;
-
- rawResultStr = ToolsDaemonTcloGetQuotedString(args, endOfArg);
- if (NULL == rawResultStr) {
- return(NULL);
- }
-
- resultStr = VixMsg_DecodeString(rawResultStr);
- free(rawResultStr);
-
- return resultStr;
-}
-
-
-#if !defined(VMTOOLS_USE_GLIB)
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonTcloOpenUrl --
- *
- * Open a URL on the guest.
- *
- * Return value:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-ToolsDaemonTcloOpenUrl(RpcInData *data) // IN
-{
- static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
- VixError err = VIX_OK;
- char *url = NULL;
- char *windowState = NULL;
- char *credentialTypeStr = NULL;
- char *obfuscatedNamePassword = NULL;
- uint32 sysError = 0;
- Bool impersonatingVMWareUser = FALSE;
- void *userToken = NULL;
- Debug(">ToolsDaemonTcloOpenUrl\n");
-
- /*
- * Parse the arguments
- */
- url = ToolsDaemonTcloGetEncodedQuotedString(data->args, &data->args);
- windowState = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
- // These parameters at the end are optional, so they may be NULL.
- credentialTypeStr = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
- obfuscatedNamePassword = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
-
- /*
- * Validate the arguments.
- */
- if ((NULL == url) || (NULL == windowState)) {
- err = VIX_E_INVALID_ARG;
- Debug("Failed to get string args\n");
- goto abort;
- }
-
- if ((NULL != credentialTypeStr)
- && (*credentialTypeStr)
- && (thisProcessRunsAsRoot)) {
- impersonatingVMWareUser = VixToolsImpersonateUserImpl(credentialTypeStr,
- VIX_USER_CREDENTIAL_NONE,
- obfuscatedNamePassword,
- &userToken);
- if (!impersonatingVMWareUser) {
- err = VIX_E_GUEST_USER_PERMISSIONS;
- goto abort;
- }
- }
-
- Debug("Opening URL: \"%s\"\n", url);
-
- /* Actually open the URL. */
- if (!GuestApp_OpenUrl(url, strcmp(windowState, "maximize") == 0)) {
- err = VIX_E_FAIL;
- Debug("Failed to open the url \"%s\"\n", url);
- goto abort;
- }
-
-abort:
- if (impersonatingVMWareUser) {
- VixToolsUnimpersonateUser(userToken);
- }
- VixToolsLogoutUser(userToken);
-
- /*
- * All Foundry tools commands return results that start with a
- * foundry error and a guest-OS-specific error.
- */
- Str_Sprintf(resultBuffer, sizeof resultBuffer, "%"FMT64"d %d", err, sysError);
- RPCIN_SETRETVALS(data, resultBuffer, TRUE);
-
- /*
- * These were allocated by ToolsDaemonTcloGetQuotedString.
- */
- free(url);
- free(windowState);
- free(credentialTypeStr);
- free(obfuscatedNamePassword);
-
- Debug("<ToolsDaemonTcloOpenUrl\n");
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonTcloSetPrinter --
- *
- * Set the printer on the guest.
- *
- * Return value:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-ToolsDaemonTcloSetPrinter(RpcInData *data) // IN
-{
- static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
-#if defined(_WIN32)
- VixError err = VIX_OK;
- char *printerName = NULL;
- char *defaultString = NULL;
- int defaultInt;
- DWORD sysError = ERROR_SUCCESS;
- Debug(">ToolsDaemonTcloSetPrinter\n");
-
- /*
- * Parse the arguments
- */
- printerName = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
- defaultString = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
-
- /*
- * Validate the arguments.
- */
- if ((NULL == printerName) || (NULL == defaultString)) {
- err = VIX_E_INVALID_ARG;
- Debug("Failed to get string args\n");
- goto abort;
- }
-
- if (!StrUtil_StrToInt(&defaultInt, defaultString)) {
- err = VIX_E_INVALID_ARG;
- Debug("Failed to convert int arg\n");
- goto abort;
- }
-
- Debug("Setting printer to: \"%s\", %ssetting as default\n",
- printerName, (defaultInt != 0) ? "" : "not ");
-
- /* Actually set the printer. */
- if (!Printer_AddConnection(printerName, &sysError)) {
- err = VIX_E_FAIL;
- Debug("Failed to add printer %s : %d %s\n", printerName, sysError,
- Err_Errno2String(sysError));
- goto abort;
- }
-
- /* Set this printer as the default if requested. */
- if (defaultInt != 0) {
- if (!Win32U_SetDefaultPrinter(printerName)) {
- /*
- * We couldn't set this printer as default. Oh well. We'll
- * still report success or failure based purely on whether
- * the actual printer add succeeded or not.
- */
- Debug("Unable to set \"%s\" as the default printer\n",
- printerName);
- }
- }
-
-abort:
- /*
- * All Foundry tools commands return results that start with a
- * foundry error and a guest-OS-specific error.
- */
- Str_Sprintf(resultBuffer, sizeof resultBuffer, "%"FMT64"d %d", err, sysError);
- RPCIN_SETRETVALS(data, resultBuffer, TRUE);
-
- /*
- * These were allocated by ToolsDaemonTcloGetQuotedString.
- */
- free(printerName);
- free(defaultString);
-
- Debug("<ToolsDaemonTcloSetPrinter\n");
- return TRUE;
-
-#else
- Str_Sprintf(resultBuffer,
- sizeof resultBuffer,
- "%d %d 0",
- VIX_E_OP_NOT_SUPPORTED_ON_GUEST,
- Err_Errno());
- RPCIN_SETRETVALS(data, resultBuffer, TRUE);
- return TRUE;
-#endif
-}
-#endif
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonTcloSyncDriverFreeze --
- *
- * Use the Sync Driver to freeze I/O in the guest..
- *
- * Return value:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-#if defined(linux) || defined(_WIN32)
-Bool
-ToolsDaemonTcloSyncDriverFreeze(RpcInData *data)
-{
- static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
- VixError err = VIX_OK;
- char *driveList = NULL;
- char *timeout = NULL;
- int timeoutVal;
- DECLARE_SYNCDRIVER_ERROR(sysError);
-#if defined(VMTOOLS_USE_GLIB)
- ToolsAppCtx *ctx = data->appCtx;
- GSource *timer;
-#else
- Event *cbEvent;
-#endif
-
- Debug(">ToolsDaemonTcloSyncDriverFreeze\n");
-
- /*
- * Parse the arguments
- */
- driveList = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
- timeout = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
-
- /*
- * Validate the arguments.
- */
- if (NULL == driveList || NULL == timeout) {
- err = VIX_E_INVALID_ARG;
- Debug("ToolsDaemonTcloSyncDriverFreeze: Failed to get string args\n");
- goto abort;
- }
-
- if (!StrUtil_StrToInt(&timeoutVal, timeout) || timeoutVal < 0) {
- Debug("ToolsDaemonTcloSyncDriverFreeze: Bad args, timeout '%s'\n", timeout);
- err = VIX_E_INVALID_ARG;
- goto abort;
- }
-
- Debug("SYNCDRIVE: Got request to freeze '%s', timeout %d\n", driveList,
- timeoutVal);
-
- /* Disallow multiple freeze calls. */
- if (gSyncDriverHandle != SYNCDRIVER_INVALID_HANDLE) {
- err = VIX_E_OBJECT_IS_BUSY;
- goto abort;
- }
-
- /* Perform the actual freeze. */
- if (!SyncDriver_Freeze(driveList, &gSyncDriverHandle) ||
- SyncDriver_QueryStatus(gSyncDriverHandle, INFINITE) != SYNCDRIVER_IDLE) {
- Debug("ToolsDaemonTcloSyncDriverFreeze: Failed to Freeze drives '%s'\n",
- driveList);
- err = VIX_E_FAIL;
- sysError = SYNCDRIVERERROR;
- if (gSyncDriverHandle != SYNCDRIVER_INVALID_HANDLE) {
- SyncDriver_Thaw(gSyncDriverHandle);
- SyncDriver_CloseHandle(&gSyncDriverHandle);
- }
- goto abort;
- }
-
- /* Start the timer callback to automatically thaw. */
- if (0 != timeoutVal) {
- Debug("ToolsDaemonTcloSyncDriverFreeze: Starting timer callback %d\n", timeoutVal);
-#if defined(VMTOOLS_USE_GLIB)
- timer = g_timeout_source_new(timeoutVal * 10);
- VMTOOLSAPP_ATTACH_SOURCE(ctx, timer, ToolsDaemonSyncDriverThawCallback, NULL, NULL);
- g_source_unref(timer);
-#else
- cbEvent = EventManager_Add(data->clientData,
- timeoutVal,
- ToolsDaemonSyncDriverThawCallback,
- NULL);
- if (!cbEvent) {
- Debug("ToolsDaemonTcloSyncDriverFreeze: Failed to start callback, aborting\n");
- if (!SyncDriver_Thaw(gSyncDriverHandle)) {
- Debug("ToolsDaemonTcloSyncDriverFreeze: Unable to abort freeze. Oh well.\n");
- }
- SyncDriver_CloseHandle(&gSyncDriverHandle);
- err = VIX_E_FAIL;
- sysError = SYNCDRIVERERROR;
- goto abort;
- }
-#endif
- }
-
-abort:
- /*
- * These were allocated by ToolsDaemonTcloGetQuotedString.
- */
- free(driveList);
- free(timeout);
-
- /*
- * All Foundry tools commands return results that start with a
- * foundry error and a guest-OS-specific error.
- */
- Str_Sprintf(resultBuffer, sizeof resultBuffer, "%"FMT64"d %d", err, sysError);
- Debug("<ToolsDaemonTcloSyncDriverFreeze\n");
- return RPCIN_SETRETVALS(data, resultBuffer, TRUE);
-}
-#endif
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonSyncDriverThawCallback --
- *
- * Callback to thaw all currently frozen drives if they have not been
- * thawed already.
- *
- * Results:
- * TRUE (returning FALSE will stop the event loop)
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-#if defined(linux) || defined(_WIN32)
-static Bool
-ToolsDaemonSyncDriverThawCallback(void *clientData) // IN (ignored)
-{
- Debug(">ToolsDaemonSyncDriverThawCallback\n");
- Debug("ToolsDaemonSyncDriverThawCallback: Timed out waiting for thaw.\n");
-
- /* Don't bother calling freeze if no drives are frozen. */
- if (gSyncDriverHandle == SYNCDRIVER_INVALID_HANDLE ||
- !SyncDriver_DrivesAreFrozen()) {
- Debug("<ToolsDaemonSyncDriverThawCallback\n");
- Debug("ToolsDaemonSyncDriverThawCallback: No drives are frozen.\n");
- goto exit;
- }
-
- if (!SyncDriver_Thaw(gSyncDriverHandle)) {
- Debug("ToolsDaemonSyncDriverThawCallback: Failed to thaw.\n");
- }
-
-exit:
- SyncDriver_CloseHandle(&gSyncDriverHandle);
- Debug("<ToolsDaemonSyncDriverThawCallback\n");
- return TRUE;
-}
-#endif
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonTcloSyncDriverThaw --
- *
- * Thaw I/O previously frozen by the Sync Driver.
- *
- * Return value:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-#if defined(linux) || defined(_WIN32)
-Bool
-ToolsDaemonTcloSyncDriverThaw(RpcInData *data) // IN
-{
- static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
- VixError err = VIX_OK;
- DECLARE_SYNCDRIVER_ERROR(sysError);
- Debug(">ToolsDaemonTcloSyncDriverThaw\n");
-
- /*
- * This function has no arguments that we care about.
- */
-
- Debug("SYNCDRIVE: Got request to thaw\n");
-
- if (gSyncDriverHandle == SYNCDRIVER_INVALID_HANDLE ||
- !SyncDriver_DrivesAreFrozen()) {
- err = VIX_E_GUEST_VOLUMES_NOT_FROZEN;
- sysError = SYNCDRIVERERROR;
- Debug("ToolsDaemonTcloSyncDriverThaw: No drives are frozen.\n");
- } else if (!SyncDriver_Thaw(gSyncDriverHandle)) {
- err = VIX_E_FAIL;
- sysError = SYNCDRIVERERROR;
- Debug("ToolsDaemonTcloSyncDriverThaw: Failed to Thaw drives\n");
- }
-
- SyncDriver_CloseHandle(&gSyncDriverHandle);
-
- /*
- * All Foundry tools commands return results that start with a
- * foundry error and a guest-OS-specific error.
- */
- Str_Sprintf(resultBuffer, sizeof resultBuffer, "%"FMT64"d %d", err, sysError);
- Debug("<ToolsDaemonTcloSyncDriverThaw\n");
- return RPCIN_SETRETVALS(data, resultBuffer, TRUE);
-}
-#endif
-
-#if !defined(VMTOOLS_USE_GLIB)
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FoundryToolsDaemon_RegisterOpenUrlCapability --
- *
- * Register the OpenUrl capability. Sometimes this needs to
- * be done separately from the TCLO callback registration, so we
- * provide it separately here.
- *
- * Results:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-FoundryToolsDaemon_RegisterOpenUrlCapability(void)
-{
- if (!RpcOut_sendOne(NULL, NULL, "tools.capability.open_url 1")) {
- Debug("Unable to register open url capability\n");
- Debug("<FoundryToolsDaemon_RegisterOpenUrlCapability");
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FoundryToolsDaemon_RegisterOpenUrl --
- *
- * Register the OpenUrl capability and TCLO handler.
- *
- * Results:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-FoundryToolsDaemon_RegisterOpenUrl(RpcIn *in) // IN
-{
- /* Register the TCLO handler. */
- RpcIn_RegisterCallbackEx(in,
- VIX_BACKDOORCOMMAND_OPEN_URL,
- ToolsDaemonTcloOpenUrl,
- NULL);
- /*
- * Inform the VMX that we support opening urls in the guest; the UI
- * and VMX need to know about this capability in advance (rather than
- * simply trying and failing). I've put this here on the theory that
- * it's better to have it close to the command that handles the
- * actual request than it is to have it near the other capabilities
- * registration code, which is in toolsDaemon.c.
- *
- * Eventually, Foundry might want to have a unified way of
- * registering support for only a subset of the foundry commands in
- * the guest.
- */
- if (!FoundryToolsDaemon_RegisterOpenUrlCapability()) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FoundryToolsDaemon_UnregisterOpenUrl --
- *
- * Unregister the "OpenUrl" capability.
- *
- * Results:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-FoundryToolsDaemon_UnregisterOpenUrl(void)
-{
- /*
- * RpcIn doesn't have an unregister facility, so all we need to do
- * here is unregister the capability.
- */
-
- /*
- * Report no longer supporting open url;
- */
- if (!RpcOut_sendOne(NULL, NULL, "tools.capability.open_url 0")) {
- Debug("<FoundryToolsDaemon_UnregisterOpenUrl\n");
- Debug("Unable to unregister OpenUrl capability\n");
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FoundryToolsDaemon_RegisterSetPrinterCapability --
- *
- * Register the Set Printer capability. Sometimes this needs to
- * be done separately from the TCLO callback registration, so we
- * provide it separately here.
- *
- * Results:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-FoundryToolsDaemon_RegisterSetPrinterCapability(void)
-{
- if (!RpcOut_sendOne(NULL, NULL, "tools.capability.printer_set 1")) {
- Debug("Unable to register printer set capability\n");
- Debug("<FoundryToolsDaemon_RegisterSetPrinterCapability\n");
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FoundryToolsDaemon_RegisterSetPrinter --
- *
- * Register the Set Printer capability and TCLO handler.
- *
- * Results:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-FoundryToolsDaemon_RegisterSetPrinter(RpcIn *in) // IN
-{
- /* First, try to load the printer library. */
- if (!Printer_Init()) {
- Debug("<FoundryToolsDaemon_RegisterSetPrinter\n");
- Debug("Unable to load printer library.\n");
- return FALSE;
- }
-
- /* Register the TCLO handler. */
- RpcIn_RegisterCallbackEx(in,
- VIX_BACKDOORCOMMAND_SET_GUEST_PRINTER,
- ToolsDaemonTcloSetPrinter,
- NULL);
- /*
- * Inform the VMX that we support setting the guest printer; the UI
- * and VMX need to know about this capability in advance (rather than
- * simply trying and failing). I've put this here on the theory that
- * it's better to have it close to the command that handles the
- * actual request than it is to have it near the other capabilities
- * registration code, which is in toolsDaemon.c.
- *
- * Eventually, Foundry might want to have a unified way of
- * registering support for only a subset of the foundry commands in
- * the guest.
- */
- if (!FoundryToolsDaemon_RegisterSetPrinterCapability()) {
- Debug("<FoundryToolsDaemon_RegisterSetPrinter\n");
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FoundryToolsDaemon_UnregisterSetPrinter --
- *
- * Unregister the "Set Printer" capability.
- *
- * Results:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-FoundryToolsDaemon_UnregisterSetPrinter(RpcIn *in) // IN
-{
- /*
- * RpcIn doesn't have an unregister facility, so all we need to do
- * here is unregister the capability.
- */
-
- /*
- * Report no longer supporting setting the guest printer.
- */
- if (!RpcOut_sendOne(NULL, NULL, "tools.capability.printer_set 0")) {
- Debug("<FoundryToolsDaemon_UnregisterSetPrinter\n");
- Debug("Unable to unregister printer set capability\n");
- return FALSE;
- }
-
- /* Cleanup the printer library. */
- if (!Printer_Cleanup()) {
- /*
- * Failed to cleanup, but we still unregistered the command so
- * we'll just warn and pretend we succeeded.
- */
- Debug("Unable to cleanup printer library\n");
- }
-
- return TRUE;
-}
-
-#endif
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonTcloMountHGFS --
- *
- *
- * Return value:
- * VixError
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-ToolsDaemonTcloMountHGFS(RpcInData *data) // IN
-{
- VixError err = VIX_OK;
- static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
-
-#if defined(linux)
- /*
- * Look for a vmhgfs mount at /mnt/hgfs. If one exists, nothing
- * else needs to be done. If one doesn't exist, then mount at
- * that location.
- */
- FILE *mtab;
- struct mntent *mnt;
- Bool vmhgfsMntFound = FALSE;
- if ((mtab = setmntent(_PATH_MOUNTED, "r")) == NULL) {
- err = VIX_E_FAIL;
- } else {
- while ((mnt = getmntent(mtab)) != NULL) {
- if ((strcmp(mnt->mnt_fsname, ".host:/") == 0) &&
- (strcmp(mnt->mnt_type, HGFS_NAME) == 0) &&
- (strcmp(mnt->mnt_dir, "/mnt/hgfs") == 0)) {
- vmhgfsMntFound = TRUE;
- break;
- }
- }
- endmntent(mtab);
- }
-
- if (vmhgfsMntFound) {
- /*
- * We need to call the mount program, not the mount system call. The
- * mount program does several additional things, like compute the mount
- * options from the contents of /etc/fstab, and invoke custom mount
- * programs like the one needed for HGFS.
- */
- int ret = system("mount -t vmhgfs .host:/ /mnt/hgfs");
- if (ret == -1 || WIFSIGNALED(ret) ||
- (WIFEXITED(ret) && WEXITSTATUS(ret) != 0)) {
- err = VIX_E_FAIL;
- }
- }
-#endif
-
- /*
- * All tools commands return results that start with an error
- * and a guest-OS-specific error.
- */
- Str_Sprintf(resultBuffer,
- sizeof(resultBuffer),
- "%"FMT64"d %d",
- err,
- Err_Errno());
- RPCIN_SETRETVALS(data, resultBuffer, TRUE);
-
- return TRUE;
-} // ToolsDaemonTcloMountHGFS
-
-
-#if !defined(N_PLAT_NLM)
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonHgfsImpersonated --
- *
- * Tclo cmd handler for hgfs requests.
- *
- * Here we receive guest user credentials and an HGFS packet to
- * be processed by the HGFS server under the context of
- * the guest user credentials.
- *
- * We pre-allocate a HGFS reply packet buffer and leave some space at
- * the beginning of the buffer for foundry error codes.
- * The format of the foundry error codes is a 64 bit number (as text),
- * followed by a 32 bit number (as text), followed by a hash,
- * all delimited by space (' '). The hash is needed
- * to make it easier for text parsers to know where the
- * HGFS reply packet begins, since it can start with a space.
- *
- * We do this funky "allocate an HGFS packet with extra
- * room for foundry error codes" to avoid copying buffers
- * around. The HGFS packet buffer is roughly 62k for large V3 Hgfs request
- * or 6k for other request , so it would be bad to copy that for every packet.
- *
- * It is guaranteed that we will not be called twice
- * at the same time, so it is safe for resultPacket to be static.
- * The TCLO processing loop (RpcInLoop()) is synchronous.
- *
- *
- * Results:
- * TRUE on TCLO success (*result contains the hgfs reply)
- * FALSE on TCLO error (not supposed to happen)
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-ToolsDaemonHgfsImpersonated(RpcInData *data) // IN
-{
- VixError err;
- size_t hgfsPacketSize = 0;
- const char *origArgs = data->args;
- Bool impersonatingVMWareUser = FALSE;
- char *credentialTypeStr = NULL;
- char *obfuscatedNamePassword = NULL;
- void *userToken = NULL;
- int actualUsed;
-#define STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING 20
-#define OTHER_TEXT_SIZE 4 /* strlen(space zero space quote) */
- static char resultPacket[STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
- + OTHER_TEXT_SIZE
- + HGFS_LARGE_PACKET_MAX];
- char *hgfsReplyPacket = resultPacket
- + STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
- + OTHER_TEXT_SIZE;
-
- Debug(">ToolsDaemonHgfsImpersonated\n");
-
- err = VIX_OK;
-
- /*
- * We assume VixError is 64 bits. If it changes, we need
- * to adjust STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING.
- *
- * There isn't much point trying to return gracefully
- * if sizeof(VixError) is larger than we expected: we didn't
- * allocate enough space to actually represent the error!
- * So we're stuck. Panic at this point.
- */
- ASSERT_ON_COMPILE(sizeof (uint64) == sizeof err);
-
- /*
- * Get the authentication information.
- */
- credentialTypeStr = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
- obfuscatedNamePassword = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
-
- /*
- * Make sure we are passed the correct arguments.
- */
- if ((NULL == credentialTypeStr) || (NULL == obfuscatedNamePassword)) {
- err = VIX_E_INVALID_ARG;
- goto abort;
- }
-
- /*
- * Skip over our token that is right before the HGFS packet.
- * This makes ToolsDaemonTcloGetQuotedString parsing predictable,
- * since it will try to eat trailing spaces after a quoted string,
- * and the HGFS packet might begin with a space.
- */
- if (((data->args - origArgs) >= data->argsSize) || ('#' != *(data->args))) {
- /*
- * Buffer too small or we got an unexpected token.
- */
- err = VIX_E_FAIL;
- goto abort;
- }
- data->args++;
-
- /*
- * At this point args points to the HGFS packet.
- * If we're pointing beyond the end of the buffer, we'll
- * get a negative HGFS packet length and abort.
- */
- hgfsPacketSize = data->argsSize - (data->args - origArgs);
- if (hgfsPacketSize <= 0) {
- err = VIX_E_FAIL;
- goto abort;
- }
-
- if (thisProcessRunsAsRoot) {
- impersonatingVMWareUser = VixToolsImpersonateUserImpl(credentialTypeStr,
- VIX_USER_CREDENTIAL_NONE,
- obfuscatedNamePassword,
- &userToken);
- if (!impersonatingVMWareUser) {
- err = VIX_E_GUEST_USER_PERMISSIONS;
- hgfsPacketSize = 0;
- goto abort;
- }
- }
-
- /*
- * Impersonation was okay, so let's give our packet to
- * the HGFS server and forward the reply packet back.
- */
- HgfsServer_DispatchPacket(data->args, // packet in buf
- hgfsReplyPacket, // packet out buf
- &hgfsPacketSize); // in/out size
-
-abort:
- if (impersonatingVMWareUser) {
- VixToolsUnimpersonateUser(userToken);
- }
- VixToolsLogoutUser(userToken);
-
- /*
- * These were allocated by ToolsDaemonTcloGetQuotedString.
- */
- free(credentialTypeStr);
- free(obfuscatedNamePassword);
-
- data->result = resultPacket;
- data->resultLen = STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
- + OTHER_TEXT_SIZE
- + hgfsPacketSize;
-
- /*
- * Render the foundry error codes into the buffer.
- */
- actualUsed = Str_Snprintf(resultPacket,
- STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
- + OTHER_TEXT_SIZE,
- "%"FMT64"d 0 ",
- err);
-
- if (actualUsed < 0) {
- /*
- * We computed our string length wrong! This should never happen.
- * But if it does, let's try to recover gracefully. The "1" in
- * the string below is VIX_E_FAIL. We don't try to use %d since
- * we couldn't even do that right the first time around.
- * That hash is needed for the parser on the other
- * end to stop before the HGFS packet, since the HGFS packet
- * can contain a space (and the parser can eat trailing spaces).
- */
- ASSERT(0);
- actualUsed = Str_Snprintf(resultPacket,
- STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING,
- "1 0 #");
- data->resultLen = actualUsed;
- } else {
- /*
- * We computed the string length correctly. Great!
- *
- * We allocated enough space to cover a large 64 bit number
- * for VixError. Chances are we didn't use all that space.
- * Instead, pad it with whitespace so the text parser can skip
- * over it.
- */
- memset(resultPacket + actualUsed,
- ' ',
- STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
- + OTHER_TEXT_SIZE
- - actualUsed);
- /*
- * Put a hash right before the HGFS packet.
- * So the buffer will look something like this:
- * "0 0 #" followed by the HGFS packet.
- */
- resultPacket[STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
- + OTHER_TEXT_SIZE - 1] = '#';
- }
-
- Debug("<<<ToolsDaemonHgfsImpersonated\n");
- return TRUE;
-} // ToolsDaemonHgfsImpersonated
-
-#undef STRLEN_OF_MAX_64_BIT_NUMBER_AS_STRING
-#undef OTHER_TEXT_SIZE
-#endif
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonTcloReportProgramCompleted --
- *
- *
- * Return value:
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-ToolsDaemonTcloReportProgramCompleted(const char *requestName, // IN
- VixError err, // IN
- int exitCode, // IN
- int64 pid, // IN
- void *clientData) // IN
-{
- Bool sentResult;
-
-#if defined(VMTOOLS_USE_GLIB)
- ToolsAppCtx *ctx = clientData;
- gchar *msg = g_strdup_printf("%s %s %"FMT64"d %d %d %"FMT64"d",
- VIX_BACKDOORCOMMAND_RUN_PROGRAM_DONE,
- requestName,
- err,
- Err_Errno(),
- exitCode,
- (int64) pid);
- sentResult = RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL);
- g_free(msg);
-#else
- sentResult = RpcOut_sendOne(NULL,
- NULL,
- "%s %s %"FMT64"d %d %d %"FMT64"d",
- VIX_BACKDOORCOMMAND_RUN_PROGRAM_DONE,
- requestName,
- err,
- Err_Errno(),
- exitCode,
- (int64) pid);
-#endif
-
- if (!sentResult) {
- Warning("Unable to send results from polling the result program.\n\n");
- }
-} // ToolsDaemonTcloReportProgramCompleted
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsDaemonTcloReceiveVixCommand --
- *
- *
- * Return value:
- * TRUE on success
- * FALSE on failure
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-ToolsDaemonTcloReceiveVixCommand(RpcInData *data) // IN
-{
- VixError err = VIX_OK;
- char *requestName = NULL;
- VixCommandRequestHeader *requestMsg = NULL;
- size_t maxResultBufferSize;
- size_t tcloBufferLen;
- char *resultValue = NULL;
- size_t resultValueLength = 0;
- Bool deleteResultValue = FALSE;
- char *destPtr = NULL;
- int vixPrefixDataSize = (MAX64_DECIMAL_DIGITS * 2)
- + (sizeof(' ') * 2)
- + sizeof('\0');
-
- /*
- * Our temporary buffer will be the same size as what the
- * Tclo/RPC system can handle, which is GUESTMSG_MAX_IN_SIZE.
- */
- static char tcloBuffer[GUESTMSG_MAX_IN_SIZE];
-
-#if defined(VMTOOLS_USE_GLIB)
- ToolsAppCtx *ctx = data->appCtx;
- GMainLoop *eventQueue = ctx->mainLoop;
- GKeyFile *confDictRef = ctx->config;
-#else
- DblLnkLst_Links *eventQueue = globalEventQueue;
- GuestApp_Dict **confDictRef = data->clientData;
-#endif
-
- requestName = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
-
- /*
- * Skip the NULL, char, and then the rest of the buffer should just
- * be a Vix command object.
- */
- while (*data->args) {
- data->args += 1;
- }
- data->args += 1;
- err = VixMsg_ValidateMessage((char *) data->args, data->argsSize);
- if (VIX_OK != err) {
- goto abort;
- }
- requestMsg = (VixCommandRequestHeader *) data->args;
- maxResultBufferSize = sizeof(tcloBuffer) - vixPrefixDataSize;
-
- err = VixTools_ProcessVixCommand(requestMsg,
- requestName,
- maxResultBufferSize,
- confDictRef,
- eventQueue,
- &resultValue,
- &resultValueLength,
- &deleteResultValue);
-
-
-abort:
- tcloBufferLen = resultValueLength + vixPrefixDataSize;
-
- /*
- * If we generated a message larger than tclo/Rpc can handle,
- * we did something wrong. Our code should never have done this.
- */
- if (tcloBufferLen > sizeof tcloBuffer) {
- ASSERT(0);
- resultValue[0] = 0;
- tcloBufferLen = tcloBufferLen - resultValueLength;
- err = VIX_E_OUT_OF_MEMORY;
- }
-
- /*
- * This should never happen since tcloBuffer is pretty huge.
- * But, there is no harm in being paranoid and I don't want to
- * find out the buffer is too small when we are halfway through
- * formatting the response.
- */
- if ((32 + resultValueLength + 32) >= sizeof(tcloBuffer)) {
- err = VIX_E_OUT_OF_MEMORY;
- resultValueLength = 0;
- }
-
-
- /*
- * All Foundry tools commands return results that start with a foundry error
- * and a guest-OS-specific error.
- */
- Str_Sprintf(tcloBuffer,
- sizeof tcloBuffer,
- "%"FMT64"d %d ",
- err,
- Err_Errno());
- destPtr = tcloBuffer + strlen(tcloBuffer);
-
- /*
- * If this is a binary result, then we put a # at the end of the ascii to
- * mark the end of ascii and the start of the binary data.
- */
- if ((NULL != requestMsg)
- && (requestMsg->commonHeader.commonFlags & VIX_COMMAND_GUEST_RETURNS_BINARY)) {
- *(destPtr++) = '#';
- data->resultLen = destPtr - tcloBuffer + sizeof '#' + resultValueLength;
- }
-
- /*
- * Copy the result. Don't use a strcpy, since this may be a binary buffer.
- */
- memcpy(destPtr, resultValue, resultValueLength);
- destPtr += resultValueLength;
-
- /*
- * If this is not binary data, then it should be a NULL terminated string.
- */
- if ((NULL == requestMsg)
- || !(requestMsg->commonHeader.commonFlags & VIX_COMMAND_GUEST_RETURNS_BINARY)) {
- *(destPtr++) = 0;
- data->resultLen = strlen(tcloBuffer) + 1;
- }
-
- data->result = tcloBuffer;
-
- if (deleteResultValue) {
- free(resultValue);
- }
- free(requestName);
-
- Debug("<ToolsDaemonTcloReceiveVixCommand\n");
- return TRUE;
-} // ToolsDaemonTcloReceiveVixCommand
-
+++ /dev/null
-/*********************************************************
- * Copyright (C) 1998 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-
-/*
- * foundryToolsDaemon.h --
- *
- * Foundry related Tools functionality.
- *
- */
-
-
-#ifndef __VIX_TOOLS_DAEMON_H__
-# define __VIX_TOOLS_DAEMON_H__
-
-
-#if defined(VMTOOLS_USE_GLIB)
-
-#include "vmtoolsApp.h"
-
-void
-FoundryToolsDaemon_Initialize(ToolsAppCtx *ctx);
-
-#else /* not vix plugin */
-
-#include "vm_basic_types.h"
-#include "rpcin.h"
-#include "guestApp.h"
-
-void FoundryToolsDaemon_RegisterRoutines(RpcIn *in,
- GuestApp_Dict **confDictRef,
- DblLnkLst_Links *eventQueue,
- Bool runAsRoot);
-/* There isn't an _UnregisterRoutines yet. */
-
-Bool FoundryToolsDaemon_RegisterSetPrinter(RpcIn *in);
-Bool FoundryToolsDaemon_RegisterSetPrinterCapability(void);
-Bool FoundryToolsDaemon_UnregisterSetPrinter(RpcIn *in);
-
-Bool FoundryToolsDaemon_RegisterOpenUrl(RpcIn *in);
-Bool FoundryToolsDaemon_RegisterOpenUrlCapability(void);
-Bool FoundryToolsDaemon_UnregisterOpenUrl(void);
-
-#endif
-
-#endif /* __VIX_TOOLS_DAEMON_H__ */
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * string.cc --
+ *
+ * A string wrapper for bora/lib/unicode. This class is intended to provide
+ * more c++ features such as operator overloading, automatic string conversion
+ * between different types of string classes.
+ */
+
+
+#include <sstream>
+#include <iostream>
+
+#include "string.hh"
+#include "unicode.h"
+#include "util.h"
+
+namespace utf {
+
+/* Initialize static scope variables */
+const string::size_type string::npos = Glib::ustring::npos;
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::string --
+ *
+ * Constructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::string()
+ : mUstr(),
+ mUtf16Cache(NULL)
+{
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::string --
+ *
+ * Constructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::string(ConstUnicode s) // IN
+ : mUstr(),
+ mUtf16Cache(NULL)
+{
+ ASSERT(s);
+ mUstr = Unicode_GetUTF8(s);
+ ASSERT(Validate(mUstr));
+}
+
+
+#ifdef _WIN32
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::string --
+ *
+ * Constructor from a ubstr_t object. Copies the UTF-16 representation of
+ * the ubstr_t.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Makes a copy of the ubstr_t data and frees that data when the
+ * utf::string is destroyed.
+ *
+ * Note:
+ * WIN32 only call
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::string(const ubstr_t &s) // IN
+ : mUstr(),
+ mUtf16Cache(NULL)
+{
+ // If the input is empty, then there's nothing to do.
+ if (s.length() == 0) {
+ return;
+ }
+
+ mUstr = Glib::ustring(static_cast<const char *>(s));
+ ASSERT(Validate(mUstr));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::string --
+ *
+ * Constructor from a _bstr_t object. Copies the UTF-16 representation of
+ * the _bstr_t. Needed for dealing with _com_error::Description().
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Makes a copy of the _bstr_t data and frees that data when
+ * the utf::string is destroyed.
+ *
+ * Note:
+ * WIN32 only call
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::string(const _bstr_t &s) // IN
+ : mUstr(),
+ mUtf16Cache(NULL)
+{
+ // If the input is empty, then there's nothing to do.
+ if (s.length() == 0) {
+ return;
+ }
+
+ Unicode utf8 = Unicode_AllocWithUTF16(static_cast<const utf16_t *>(s));
+
+ try {
+ mUstr = Glib::ustring(utf8);
+ Unicode_Free(utf8);
+ } catch (...) {
+ Unicode_Free(utf8);
+ throw;
+ }
+
+ ASSERT(Validate(mUstr));
+}
+
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::string --
+ *
+ * Constructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::string(const utf16string &s) // IN
+ : mUstr(),
+ mUtf16Cache(NULL)
+{
+ // If the input is empty, then there's nothing to do.
+ if (s.empty()) {
+ return;
+ }
+
+ string copy(s.c_str());
+ swap(copy);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::string --
+ *
+ * Constructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::string(const utf16_t *s) // IN
+ : mUstr(),
+ mUtf16Cache(NULL)
+{
+ ASSERT(s != NULL);
+
+ /*
+ * Since we already have a UTF-16 representation of the string, copy it
+ * now.
+ */
+ mUtf16Cache = Unicode_UTF16Strdup(s);
+
+ Unicode utf8 = Unicode_AllocWithUTF16(s);
+
+ try {
+ mUstr = Glib::ustring(utf8);
+ Unicode_Free(utf8);
+ } catch (...) {
+ Unicode_Free(utf8);
+ throw;
+ }
+
+ ASSERT(Validate(mUstr));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::string --
+ *
+ * Constructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::string(const char *s, // IN
+ StringEncoding encoding) // IN
+ : mUstr(),
+ mUtf16Cache(NULL)
+{
+ ASSERT(s != NULL);
+
+ Unicode utf8 = Unicode_Alloc(s, encoding);
+
+ try {
+ mUstr = Glib::ustring(utf8);
+ Unicode_Free(utf8);
+ } catch (...) {
+ Unicode_Free(utf8);
+ throw;
+ }
+
+ ASSERT(Validate(mUstr));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::string --
+ *
+ * Constructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::string(const Glib::ustring &s) // IN
+ : mUstr(s),
+ mUtf16Cache(NULL)
+{
+ ASSERT(Validate(s));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::string --
+ *
+ * Copy constructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::string(const string &s) // IN
+ : mUstr(s.mUstr),
+ mUtf16Cache(NULL)
+{
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::~string --
+ *
+ * Destructor.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::~string()
+{
+ InvalidateCache();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator Glib::ustring --
+ *
+ * Implicit conversion to Glib::ustring operator
+ *
+ * Results:
+ * The internal Glib::ustring object.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::operator const Glib::ustring& ()
+ const
+{
+ return ustr();
+}
+
+
+#ifdef _WIN32
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator ubstr_t --
+ *
+ * Implicit conversion to ubstr_t
+ *
+ * Results:
+ * The current ubstr_t string. NUL-terminated.
+ *
+ * Side effects:
+ * None
+ *
+ * Note:
+ * This function is only defined in _WIN32
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::operator const ubstr_t()
+ const
+{
+ return ubstr_t(GetUtf16Cache());
+}
+
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator= --
+ *
+ * Assignment operator.
+ *
+ * Results:
+ * A reference to this string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string&
+string::operator=(const string &s) // IN
+{
+ return assign(s);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator+= --
+ *
+ * Append operator of the utf::string class.
+ *
+ * Results:
+ * A reference to this string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string&
+string::operator+=(const string &s) // IN
+{
+ return append(s);
+}
+
+
+string&
+string::operator+=(value_type uc) // IN
+{
+ push_back(uc);
+ return *this;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::swap --
+ *
+ * Swaps the contents with a given utf::string.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+string::swap(string &s) // IN/OUT
+{
+ mUstr.swap(s.mUstr);
+ std::swap(mUtf16Cache, s.mUtf16Cache);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::resize --
+ *
+ * Change the size of this utf::string.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+string::resize(size_type n, // IN
+ value_type c) // IN/OPT
+{
+ InvalidateCache();
+ mUstr.resize(n, c);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::c_str --
+ *
+ * Get the UTF-8 representation of this string.
+ *
+ * Results:
+ * The current string with UTF-8 encoding. NUL-terminated.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+const char *
+string::c_str()
+ const
+{
+ return mUstr.c_str();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::w_str --
+ *
+ * Get the UTF-16 representation of this string.
+ *
+ * Results:
+ * The current string with UTF-16 (host-endian) encoding. NUL-terminated.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+const utf16_t *
+string::w_str()
+ const
+{
+ return GetUtf16Cache();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::ustr --
+ *
+ * Get the Glib::ustring backing of this string.
+ *
+ * Results:
+ * The internal Glib::ustring object.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+const Glib::ustring&
+string::ustr()
+ const
+{
+ return mUstr;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::empty --
+ *
+ * Test if this is an empty string.
+ *
+ * Results:
+ * true if it's an empty string, otherwise false.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+string::empty()
+ const
+{
+ return mUstr.empty();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::size --
+ *
+ * Results:
+ * Returns the length of this string, in characters (code points),
+ * excluding NUL.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::size()
+ const
+{
+ return mUstr.size();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::length --
+ *
+ * Results:
+ * Returns the length of this string, in characters (code points),
+ * excluding NUL. (Same as size().)
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::length()
+ const
+{
+ return size();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::bytes --
+ *
+ * Results:
+ * Returns the number of bytes used by the UTF-8 representation of this
+ * string, excluding NUL.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::bytes()
+ const
+{
+ return mUstr.bytes();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::foldCase --
+ *
+ * Returns the case-folded string of this string.
+ *
+ * Results:
+ * The newly created string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+string::foldCase()
+ const
+{
+ return string(mUstr.casefold());
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::trim --
+ *
+ * Returns the whitespace-trimmed version of this string.
+ *
+ * Results:
+ * The newly created string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+string::trim()
+ const
+{
+ Unicode trim = Unicode_Trim(c_str());
+ string result(trim);
+ Unicode_Free(trim);
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::trimLeft --
+ *
+ * Get the left-trimmed version of this string.
+ *
+ * Results:
+ * The newly created string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+string::trimLeft()
+ const
+{
+ Unicode trim = Unicode_TrimLeft(c_str());
+ string result(trim);
+ Unicode_Free(trim);
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::trimRight --
+ *
+ * Get the right-trimmed version of this string.
+ *
+ * Results:
+ * The newly created string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+string::trimRight()
+ const
+{
+ Unicode trim = Unicode_TrimRight(c_str());
+ string result(trim);
+ Unicode_Free(trim);
+ return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::normalize --
+ *
+ * Creates a new string by normalizing the input string.
+ *
+ * Results:
+ * The newly created string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+string::normalize(NormalizeMode mode) // IN
+ const
+{
+ return mUstr.normalize((Glib::NormalizeMode)mode);
+}
+
+
+#ifdef SUPPORT_UNICODE
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::toLower --
+ *
+ * Creates a new string by lower-casing the input string using
+ * the rules of the specified locale.
+ *
+ * Results:
+ * The newly created string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+string::toLower(const char *locale) // IN
+ const
+{
+ Unicode lower = Unicode_ToLower(c_str(), locale);
+ string results(lower);
+ Unicode_Free(lower);
+
+ return results;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::toUpper --
+ *
+ * Creates a new string by upper-casing the input string using
+ * the rules of the specified locale.
+ *
+ * Results:
+ * The newly created string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+string::toUpper(const char *locale) // IN
+ const
+{
+ Unicode upper = Unicode_ToUpper(c_str(), locale);
+ string results(upper);
+ Unicode_Free(upper);
+
+ return results;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::toTitle --
+ *
+ * Creates a new string by title-casing the input string using
+ * the rules of the specified locale.
+ *
+ * Results:
+ * The newly created string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+string::toTitle(const char *locale) // IN
+ const
+{
+ Unicode title = Unicode_ToTitle(c_str(), locale);
+ string results(title);
+ Unicode_Free(title);
+
+ return results;
+}
+
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::append --
+ *
+ * Appends the argument string to this utf::string.
+ *
+ * Results:
+ * A reference to this object.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string&
+string::append(const string &s) // IN
+{
+ InvalidateCache();
+ mUstr.append(s.mUstr);
+
+ return *this;
+}
+
+
+string&
+string::append(const string &s, // IN
+ size_type i, // IN
+ size_type n) // IN
+{
+ InvalidateCache();
+ mUstr.append(s.mUstr, i, n);
+
+ return *this;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::push_back --
+ *
+ * Appends the character at the end of this string.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+string::push_back(value_type uc) // IN
+{
+ InvalidateCache();
+ mUstr.push_back(uc);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::assign --
+ *
+ * Assigns the passed in string to this string.
+ *
+ * Results:
+ * A reference to this object
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string&
+string::assign(const string &s) // IN
+{
+ string copy(s);
+ swap(copy);
+ return *this;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::insert --
+ *
+ * Inserts the argument string to this string at index i, return this
+ * string.
+ *
+ * These are passthrough calls to the Glib::insert calls.
+ *
+ * Results:
+ * A reference to this object
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string&
+string::insert(size_type i, // IN
+ const string &s) // IN
+{
+ InvalidateCache();
+ mUstr.insert(i, s.mUstr);
+ return *this;
+}
+
+
+string&
+string::insert(size_type i, // IN
+ size_type n, // IN
+ value_type uc)
+{
+ InvalidateCache();
+ mUstr.insert(i, n, uc);
+ return *this;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::clear --
+ *
+ * Clears this string.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+string::clear()
+{
+ InvalidateCache();
+ mUstr.clear();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::zero_clear --
+ *
+ * Zeroes and clears this string.
+ *
+ * XXX: This is temporary until we have a separate string class for
+ * passwords.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+string::zero_clear()
+{
+ if (mUtf16Cache != NULL) {
+ Util_ZeroFree(mUtf16Cache,
+ Unicode_UTF16Strlen(mUtf16Cache) * sizeof *mUtf16Cache);
+ mUtf16Cache = NULL;
+ }
+
+ /*
+ * This is a best effort. We aren't guaranteed that Glib::ustring doesn't
+ * leave behind any internal copies of the string.
+ */
+ if (mUstr.c_str() != mUstr.data()) {
+ Util_Zero(const_cast<char *>(mUstr.c_str()), mUstr.bytes());
+ }
+ Util_Zero(const_cast<char *>(mUstr.data()), mUstr.bytes());
+ mUstr.clear();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::erase --
+ *
+ * Erase the contents of this string in the specified index range.
+ *
+ * Results:
+ * A reference to this object
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string&
+string::erase(size_type i, // IN
+ size_type n) // IN
+{
+ InvalidateCache();
+ mUstr.erase(i, n);
+ return *this;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::erase --
+ *
+ * Erase the contents of this string with given iterator.
+ *
+ * Results:
+ * The current iterator.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::iterator
+string::erase(iterator p) // IN
+{
+ InvalidateCache();
+ return mUstr.erase(p);
+}
+
+
+string::iterator
+string::erase(iterator pbegin, // IN
+ iterator pend) // IN
+{
+ InvalidateCache();
+ return mUstr.erase(pbegin, pend);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::replace --
+ *
+ * Replace the string contents specified by the range, with the passed in
+ * string.
+ *
+ * Results:
+ * A reference to this object.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string&
+string::replace(size_type i, // IN
+ size_type n, // IN
+ const string &s) // IN
+{
+ InvalidateCache();
+ mUstr.replace(i, n, s.mUstr);
+ return *this;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::replace --
+ *
+ * Replace all occurences of the given string with another string.
+ *
+ * Results:
+ * A utf::string created with the substring replaced.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string&
+string::replace(const string &from, // IN
+ const string &to) // IN
+{
+ size_type end;
+ size_type start = 0;
+ size_type fromSize = from.length();
+ string result;
+
+ while ((end = find(from, start)) != string::npos) {
+ result += substr(start, end - start);
+ result += to;
+
+ start = end + fromSize;
+ }
+
+ if (start < length()) {
+ result += substr(start);
+ }
+
+ swap(result);
+ return *this;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::compare --
+ *
+ * A 3-way (output -1, 0, or 1) string comparison. Compares each Unicode
+ * code point of this string to the argument string.
+ *
+ * Results:
+ * -1 if *this < s, 0 if *this == s, 1 if *this > s.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+string::compare(const string &s, // IN
+ bool ignoreCase) // IN/OPT: false by default
+ const
+{
+ return ignoreCase
+ ? Unicode_CompareIgnoreCase(c_str(), s.c_str())
+ : Unicode_Compare(c_str(), s.c_str());
+}
+
+
+int
+string::compare(size_type i, // IN
+ size_type n, // IN
+ const string &s) // IN
+ const
+{
+ return mUstr.compare(i, n, s.mUstr);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::compareLength --
+ *
+ * A 3-way (output -1, 0, or 1) string comparison with given length.
+ * Compares only the first len characters (in code units) of the strings.
+ *
+ * Results:
+ * -1 if *this < s, 0 if *this == s, 1 if *this > s.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+string::compareLength(const string &s, // IN
+ size_type len, // IN: length in code-point
+ bool ignoreCase) // IN/OPT: false by default
+ const
+{
+ return substr(0, len).compare(s.substr(0, len), ignoreCase);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::compareRange --
+ *
+ * A 3-way (output -1, 0, or 1) string comparison with given length.
+ * Compares the substrings from this string [thisStart ~ thisStart + thisLength-1]
+ * with the input string str [strStart ~ strStart + strLength - 1].
+ *
+ * Results:
+ * -1 if *this < s, 0 if *this == s, 1 if *this > s.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+string::compareRange(size_type thisStart, // IN: index in code-point
+ size_type thisLength, // IN: length in code-point
+ const string &str, // IN
+ size_type strStart, // IN: index in code-point
+ size_type strLength, // IN: length in code-point
+ bool ignoreCase) // IN/OPT: false by default
+ const
+{
+ return substr(thisStart, thisLength).compare(str.substr(strStart, strLength), ignoreCase);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::find --
+ *
+ * Searches for the first occurrence of the input string inside this string.
+ *
+ * Results:
+ * If s is found, then, it returns the first starting index of the input string.
+ * Otherwise, returns npos.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::find(const string &s, // IN
+ size_type pos) // IN/OPT
+ const
+{
+ return mUstr.find(s.mUstr, pos);
+}
+
+
+string::size_type
+string::find(value_type uc, // IN
+ size_type pos) // IN/OPT
+ const
+{
+ return mUstr.find(uc, pos);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::rfind --
+ *
+ * Searches for the last occurrence of the input string inside this string.
+ *
+ * Results:
+ * If s is found, then, it returns the last starting index of the input string.
+ * Otherwise, returns npos.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::rfind(const string &s, // IN
+ size_type pos) // IN/OPT
+ const
+{
+ return mUstr.rfind(s.mUstr, pos);
+}
+
+
+string::size_type
+string::rfind(value_type uc, // IN
+ size_type pos) // IN/OPT
+ const
+{
+ return mUstr.rfind(uc, pos);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::find_first_of --
+ *
+ * Find the first occurence of 's' in this string. 'i' determines where in
+ * the current string we start searching for 's'
+ *
+ * Results:
+ * If s is found, then, it returns the index where s occurs in this
+ * string.
+ * Otherwise, returns npos.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::find_first_of(const string &s, // IN
+ size_type i) // IN/OPT
+ const
+{
+ return mUstr.find_first_of(s.mUstr, i);
+}
+
+
+string::size_type
+string::find_first_of(value_type uc, // IN
+ size_type i) // IN/OPT
+ const
+{
+ return mUstr.find_first_of(uc, i);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::find_first_not_of --
+ *
+ * Find the first occurence of a string NOT in 's' in this string. 'i'
+ * determines where in this string we start searching to NOT 's'.
+ *
+ * Results:
+ * Returns the index of the first sequence in this string that is not 's'
+ * Otherwise, returns npos.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::find_first_not_of(const string &s, // IN
+ size_type i) // IN/OPT
+ const
+{
+ return mUstr.find_first_not_of(s.mUstr, i);
+}
+
+
+string::size_type
+string::find_first_not_of(value_type uc, // IN
+ size_type i) // IN/OPT
+ const
+{
+ return mUstr.find_first_not_of(uc, i);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::find_last_of --
+ *
+ * Does a reverse search in this string for 's'. 'i' determines where we
+ * start the search for in this string.
+ *
+ * Results:
+ * If s is found, then, it returns the index where s occurs in this
+ * string.
+ * Otherwise, returns npos.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::find_last_of(const string &s, // IN
+ size_type i) // IN/OPT
+ const
+{
+ return mUstr.find_last_of(s.mUstr, i);
+}
+
+
+string::size_type
+string::find_last_of(value_type uc, // IN
+ size_type i) // IN/OPT
+ const
+{
+ return mUstr.find_last_of(uc, i);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::find_last_not_of --
+ *
+ * Searches for the last character within the current string that does
+ * not match any characters in 's'. 'i' determines where we start the
+ * search for in this string. (moving backwards).
+ *
+ * Results:
+ * If NOT 's' is found, then, it returns the index where s does not occurs
+ * in this string.
+ * Otherwise, returns npos.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::find_last_not_of(const string &s, // IN
+ size_type i) // IN/OPT
+ const
+{
+ return mUstr.find_last_not_of(s.mUstr, i);
+}
+
+
+string::size_type
+string::find_last_not_of(value_type uc, // IN
+ size_type i) // IN/OPT
+ const
+{
+ return mUstr.find_last_not_of(uc, i);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::substr --
+ *
+ * Create a substring of this string with given range.
+ *
+ * Results:
+ * The newly created string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+string::substr(size_type start, // IN
+ size_type len) // IN
+ const
+{
+ return string(mUstr.substr(start, len));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator[] --
+ *
+ * Get the UTF-32 character at given index in this string.
+ *
+ * Results:
+ * UTF-32 character (gunichar).
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::value_type
+string::operator[](size_type i) // IN
+ const
+{
+ return mUstr[i];
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::startsWith --
+ *
+ * Tests if the current string starts with 's'
+ *
+ * Results:
+ * true if current string starts with 's', false otherwise
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+string::startsWith(const string &s, // IN
+ bool ignoreCase) // IN/OPT: false by default
+ const
+{
+ return UnicodeStartsWith(c_str(), s.c_str(), ignoreCase);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::endsWith --
+ *
+ * Tests if the current string ends with 's'
+ *
+ * Results:
+ * true if current string ends with 's', false otherwise
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+string::endsWith(const string &s, // IN
+ bool ignoreCase) // IN/OPT: false by default
+ const
+{
+ return UnicodeEndsWith(c_str(), s.c_str(), ignoreCase);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::split --
+ *
+ * Return a vector of utf::strings. The vector contains the elements of
+ * the string split by the passed in separator. Empty tokens are not
+ * skipped.
+ *
+ * "1,2,3".split(",") -> ["1", "2", "3"]
+ * "1,,".split(",") -> ["1", "", ""]
+ * "1".split(",") -> ["1"]
+ *
+ * XXX If this is to be used for things like command line parsing, support
+ * for quoted strings needs to be added.
+ *
+ * Results:
+ * A vector of utf::strings
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+std::vector<string>
+string::split(const string &sep) // IN
+ const
+{
+ std::vector<string> splitStrings;
+ size_type sIndex = 0;
+ size_type sepLen = sep.length();
+
+ ASSERT(sepLen > 0);
+
+ while (true) {
+ size_type index = find(sep, sIndex);
+ if (index == npos) {
+ splitStrings.push_back(substr(sIndex));
+ break;
+ }
+
+ splitStrings.push_back(substr(sIndex, index - sIndex));
+ sIndex = index + sepLen;
+ }
+
+ return splitStrings;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::GetUtf16Cache --
+ *
+ * Return the UTF-16 representation of the current string, this value is
+ * cached, in the object. If the cache is not valid (NULL), then create
+ * the cache value
+ *
+ * Results:
+ * A UTF-16 representation of the current string
+ *
+ * Side effects:
+ * Allocates a UTF16 string
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+const utf16_t *
+string::GetUtf16Cache()
+ const
+{
+ if (mUtf16Cache == NULL) {
+ mUtf16Cache = Unicode_GetAllocUTF16(c_str());
+ }
+
+ return mUtf16Cache;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::InvalidateCache --
+ *
+ * Frees the cache in this string.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+string::InvalidateCache()
+{
+ free(mUtf16Cache);
+ mUtf16Cache = NULL;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator+ --
+ *
+ * Create a new string by appending the input string to this string.
+ *
+ * NOTE: This is not the same as append. append() will modify the
+ * current object, while this will return a new object.
+ *
+ * Results:
+ * The newly created string.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+string::operator+(const string &rhs) // IN
+ const
+{
+ return mUstr + rhs.mUstr;
+}
+
+
+string
+string::operator+(value_type uc) // IN
+ const
+{
+ return mUstr + uc;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator== --
+ *
+ * Equality operator for string objects
+ *
+ * Results:
+ * true or false (true if equal)
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+string::operator==(const string &rhs) // IN
+ const
+{
+ return compare(rhs) == 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator!= --
+ *
+ * Inequality operator for string objects
+ *
+ * Results:
+ * true or false (true if not equal)
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+string::operator!=(const string &rhs) // IN
+ const
+{
+ return compare(rhs) != 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator< --
+ *
+ * Less than operator for string objects
+ *
+ * Results:
+ * true or false (true if lhs is < rhs)
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+string::operator<(const string &rhs) // IN
+ const
+{
+ return compare(rhs) < 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator> --
+ *
+ * Greater than operator for string objects
+ *
+ * Results:
+ * true or false (true if lhs is > rhs)
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+string::operator>(const string &rhs) // IN
+ const
+{
+ return compare(rhs) > 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator<= --
+ *
+ * Less than or equal than operator for string objects
+ *
+ * Results:
+ * true or false (true if lhs is <= rhs)
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+string::operator<=(const string &rhs) // IN
+ const
+{
+ return compare(rhs) <= 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::operator>= --
+ *
+ * Greater than or equal than operator for string objects
+ *
+ * Results:
+ * true or false (true if lhs is >= rhs)
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+string::operator>=(const string &rhs) // IN
+ const
+{
+ return compare(rhs) >= 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::begin --
+ *
+ * Returns an iterator to the start of the string.
+ *
+ * Results:
+ * iterator
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::iterator
+string::begin()
+{
+ return mUstr.begin();
+}
+
+
+string::const_iterator
+string::begin()
+ const
+{
+ return mUstr.begin();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::end --
+ *
+ * Returns an iterator to the end of the string.
+ *
+ * Results:
+ * iterator
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::iterator
+string::end()
+{
+ return mUstr.end();
+}
+
+
+string::const_iterator
+string::end()
+ const
+{
+ return mUstr.end();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::Validate --
+ *
+ * Validates the string.
+ *
+ * Results:
+ * true if the string contains is valid UTF-8, false otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+bool
+Validate(const Glib::ustring& s) // IN
+{
+ bool isValid = s.validate();
+ if (!isValid) {
+ char *escaped = Unicode_EscapeBuffer(s.c_str(), -1, STRING_ENCODING_UTF8);
+ Warning("Invalid UTF-8 string: \"%s\"\n", escaped);
+ free(escaped);
+ }
+ return isValid;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::CreateWithLength --
+ *
+ * A wrapper function for Unicode_AllocWithLength() that returns a utf::string.
+ *
+ * Results:
+ * A utf::string created with given parameters.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+CreateWithLength(const void *buffer, // IN
+ ssize_t lengthInBytes, // IN: NUL not included
+ StringEncoding encoding) // IN
+{
+ if (!Unicode_IsBufferValid(buffer, lengthInBytes, encoding)) {
+ throw ConversionError();
+ }
+
+ Unicode utf8 = Unicode_AllocWithLength(buffer, lengthInBytes, encoding);
+
+ try {
+ string result(utf8);
+ Unicode_Free(utf8);
+ return result;
+ } catch (...) {
+ Unicode_Free(utf8);
+ throw;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * utf::CreateWithBOMBuffer --
+ *
+ * Convert a text buffer with BOM (byte-order mark) to utf::string.
+ * If BOM not present, assume it's UTF-8.
+ *
+ * Results:
+ * A utf::string containing the text buffer.
+ *
+ * Side Effect:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+string
+CreateWithBOMBuffer(const void *buffer, // IN
+ ssize_t lengthInBytes) // IN: NUL not included
+{
+ struct BOMMap {
+ uint8 bom[4]; // BOM with max size.
+ ssize_t len; // Length of BOM.
+ StringEncoding encoding; // Encoding if a BOM is present.
+ };
+
+ static const BOMMap mapBOM[] = {
+ {{0}, 0, STRING_ENCODING_UTF8 }, // Default encoding.
+ {{0xEF, 0xBB, 0xBF}, 3, STRING_ENCODING_UTF8 },
+ {{0xFE, 0xFF}, 2, STRING_ENCODING_UTF16_BE },
+ {{0xFF, 0xFE}, 2, STRING_ENCODING_UTF16_LE },
+ {{0x00, 0x00, 0xFE, 0xFF}, 4, STRING_ENCODING_UTF32_BE },
+ {{0xFF, 0xFE, 0x00, 0x00}, 4, STRING_ENCODING_UTF32_LE }
+ };
+
+ ASSERT(lengthInBytes >= 0);
+ unsigned int index = 0; // Default encoding, no need to check.
+ for (unsigned int i = 1; i < ARRAYSIZE(mapBOM); i++) {
+ if ( lengthInBytes >= mapBOM[i].len
+ && memcmp(mapBOM[i].bom, buffer, mapBOM[i].len) == 0) {
+ index = i;
+ break;
+ }
+ }
+
+ return CreateWithLength(reinterpret_cast<const char*>(buffer) + mapBOM[index].len,
+ lengthInBytes - mapBOM[index].len,
+ mapBOM[index].encoding);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::IntToStr --
+ *
+ * Converts an integer to a utf::string.
+ *
+ * Results:
+ * A utf::string created with the given integer.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string
+IntToStr(int64 val) // IN
+{
+ std::ostringstream ostream;
+ ostream << val;
+ return ostream.str().c_str();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::CopyArray --
+ *
+ * Copies an array to a vector.
+ *
+ * Results:
+ * A vector containing a shallow copy of the array.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+template<typename T>
+static void
+CopyArray(const T *p, // IN:
+ size_t n, // IN: The number of array elements to copy.
+ std::vector<T>& buf) // OUT:
+{
+ buf.resize(n);
+ if (!buf.empty()) {
+ ASSERT(p != NULL);
+ memcpy(&buf[0], p, buf.size() * sizeof buf[0]);
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::CreateWritableBuffer --
+ *
+ * Copies a utf::string to a writable buffer.
+ *
+ * Results:
+ * A std::vector containing the string data.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CreateWritableBuffer(const string& s, // IN:
+ std::vector<char>& buf) // OUT: A copy of the string, as UTF-8.
+{
+ CopyArray(s.c_str(), s.bytes() + 1, buf);
+}
+
+
+void
+CreateWritableBuffer(const string& s, // IN:
+ std::vector<utf16_t>& buf) // OUT: A copy of the string, as UTF-16.
+{
+ CopyArray(s.w_str(), Unicode_UTF16Strlen(s.w_str()) + 1, buf);
+}
+
+
+} // namespace utf
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * string.hh --
+ *
+ * A string wrapper for bora/lib/unicode. This class is intended to provide
+ * more c++ features such as operator overloading, automatic string conversion
+ * between different types of string classes.
+ *
+ * This class uses glib::ustring as the underlying storage for its data,
+ * we chose this object because of its internal support for unicode.
+ *
+ */
+
+#ifndef UTF_STRING_HH
+#define UTF_STRING_HH
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#ifdef _WIN32
+#pragma pack(push, 8)
+#endif // _WIN32
+
+#include <glibmm/ustring.h>
+
+#ifdef _WIN32
+#pragma pack(pop)
+#endif // _WIN32
+
+#ifdef _WIN32
+#include "ubstr_t.hh"
+#endif
+
+#include "libExport.hh"
+extern "C" {
+#include "unicodeTypes.h"
+}
+
+#ifdef _WIN32
+/*
+ * Disabling Windows warning 4251
+ * This is a warning msg about requiring Glib::ustring to be DLL
+ * exportable.
+ */
+#pragma warning(push)
+#pragma warning(disable:4251)
+#endif
+
+namespace utf {
+
+
+/* utf8string should be replaced with an opaque type. It is temporarily used
+ * to replace the std::string in our codebase.
+ */
+typedef std::string utf8string;
+typedef std::basic_string<utf16_t> utf16string;
+
+class VMSTRING_EXPORT string
+{
+public:
+ // type definitions
+ typedef Glib::ustring::size_type size_type;
+ typedef Glib::ustring::value_type value_type;
+ typedef Glib::ustring::iterator iterator;
+ typedef Glib::ustring::const_iterator const_iterator;
+
+ // constant definitions
+ static const size_type npos;
+
+ // Normalize mode map to Glib::NormalizeMode
+ typedef enum {
+ NORMALIZE_DEFAULT = Glib::NORMALIZE_DEFAULT,
+ NORMALIZE_NFD = Glib::NORMALIZE_NFD,
+ NORMALIZE_DEFAULT_COMPOSE = Glib::NORMALIZE_DEFAULT_COMPOSE,
+ NORMALIZE_NFC = Glib::NORMALIZE_NFC,
+ NORMALIZE_ALL = Glib::NORMALIZE_ALL,
+ NORMALIZE_NFKD = Glib::NORMALIZE_NFKD,
+ NORMALIZE_ALL_COMPOSE = Glib::NORMALIZE_ALL_COMPOSE,
+ NORMALIZE_NFKC = Glib::NORMALIZE_NFKC
+ } NormalizeMode;
+
+ string();
+ string(ConstUnicode s);
+
+#ifdef _WIN32
+ string(const ubstr_t &s);
+ explicit string(const _bstr_t &s);
+#endif
+
+ string(const utf16string &s);
+ string(const utf16_t *s);
+ string(const char *s, StringEncoding encoding);
+ string(const Glib::ustring &s);
+ string(const string &s);
+
+ ~string();
+
+ // Implicit conversions
+ operator const Glib::ustring& () const;
+#ifdef _WIN32
+ operator const ubstr_t() const;
+#endif
+
+ // Conversions to other i18n types (utf8, utf16, unicode)
+ const char *c_str() const;
+ const utf16_t *w_str() const;
+ const Glib::ustring& ustr() const;
+
+ // Mapping functions to Glib::ustring
+ void swap(string &s);
+ void resize(size_type n, value_type c = '\0');
+ bool empty() const;
+ size_type size() const;
+ size_type length() const;
+ size_type bytes() const;
+ string foldCase() const;
+ string trim() const;
+ string trimLeft() const;
+ string trimRight() const;
+ string normalize(NormalizeMode mode = NORMALIZE_DEFAULT_COMPOSE) const;
+
+#ifdef SUPPORT_UNICODE
+ string toLower(const char *locale) const;
+ string toUpper(const char *locale) const;
+ string toTitle(const char *locale) const;
+#endif
+
+ // String-level member methods.
+ string& append(const string &s);
+ string& append(const string &s, size_type i, size_type n);
+ string& assign(const string &s);
+ void push_back(value_type uc);
+ void clear();
+ void zero_clear();
+ string& insert(size_type i, const string& s);
+ string& insert(size_type i, size_type n, value_type uc);
+ string& erase(size_type i, size_type n = npos);
+ iterator erase(iterator p);
+ iterator erase(iterator pbegin, iterator pend);
+ string& replace(size_type i, size_type n, const string& s);
+ string& replace(const string &from, const string &to);
+
+ int compare(const string &s, bool ignoreCase = false) const;
+ int compare(size_type i, size_type n, const string &s) const;
+ int compareLength(const string &s, size_type len, bool ignoreCase = false) const;
+ int compareRange(size_type thisStart, size_type thisLength, const string &str,
+ size_type strStart, size_type strLength,
+ bool ignoreCase = false) const;
+ size_type find(const string &s, size_type pos = 0) const;
+ size_type rfind(const string &s, size_type pos = npos) const;
+ size_type find_first_of(const string &s, size_type i = 0) const;
+ size_type find_first_not_of(const string &s, size_type i = 0) const;
+ size_type find_last_of(const string &s, size_type i = npos) const;
+ size_type find_last_not_of(const string &s, size_type i = npos) const;
+ string substr(size_type start = 0, size_type len = npos) const;
+
+ // Character-level member methods.
+ value_type operator[](size_type i) const;
+ size_type find(value_type uc, size_type pos = 0) const;
+ size_type rfind(value_type uc, size_type pos = npos) const;
+ size_type find_first_of(value_type uc, size_type i = 0) const;
+ size_type find_first_not_of(value_type uc, size_type i = 0) const;
+ size_type find_last_of(value_type uc, size_type i = npos) const;
+ size_type find_last_not_of(value_type uc, size_type i = npos) const;
+
+ // Sequence accessor.
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ // Operator overloads
+ string& operator=(const string &s);
+ string& operator+=(const string &s);
+ string& operator+=(value_type uc);
+
+ // Some helper functions that are nice to have
+ bool startsWith(const string &s, bool ignoreCase = false) const;
+ bool endsWith(const string &s, bool ignoreCase = false) const;
+ std::vector<string> split(const string &sep) const;
+
+ // Overloaded operators
+ string operator+(const string &rhs) const;
+ string operator+(value_type uc) const;
+ bool operator==(const string &rhs) const;
+ bool operator!=(const string &rhs) const;
+ bool operator<(const string &rhs) const;
+ bool operator>(const string &rhs) const;
+ bool operator<=(const string &rhs) const;
+ bool operator>=(const string &rhs) const;
+
+private:
+ // Cache operations
+ void InvalidateCache();
+
+ // Cache accessors
+ const utf16_t *GetUtf16Cache() const;
+
+ // utf::string is internally backed by Glib::ustring.
+ Glib::ustring mUstr;
+
+ // Cached representations.
+ mutable utf16_t *mUtf16Cache;
+};
+
+// Helper operators
+
+string inline
+operator+(ConstUnicode lhs, const string &rhs) {
+ return string(lhs) + rhs;
+}
+
+bool inline
+operator==(ConstUnicode lhs, const string &rhs) {
+ return string(lhs) == rhs;
+}
+
+bool inline
+operator!=(ConstUnicode lhs, const string &rhs) {
+ return string(lhs) != rhs;
+}
+
+bool inline
+operator<(ConstUnicode lhs, const string &rhs) {
+ return string(lhs) < rhs;
+}
+
+bool inline
+operator>(ConstUnicode lhs, const string &rhs) {
+ return string(lhs) > rhs;
+}
+
+bool inline
+operator<=(ConstUnicode lhs, const string &rhs) {
+ return string(lhs) <= rhs;
+}
+
+bool inline
+operator>=(ConstUnicode lhs, const string &rhs) {
+ return string(lhs) >= rhs;
+}
+
+
+// ConversionError class for exception
+
+class ConversionError {};
+
+
+// Helper functions
+
+bool VMSTRING_EXPORT Validate(const Glib::ustring& s);
+
+string VMSTRING_EXPORT
+CreateWithLength(const void *buffer, ssize_t lengthInBytes, StringEncoding encoding);
+
+string VMSTRING_EXPORT
+CreateWithBOMBuffer(const void *buffer, ssize_t lengthInBytes);
+
+string VMSTRING_EXPORT
+IntToStr(int64 val);
+
+void VMSTRING_EXPORT CreateWritableBuffer(const string& s,
+ std::vector<char>& buf);
+void VMSTRING_EXPORT CreateWritableBuffer(const string& s,
+ std::vector<utf16_t>& buf);
+
+
+} // namespace utf
+
+
+
+// Template specializations for utf::string.
+namespace std {
+
+template<>
+inline void
+swap<utf::string>(utf::string& s1, // IN/OUT
+ utf::string& s2) // IN/OUT
+{
+ s1.swap(s2);
+}
+
+} // namespace std
+
+
+#ifdef _WIN32
+#pragma warning(pop)
+#endif
+
+#endif
--- /dev/null
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * ubstr_t.hh --
+ *
+ * A string wrapper for _bstr_t. _bstr_t assumes all char* strings use
+ * the local MBCS encoding, but we want to require that char* strings be
+ * interpreted as UTF-8.
+ */
+
+#ifndef _WIN32
+#error This file should be built on Windows only.
+#endif
+
+#pragma once
+
+#include <algorithm>
+#include <comutil.h>
+#include <glibmm/refptr.h>
+
+extern "C" {
+#include "unicode.h"
+#include "util.h"
+}
+
+
+#ifdef I_LOVE_BSTR_T_CLASSIC
+
+typedef _bstr_t ubstr_t;
+typedef _variant_t uvariant_t;
+
+#else
+
+class ubstr_t
+{
+public:
+ ubstr_t();
+ ubstr_t(const char *s);
+ ubstr_t(const wchar_t *s);
+ ubstr_t(const _variant_t& var);
+ ubstr_t(BSTR bstr, bool copy);
+ ubstr_t(const ubstr_t& s);
+
+ ubstr_t& operator=(const ubstr_t& s);
+ ubstr_t& operator=(const char *s);
+ ubstr_t& operator=(const wchar_t *s);
+ ubstr_t& operator=(const _variant_t& var);
+
+ // Wrappers around standard _bstr_t methods.
+ void Assign(BSTR s);
+ BSTR copy(bool copy = true) const;
+
+ void Attach(BSTR s);
+ BSTR Detach();
+
+ BSTR *GetAddress();
+ BSTR& GetBSTR();
+
+ unsigned int length() const;
+
+ ubstr_t& operator+=(const ubstr_t& s);
+ ubstr_t operator+(const ubstr_t& s) const;
+ ubstr_t operator+(const char *s) const;
+ ubstr_t operator+(const wchar_t *s) const;
+
+ bool operator!() const;
+ bool operator==(const ubstr_t& s) const;
+ bool operator!=(const ubstr_t& s) const;
+ bool operator<(const ubstr_t& s) const;
+ bool operator>(const ubstr_t& s) const;
+ bool operator<=(const ubstr_t& s) const;
+ bool operator>=(const ubstr_t& s) const;
+
+ operator const wchar_t*() const;
+ operator wchar_t*() const; // XXX: Get rid of this.
+ operator const char*() const;
+#ifndef I_HATE_NON_CONST_BSTR_T_CASTS
+ operator char*() const; // XXX: Get rid of this.
+#endif
+
+ /*
+ * _variant_t is implicitly constructible from a _bstr_t. Since we can't
+ * add a constructor to _variant_t, instead provide an implicit conversion
+ * from ubstr_t to _variant_t.
+ */
+ operator _variant_t() const;
+
+ void swap(ubstr_t& s);
+
+private:
+ class UTF8Data
+ {
+ public:
+ // Takes ownership of the input string.
+ UTF8Data(char *utf8String = NULL) // IN/OUT: May be NULL
+ : mUTF8String(utf8String),
+ mRefCount(1)
+ {
+ }
+
+ // For Glib::RefPtr.
+ void reference()
+ {
+ ++mRefCount;
+ }
+
+ // For Glib::RefPtr.
+ void unreference()
+ {
+ --mRefCount;
+ if (mRefCount == 0) {
+ delete this;
+ }
+ }
+
+ // Takes ownership of the input string.
+ void Set(char *utf8String) // IN/OUT: May be NULL.
+ {
+ free(mUTF8String);
+ mUTF8String = utf8String;
+ }
+
+ char *Get()
+ {
+ return mUTF8String;
+ }
+
+ private:
+ // Only destructible via unreference().
+ ~UTF8Data()
+ {
+ free(mUTF8String);
+ }
+
+ char *mUTF8String;
+ unsigned int mRefCount;
+
+ private:
+ // Intentionally unimplemented.
+ UTF8Data(const UTF8Data&);
+ UTF8Data& operator=(const UTF8Data&);
+ };
+
+ char *GetUTF8Cache() const;
+ void InvalidateCache();
+
+ /*
+ * Anything that mutates mBstr (all non-const methods) must call
+ * InvalidateCache().
+ */
+ _bstr_t mBstr;
+
+ // mUTF8 is allocated and initialized lazily.
+ mutable Glib::RefPtr<UTF8Data> mUTF8;
+};
+
+
+/*
+ * _variant_t does string conversions too, so we also need to wrap that.
+ * Since _variant_t doesn't keep a cached version of the locally-encoded
+ * MBCS string and since we don't use _variant_t nearly as much as _bstr_t,
+ * substitutability isn't as much of a concern, so we can use inheritance.
+ */
+class uvariant_t
+ : public _variant_t
+{
+public:
+ /*
+ * Wrappers around standard _variant_t constructors. Unfortunately we
+ * have to wrap all the constructors since they aren't inherited.
+ */
+ uvariant_t() : _variant_t() { }
+ uvariant_t(const VARIANT& var) : _variant_t(var) { }
+ uvariant_t(const VARIANT *var) : _variant_t(var) { }
+ uvariant_t(const _variant_t& var) : _variant_t(var) { }
+ uvariant_t(VARIANT& var, bool copy) : _variant_t(var, copy) { }
+ uvariant_t(short i, VARTYPE vt = VT_I2) : _variant_t(i, vt) { }
+ uvariant_t(long i, VARTYPE vt = VT_I4) : _variant_t(i, vt) { }
+ uvariant_t(float f) : _variant_t(f) { }
+ uvariant_t(double d, VARTYPE vt = VT_R8) : _variant_t(d, vt) { }
+ uvariant_t(const CY& cy) : _variant_t(cy) { }
+ uvariant_t(const _bstr_t& s) : _variant_t(s) { }
+ uvariant_t(const wchar_t *s) : _variant_t(s) { }
+ uvariant_t(IDispatch *dispatch, bool addRef = true) : _variant_t(dispatch, addRef) { }
+ uvariant_t(bool b) : _variant_t(b) { }
+ uvariant_t(IUnknown *unknown, bool addRef = true) : _variant_t(unknown, addRef) { }
+ uvariant_t(const DECIMAL& dec) : _variant_t(dec) { }
+ uvariant_t(BYTE i) : _variant_t(i) { }
+ uvariant_t(char c) : _variant_t(c) { }
+ uvariant_t(unsigned short i) : _variant_t(i) { }
+ uvariant_t(unsigned long i) : _variant_t(i) { }
+ uvariant_t(int i) : _variant_t(i) { }
+ uvariant_t(unsigned int i) : _variant_t(i) { }
+#if _WIN32_WINNT >= 0x0501
+ uvariant_t(__int64 i) : _variant_t(i) { }
+ uvariant_t(unsigned __int64 i) : _variant_t(i) { }
+#endif
+
+ // Override the _variant_t constructor that assumes locally-encoded strings.
+ uvariant_t(const char *s) : _variant_t(ubstr_t(s)) { }
+
+ // Provide conversion from our ubstr_t wrapper.
+ uvariant_t(const ubstr_t& s) : _variant_t(s) { }
+};
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::ubstr_t --
+ *
+ * ubstr_t constructors.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline
+ubstr_t::ubstr_t()
+ : mBstr(),
+ mUTF8()
+{
+}
+
+
+inline
+ubstr_t::ubstr_t(const char *s) // IN: A UTF-8-encoded string.
+ : mBstr(),
+ mUTF8()
+{
+ if (s != NULL) {
+ // Since we already have the UTF-8 version of the string, cache it now.
+ mUTF8 = Glib::RefPtr<UTF8Data>(new UTF8Data(Util_SafeStrdup(s)));
+ utf16_t *utf16Str = Unicode_GetAllocUTF16(s);
+ try {
+ mBstr = utf16Str;
+ free(utf16Str);
+ } catch (...) {
+ free(utf16Str);
+ throw;
+ }
+ }
+}
+
+
+inline
+ubstr_t::ubstr_t(const wchar_t *s) // IN
+ : mBstr(s),
+ mUTF8()
+{
+}
+
+
+inline
+ubstr_t::ubstr_t(const _variant_t& var) // IN
+ : mBstr(var),
+ mUTF8()
+{
+}
+
+
+inline
+ubstr_t::ubstr_t(BSTR bstr, // IN
+ bool copy) // IN
+ : mBstr(bstr, copy),
+ mUTF8()
+{
+}
+
+
+inline
+ubstr_t::ubstr_t(const ubstr_t& s) // IN
+ : mBstr(s.mBstr),
+ mUTF8(s.mUTF8)
+{
+ if (static_cast<wchar_t *>(mBstr) != NULL && !mUTF8) {
+ mUTF8 = s.mUTF8 = Glib::RefPtr<UTF8Data>(new UTF8Data());
+ }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::operator= --
+ *
+ * ubstr_t assignment operators.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline ubstr_t&
+ubstr_t::operator=(const ubstr_t& s) // IN
+{
+ ubstr_t copy(s);
+ swap(copy);
+ return *this;
+}
+
+
+inline ubstr_t&
+ubstr_t::operator=(const char *s) // IN: A UTF-8-encoded string.
+{
+ return operator=(ubstr_t(s));
+}
+
+
+inline ubstr_t&
+ubstr_t::operator=(const wchar_t *s) // IN
+{
+ return operator=(ubstr_t(s));
+}
+
+
+inline ubstr_t&
+ubstr_t::operator=(const _variant_t& var) // IN
+{
+ return operator=(ubstr_t(var));
+}
+
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::Assign --
+ *
+ * Wrapper around _bstr_t::Assign.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline void
+ubstr_t::Assign(BSTR s) // IN
+{
+ InvalidateCache();
+ mBstr.Assign(s);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::copy --
+ *
+ * Wrapper around _bstr_t::copy.
+ *
+ * Results:
+ * A copy of the underlying BSTR.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline BSTR
+ubstr_t::copy(bool copy) // IN/OPT
+ const
+{
+ return mBstr.copy(copy);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::Attach --
+ *
+ * Wrapper around _bstr_t::Attach.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Invalidates the UTF-8 cache.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline void
+ubstr_t::Attach(BSTR s) // IN
+{
+ InvalidateCache();
+ mBstr.Attach(s);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::Detach --
+ *
+ * Wrapper around _bstr_t::Detach.
+ *
+ * Results:
+ * The underlying BSTR, which is no longer managed.
+ *
+ * Side effects:
+ * Invalidates the UTF-8 cache.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline BSTR
+ubstr_t::Detach()
+{
+ InvalidateCache();
+ return mBstr.Detach();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::GetAddress --
+ *
+ * Wrapper around _bstr_t::GetAddress.
+ *
+ * Results:
+ * A pointer to the underlying BSTR.
+ *
+ * Side effects:
+ * Invalidates the UTF-8 cache.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline BSTR *
+ubstr_t::GetAddress()
+{
+ /*
+ * We don't know if the underlying BSTR will be modified via the returned
+ * pointer. We can only assume it will.
+ */
+ InvalidateCache();
+ return mBstr.GetAddress();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::GetBSTR --
+ *
+ * Wrapper around _bstr_t::GetBSTR.
+ *
+ * Results:
+ * A reference to the underlying BSTR.
+ *
+ * Side effects:
+ * Invalidates the UTF-8 cache.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline BSTR&
+ubstr_t::GetBSTR()
+{
+ /*
+ * We don't know if the underlying BSTR will be modified via the returned
+ * reference. We can only assume it will.
+ */
+ InvalidateCache();
+ return mBstr.GetBSTR();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::length --
+ *
+ * Wrapper around _bstr_t::length.
+ *
+ * Results:
+ * The length of the string, in TCHARs.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline unsigned int
+ubstr_t::length()
+ const
+{
+ return mBstr.length();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::operator+= --
+ *
+ * Mutating concatenation operator.
+ *
+ * Results:
+ * A reference to this ubstr_t object.
+ *
+ * Side effects:
+ * Invalidates the UTF-8 cache.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline ubstr_t&
+ubstr_t::operator+=(const ubstr_t& s) // IN
+{
+ InvalidateCache();
+ mBstr += s.mBstr;
+ return *this;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::operator+ --
+ *
+ * Concatenation operators.
+ *
+ * Results:
+ * A copy of the concatenated string.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline ubstr_t
+ubstr_t::operator+(const ubstr_t& s) // IN
+ const
+{
+ ubstr_t copy(*this);
+ copy += s;
+ return copy;
+}
+
+
+inline ubstr_t
+ubstr_t::operator+(const char *s) // IN
+ const
+{
+ return operator+(ubstr_t(s));
+}
+
+
+inline ubstr_t
+ubstr_t::operator+(const wchar_t *s) // IN
+ const
+{
+ return operator+(ubstr_t(s));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::operator! --
+ *
+ * Wrapper around _bstr_t::operator!.
+ *
+ * Results:
+ * true if the underlying _bstr_t is NULL, false otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline bool
+ubstr_t::operator!()
+ const
+{
+ return !mBstr;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::operator== --
+ * ubstr_t::operator!= --
+ * ubstr_t::operator< --
+ * ubstr_t::operator> --
+ * ubstr_t::operator<= --
+ * ubstr_t::operator>= --
+ *
+ * Wrappers around _bstr_t's comparison operators.
+ *
+ * Results:
+ * true if the comparisons are hold, false otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline bool
+ubstr_t::operator==(const ubstr_t& s) // IN
+ const
+{
+ return mBstr == s.mBstr;
+}
+
+
+inline bool
+ubstr_t::operator!=(const ubstr_t& s) // IN
+ const
+{
+ return mBstr != s.mBstr;
+}
+
+
+inline bool
+ubstr_t::operator<(const ubstr_t& s) // IN
+ const
+{
+ return mBstr < s.mBstr;
+}
+
+
+inline bool
+ubstr_t::operator>(const ubstr_t& s) // IN
+ const
+{
+ return mBstr > s.mBstr;
+}
+
+
+inline bool
+ubstr_t::operator<=(const ubstr_t& s) // IN
+ const
+{
+ return mBstr <= s.mBstr;
+}
+
+
+inline bool
+ubstr_t::operator>=(const ubstr_t& s) // IN
+ const
+{
+ return mBstr >= s.mBstr;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::operator const wchar_t* --
+ * ubstr_t::operator wchar_t* --
+ *
+ * Wrappers around _bstr_t's cast operators.
+ *
+ * Results:
+ * A pointer to the underlying UTF-16 string.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline
+ubstr_t::operator const wchar_t*()
+ const
+{
+ return static_cast<const wchar_t *>(mBstr);
+}
+
+
+inline
+ubstr_t::operator wchar_t*()
+ const
+{
+ return static_cast<wchar_t *>(mBstr);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::operator const char_t* --
+ * ubstr_t::operator char_t* --
+ *
+ * Cast operators to UTF-8 strings.
+ *
+ * Results:
+ * A pointer to a UTF-8 string.
+ *
+ * Side effects:
+ * Might initializes the UTF-8 cache.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline
+ubstr_t::operator const char*()
+ const
+{
+ return GetUTF8Cache();
+}
+
+
+#ifndef I_HATE_NON_CONST_BSTR_T_CASTS
+inline
+ubstr_t::operator char*()
+ const
+{
+ return GetUTF8Cache();
+}
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::operator _variant_t --
+ *
+ * Cast operator to _variant_t.
+ *
+ * Results:
+ * A _variant_t equivalent to this ubstr_t object.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline
+ubstr_t::operator _variant_t()
+ const
+{
+ return static_cast<const wchar_t *>(mBstr);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::swap --
+ *
+ * Swaps this ubstr_t object with another.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline void
+ubstr_t::swap(ubstr_t& s) // IN/OUT
+{
+ std::swap(mBstr, s.mBstr);
+ mUTF8.swap(s.mUTF8);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::GetUTF8Cache --
+ *
+ * Retrieves the UTF-8 cache, initializing it if necessary.
+ *
+ * Results:
+ * The cached UTF-8 string.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline char *
+ubstr_t::GetUTF8Cache()
+ const
+{
+ if (static_cast<wchar_t *>(mBstr) == NULL) {
+ // Nothing to do.
+ return NULL;
+ }
+
+ char *utf8Str = NULL;
+ try {
+ if (!mUTF8) {
+ mUTF8 = Glib::RefPtr<UTF8Data>(new UTF8Data());
+ }
+
+ if (mUTF8->Get() == NULL) {
+ utf8Str = Unicode_AllocWithUTF16(static_cast<wchar_t *>(mBstr));
+ mUTF8->Set(utf8Str);
+ }
+ } catch (...) {
+ free(utf8Str);
+ throw;
+ }
+
+ return mUTF8->Get();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ubstr_t::InvalidateCache --
+ *
+ * Clears the UTF-8 cache.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline void
+ubstr_t::InvalidateCache()
+{
+ mUTF8.clear();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * operator+ --
+ *
+ * Non-member concatenation operators.
+ *
+ * Results:
+ * A copy of the concatenated string.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+inline ubstr_t
+operator+(const char *s1, // IN: A UTF-8-encoded sting.
+ const ubstr_t& s2) // IN
+{
+ return ubstr_t(s1) + s2;
+}
+
+
+inline ubstr_t
+operator+(const wchar_t *s1, // IN
+ const ubstr_t& s2) // IN
+{
+ return ubstr_t(s1) + s2;
+}
+
+
+/*
+ * These are not part of the _bstr_t interface but are provided to catch
+ * misuse. They are intentionally unimplemented to avoid a maintenance
+ * burden, and they intentionally return nothing so that accidental usage
+ * normally results in compile-time errors instead of link-time ones.
+ */
+
+void operator==(const char *s1, const ubstr_t& s2);
+void operator!=(const char *s1, const ubstr_t& s2);
+void operator<(const char *s1, const ubstr_t& s2);
+void operator>(const char *s1, const ubstr_t& s2);
+void operator<=(const char *s1, const ubstr_t& s2);
+void operator>=(const char *s1, const ubstr_t& s2);
+
+void operator==(const WCHAR *s1, const ubstr_t& s2);
+void operator!=(const WCHAR *s1, const ubstr_t& s2);
+void operator<(const WCHAR *s1, const ubstr_t& s2);
+void operator>(const WCHAR *s1, const ubstr_t& s2);
+void operator<=(const WCHAR *s1, const ubstr_t& s2);
+void operator>=(const WCHAR *s1, const ubstr_t& s2);
+
+
+#endif // I_LOVE_BSTR_T_CLASSIC
/*********************************************************
- * Copyright (C) 2005 VMware, Inc. All rights reserved.
+ * Copyright (C) 2009 VMware, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
*
*********************************************************/
-/*
- * vmware-user.c --
+/**
+ * @file vmware-user.cpp
*
- * The linux vmware-user app. It's a hidden window app that is supposed
- * to run on session start. It handles tools features which we want
- * active all the time, but don't want to impose a visable window on the
- * user.
+ * The linux vmware-user app. It's a hidden window app that is supposed
+ * to run on session start. It handles tools features which we want
+ * active all the time, but don't want to impose a visible window on the
+ * user.
*/
+#include "copyPasteWrapper.h"
+
+extern "C" {
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include "vmwareuser_version.h"
#include "embed_version.h"
+} // extern "C"
VM_EMBED_VERSION(VMWAREUSER_VERSION_STRING);
#ifdef _DEBUG
size_t argsSize, void *clientData);
void VMwareUserRpcInErrorCB (void *clientdata, char const *status);
+extern "C" {
extern Bool ForeignTools_Initialize(GuestApp_Dict *configDictionaryParam,
DblLnkLst_Links *eventQueue);
extern void ForeignTools_Shutdown(void);
+}
static Bool InitGroupLeader(Window *groupLeader, Window *rootWindow);
static Bool AcquireDisplayLock(void);
static Bool QueryX11Lock(Display *dpy, Window w, Atom lockAtom);
static void ReloadSelf(void);
+static void VMwareUserRegisterCopyPaste(bool reg);
/*
static Bool gOpenUrlRegistered;
static Bool gDnDRegistered;
-static Bool gCopyPasteRegistered;
static Bool gHgfsServerRegistered;
static pid_t gParentPid;
static char gLogFilePath[PATH_MAX];
Window gXRoot;
DblLnkLst_Links *gEventQueue;
-Bool optionCopyPaste;
Bool optionDnD;
Bool gCanUseVMwareCtrl;
Bool gCanUseVMwareCtrlTopologySet;
DnD_Unregister(gHGWnd, gGHWnd);
gDnDRegistered = FALSE;
}
- if (gCopyPasteRegistered) {
- CopyPaste_Unregister(gUserMainWidget);
- gCopyPasteRegistered = FALSE;
+
+ CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+ if (p && p->IsRegistered()) {
+ p->Unregister();
}
RpcIn_Destruct(gRpcIn);
gRpcIn = NULL;
VMwareUserCleanupRpc();
}
+#if defined(HAVE_GTKMM)
+ Gtk::Main::quit();
+#else
gtk_main_quit();
+#endif
}
gpointer data) // IN: Unused
{
VMwareUserCleanupRpc();
+#if defined(HAVE_GTKMM)
+ Gtk::Main::quit();
+#else
gtk_main_quit();
+#endif
}
if (gDnDRegistered) {
DnD_OnReset(gHGWnd, gGHWnd);
}
- if (gCopyPasteRegistered) {
- CopyPaste_OnReset();
+ CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+ if (p) {
+ p->OnReset();
}
return RPCIN_SETRETVALS(data, "ATR " TOOLS_DND_NAME, TRUE);
}
}
}
- if (!gCopyPasteRegistered) {
- gCopyPasteRegistered = CopyPaste_Register(gUserMainWidget);
- }
-
- if (gCopyPasteRegistered) {
- if (!CopyPaste_RegisterCapability()) {
- CopyPaste_Unregister(gUserMainWidget);
- gCopyPasteRegistered = FALSE;
- }
- }
+ VMwareUserRegisterCopyPaste(TRUE);
if (!HgfsServerManager_CapReg(TOOLS_DND_NAME, gHgfsServerRegistered)) {
Debug("VMwareUserRpcInCapRegCB: Failed to register HGFS server capability.\n");
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMwareUserRegisterCopyPaste
+ *
+ * Call the CopyPasteWrapper singleton to register, or unregister,
+ * copy and paste with the host. The wrapper class will try whatever
+ * versions are supported, in highest to lowest order when registering.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Copy and paste capabilities will be (un)registered.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+VMwareUserRegisterCopyPaste(bool reg) // IN: if TRUE, register, else unregister
+{
+ CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+ if (p) {
+ p->SetUserData(static_cast<void *>(gUserMainWidget));
+ if (reg) {
+ p->Register();
+ } else {
+ p->Unregister();
+ }
+ }
+}
+
+
/*
*-----------------------------------------------------------------------------
*
*/
if (strcmp(option, TOOLSOPTION_COPYPASTE) == 0) {
if (strcmp(value, "1") == 0) {
- optionCopyPaste = TRUE;
- if (!gCopyPasteRegistered) {
- CopyPaste_Register(gUserMainWidget);
- gCopyPasteRegistered = TRUE;
- }
+ VMwareUserRegisterCopyPaste(TRUE);
} else if (strcmp(value, "0") == 0) {
- optionCopyPaste = FALSE;
- if (gCopyPasteRegistered) {
- CopyPaste_Unregister(gUserMainWidget);
- gCopyPasteRegistered = FALSE;
- }
+ VMwareUserRegisterCopyPaste(FALSE);
} else {
retStr = INVALID_VALUE;
goto free_value;
gOpenUrlRegistered = FALSE;
gDnDRegistered = FALSE;
- gCopyPasteRegistered = FALSE;
gHgfsServerRegistered = FALSE;
gBlockFd = -1;
gReloadSelf = FALSE;
/* Set to system locale. */
setlocale(LC_CTYPE, "");
gtk_set_locale();
+#if defined(HAVE_GTKMM)
+ Gtk::Main main(&argc, &argv);
+#else
gtk_init(&argc, &argv);
+#endif
/*
* Running more than 1 VMware user process (vmware-user) per X11 session
/*
* We'll block here until the window is destroyed or a signal is recieved
*/
+#if defined(HAVE_GTKMM)
+ main.run();
+#else
gtk_main();
+#endif
if (gSigExit) {
break;
DnD_Unregister(gHGWnd, gGHWnd);
gDnDRegistered = FALSE;
}
- if (gCopyPasteRegistered) {
- CopyPaste_Unregister(gUserMainWidget);
- gCopyPasteRegistered = FALSE;
+ CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+ if (p) {
+ p->Unregister();
}
if (gBlockFd >= 0 && !DnD_UninitializeBlocking(gBlockFd)) {
Debug("vmware-user failed to uninitialize blocking.\n");
{
Window myGroupLeader;
Window myRootWindow;
- XSetWindowAttributes attr = { .override_redirect = True };
+ XSetWindowAttributes attr;
+
+ attr.override_redirect = True;
ASSERT(groupLeader);
ASSERT(rootWindow);
extern Window gXRoot;
extern DblLnkLst_Links *gEventQueue;
extern GtkWidget *gUserMainWidget;
-extern Bool optionCopyPaste;
extern int gBlockFd;
#endif // _VMWAREUSER_INT_H_