]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
2009.02.18-148847 2009.02.18-148847
authorMarcelo Vanzin <mvanzin@mvanzin-dev1.eng.vmware.com>
Wed, 18 Feb 2009 22:16:55 +0000 (14:16 -0800)
committerMarcelo Vanzin <mvanzin@mvanzin-dev1.eng.vmware.com>
Wed, 18 Feb 2009 22:16:55 +0000 (14:16 -0800)
319 files changed:
open-vm-tools/ChangeLog
open-vm-tools/Makefile.am
open-vm-tools/NEWS
open-vm-tools/configure.ac
open-vm-tools/guestd/Makefile.am
open-vm-tools/guestd/toolsDaemon.c
open-vm-tools/hgfsmounter/Makefile.am
open-vm-tools/hgfsmounter/hgfsmounter.c
open-vm-tools/lib/Makefile.am
open-vm-tools/lib/appUtil/appUtilX11.c
open-vm-tools/lib/dnd/Makefile.am
open-vm-tools/lib/dnd/dndClipboard.c [new file with mode: 0644]
open-vm-tools/lib/dnd/dndMsg.c [new file with mode: 0644]
open-vm-tools/lib/dndGuest/Makefile.am [new file with mode: 0644]
open-vm-tools/lib/dndGuest/copyPaste.cc [new file with mode: 0644]
open-vm-tools/lib/dndGuest/copyPasteRpcV3.cc [new file with mode: 0644]
open-vm-tools/lib/dndGuest/dnd.cc [new file with mode: 0644]
open-vm-tools/lib/dndGuest/dndFileList.cc [new file with mode: 0644]
open-vm-tools/lib/dndGuest/dndTransportGuestRpc.cc [new file with mode: 0644]
open-vm-tools/lib/dynxdr/dynxdr.c
open-vm-tools/lib/file/fileIOPosix.c
open-vm-tools/lib/file/fileLockPrimitive.c
open-vm-tools/lib/file/filePosix.c
open-vm-tools/lib/foundryMsg/foundryMsg.c
open-vm-tools/lib/foundryMsg/foundryPropertyListCommon.c
open-vm-tools/lib/foundryMsg/foundryThreads.c
open-vm-tools/lib/guestApp/guestApp.c
open-vm-tools/lib/guestInfo/Makefile.am
open-vm-tools/lib/guestInfo/guestInfo.c
open-vm-tools/lib/guestInfo/guestInfoInt.h
open-vm-tools/lib/guestInfo/guestInfoPerfMonLinux.c
open-vm-tools/lib/guestInfo/guestInfoPosix.c
open-vm-tools/lib/guestInfo/guestInfoServer.c
open-vm-tools/lib/guestRpc/Makefile.am
open-vm-tools/lib/guestRpc/guestlibV3.x
open-vm-tools/lib/hgfsServer/hgfsServer.c
open-vm-tools/lib/hgfsServer/hgfsServerInt.h
open-vm-tools/lib/hgfsServer/hgfsServerLinux.c
open-vm-tools/lib/include/backdoor_def.h
open-vm-tools/lib/include/buildNumber.h
open-vm-tools/lib/include/copyPaste.hh [new file with mode: 0644]
open-vm-tools/lib/include/copyPasteBase.h [new file with mode: 0644]
open-vm-tools/lib/include/copyPasteRpc.hh [new file with mode: 0644]
open-vm-tools/lib/include/copyPasteRpcV3.hh [new file with mode: 0644]
open-vm-tools/lib/include/dnd.h
open-vm-tools/lib/include/dnd.hh [new file with mode: 0644]
open-vm-tools/lib/include/dndBase.h [new file with mode: 0644]
open-vm-tools/lib/include/dndClipboard.h [new file with mode: 0644]
open-vm-tools/lib/include/dndFileContentsUtil.h [new file with mode: 0644]
open-vm-tools/lib/include/dndFileList.hh [new file with mode: 0644]
open-vm-tools/lib/include/dndInt.h [moved from open-vm-tools/lib/dnd/dndInt.h with 100% similarity]
open-vm-tools/lib/include/dndMsg.h [new file with mode: 0644]
open-vm-tools/lib/include/dndRpc.hh [new file with mode: 0644]
open-vm-tools/lib/include/dndRpcV3.hh [new file with mode: 0644]
open-vm-tools/lib/include/dndTransport.hh [new file with mode: 0644]
open-vm-tools/lib/include/dndTransportGuestRpc.hh [new file with mode: 0644]
open-vm-tools/lib/include/fileIO.h
open-vm-tools/lib/include/guestApp.h
open-vm-tools/lib/include/guest_os.h
open-vm-tools/lib/include/hgfsProto.h
open-vm-tools/lib/include/hostinfo.h
open-vm-tools/lib/include/libExport.hh [new file with mode: 0644]
open-vm-tools/lib/include/log.h
open-vm-tools/lib/include/resolution.h
open-vm-tools/lib/include/rpcChannel.h [new file with mode: 0644]
open-vm-tools/lib/include/system.h
open-vm-tools/lib/include/timeutil.h
open-vm-tools/lib/include/vix.h
open-vm-tools/lib/include/vixOpenSource.h
open-vm-tools/lib/include/vmGuestLib.h
open-vm-tools/lib/include/vm_assert.h
open-vm-tools/lib/include/vm_atomic.h
open-vm-tools/lib/include/vm_basic_asm.h
open-vm-tools/lib/include/vm_basic_types.h
open-vm-tools/lib/include/vm_version.h
open-vm-tools/lib/include/vmrpcdbg.h [new file with mode: 0644]
open-vm-tools/lib/include/vmtoolsApp.h [new file with mode: 0644]
open-vm-tools/lib/include/vmtoolsd_version.h [new file with mode: 0644]
open-vm-tools/lib/include/x86cpuid.h
open-vm-tools/lib/misc/hostinfoPosix.c
open-vm-tools/lib/misc/idLinux.c
open-vm-tools/lib/misc/timeutil.c
open-vm-tools/lib/misc/util_misc.c
open-vm-tools/lib/rpcChannel/Makefile.am [new file with mode: 0644]
open-vm-tools/lib/rpcChannel/bdoorChannel.c [new file with mode: 0644]
open-vm-tools/lib/rpcChannel/rpcChannel.c [new file with mode: 0644]
open-vm-tools/lib/rpcChannel/rpcChannelInt.h [new file with mode: 0644]
open-vm-tools/lib/stubs/Makefile.am
open-vm-tools/lib/system/systemLinux.c
open-vm-tools/lib/unity/unityPlatformX11Window.c
open-vm-tools/lib/vixTools/vixTools.c
open-vm-tools/lib/vmCheck/vmcheck.c
open-vm-tools/lib/wiper/wiperPosix.c
open-vm-tools/libguestlib/vmGuestLib.c
open-vm-tools/libvmtools/Makefile.am
open-vm-tools/libvmtools/vmtoolsConfig.c
open-vm-tools/libvmtools/vmtoolsLog.c
open-vm-tools/m4/COPYING [new file with mode: 0644]
open-vm-tools/m4/vmtools.m4 [new file with mode: 0644]
open-vm-tools/modules/Makefile.am
open-vm-tools/modules/freebsd/vmblock/vm_assert.h
open-vm-tools/modules/freebsd/vmblock/vm_basic_types.h
open-vm-tools/modules/freebsd/vmhgfs/backdoor_def.h
open-vm-tools/modules/freebsd/vmhgfs/hgfsProto.h
open-vm-tools/modules/freebsd/vmhgfs/kernelStubs.h
open-vm-tools/modules/freebsd/vmhgfs/os.c
open-vm-tools/modules/freebsd/vmhgfs/os.h
open-vm-tools/modules/freebsd/vmhgfs/state.c
open-vm-tools/modules/freebsd/vmhgfs/state.h
open-vm-tools/modules/freebsd/vmhgfs/vm_assert.h
open-vm-tools/modules/freebsd/vmhgfs/vm_basic_asm.h
open-vm-tools/modules/freebsd/vmhgfs/vm_basic_types.h
open-vm-tools/modules/freebsd/vmhgfs/vnops.c
open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c
open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.h
open-vm-tools/modules/freebsd/vmhgfs/x86cpuid.h
open-vm-tools/modules/freebsd/vmmemctl/vm_assert.h
open-vm-tools/modules/freebsd/vmmemctl/vm_basic_types.h
open-vm-tools/modules/freebsd/vmxnet/vm_basic_types.h
open-vm-tools/modules/linux/dkms.conf
open-vm-tools/modules/linux/pvscsi/pvscsi.c
open-vm-tools/modules/linux/pvscsi/pvscsi_version.h
open-vm-tools/modules/linux/pvscsi/vm_assert.h
open-vm-tools/modules/linux/pvscsi/vm_basic_types.h
open-vm-tools/modules/linux/vmblock/include/compat_sched.h
open-vm-tools/modules/linux/vmblock/include/vm_assert.h
open-vm-tools/modules/linux/vmblock/include/vm_basic_types.h
open-vm-tools/modules/linux/vmci/compat_sched.h
open-vm-tools/modules/linux/vmci/kernelStubs.h
open-vm-tools/modules/linux/vmci/vm_assert.h
open-vm-tools/modules/linux/vmci/vm_atomic.h
open-vm-tools/modules/linux/vmci/vm_basic_types.h
open-vm-tools/modules/linux/vmci/vmciKernelIf.c
open-vm-tools/modules/linux/vmci/vmci_queue_pair.h
open-vm-tools/modules/linux/vmhgfs/backdoor_def.h
open-vm-tools/modules/linux/vmhgfs/bdhandler.c
open-vm-tools/modules/linux/vmhgfs/compat_cred.h [new file with mode: 0644]
open-vm-tools/modules/linux/vmhgfs/compat_pagemap.h [new file with mode: 0644]
open-vm-tools/modules/linux/vmhgfs/compat_sched.h
open-vm-tools/modules/linux/vmhgfs/file.c
open-vm-tools/modules/linux/vmhgfs/filesystem.c
open-vm-tools/modules/linux/vmhgfs/hgfsProto.h
open-vm-tools/modules/linux/vmhgfs/inode.c
open-vm-tools/modules/linux/vmhgfs/kernelStubs.h
open-vm-tools/modules/linux/vmhgfs/page.c
open-vm-tools/modules/linux/vmhgfs/vm_assert.h
open-vm-tools/modules/linux/vmhgfs/vm_basic_asm.h
open-vm-tools/modules/linux/vmhgfs/vm_basic_types.h
open-vm-tools/modules/linux/vmhgfs/x86cpuid.h
open-vm-tools/modules/linux/vmmemctl/backdoor_def.h
open-vm-tools/modules/linux/vmmemctl/compat_sched.h
open-vm-tools/modules/linux/vmmemctl/os.c
open-vm-tools/modules/linux/vmmemctl/vm_assert.h
open-vm-tools/modules/linux/vmmemctl/vm_basic_types.h
open-vm-tools/modules/linux/vmxnet/compat_pci_mapping.h [new file with mode: 0644]
open-vm-tools/modules/linux/vmxnet/vm_basic_types.h
open-vm-tools/modules/linux/vmxnet/vmxnet.c
open-vm-tools/modules/linux/vmxnet/vmxnetInt.h
open-vm-tools/modules/linux/vmxnet/vmxnet_version.h
open-vm-tools/modules/linux/vmxnet3/vm_basic_types.h
open-vm-tools/modules/linux/vmxnet3/vmxnet3.c
open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h
open-vm-tools/modules/linux/vsock/include/compat_sched.h
open-vm-tools/modules/linux/vsock/include/vm_assert.h
open-vm-tools/modules/linux/vsock/include/vm_atomic.h
open-vm-tools/modules/linux/vsock/include/vm_basic_asm.h
open-vm-tools/modules/linux/vsock/include/vm_basic_types.h
open-vm-tools/modules/linux/vsock/include/vmciHostKernelAPI.h
open-vm-tools/modules/linux/vsock/include/vmci_queue_pair.h
open-vm-tools/modules/linux/vsock/include/x86cpuid.h
open-vm-tools/modules/linux/vsock/linux/af_vsock.c
open-vm-tools/modules/linux/vsock/linux/af_vsock.h
open-vm-tools/modules/linux/vsock/linux/util.c
open-vm-tools/modules/linux/vsock/linux/util.h
open-vm-tools/modules/linux/vsock/linux/vsockSocketWrapper.h
open-vm-tools/modules/solaris/vmhgfs/Makefile
open-vm-tools/modules/solaris/vmhgfs/backdoor.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/backdoor.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/backdoorGcc32.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/backdoorGcc64.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/backdoorInt.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/backdoor_def.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/backdoor_types.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/debug.c
open-vm-tools/modules/solaris/vmhgfs/debug.h
open-vm-tools/modules/solaris/vmhgfs/device.c [deleted file]
open-vm-tools/modules/solaris/vmhgfs/device.h [deleted file]
open-vm-tools/modules/solaris/vmhgfs/filesystem.c
open-vm-tools/modules/solaris/vmhgfs/filesystem.h
open-vm-tools/modules/solaris/vmhgfs/guest_msg_def.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsBd.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsBd.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsBdGlue.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsBdGlue.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsProto.h
open-vm-tools/modules/solaris/vmhgfs/hgfsSolaris.h
open-vm-tools/modules/solaris/vmhgfs/hgfsState.c
open-vm-tools/modules/solaris/vmhgfs/hgfsState.h
open-vm-tools/modules/solaris/vmhgfs/kernelStubs.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/kernelStubsSolaris.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/message.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/message.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/messageBackdoor.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/module.c
open-vm-tools/modules/solaris/vmhgfs/module.h
open-vm-tools/modules/solaris/vmhgfs/request.c
open-vm-tools/modules/solaris/vmhgfs/request.h
open-vm-tools/modules/solaris/vmhgfs/rpcout.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/rpcout.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/str.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vm_assert.h
open-vm-tools/modules/solaris/vmhgfs/vm_basic_asm.h
open-vm-tools/modules/solaris/vmhgfs/vm_basic_types.h
open-vm-tools/modules/solaris/vmhgfs/vnode.c
open-vm-tools/modules/solaris/vmhgfs/vnode.h
open-vm-tools/modules/solaris/vmhgfs/x86cpuid.h
open-vm-tools/modules/solaris/vmxnet/COPYING.CDDL [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet/Makefile [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet/includeCheck.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet/net.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet/net_sg.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet/vm_basic_types.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet/vm_device_version.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet/vmnet_def.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet/vmxnet.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet/vmxnet2_def.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet/vmxnet_def.h [new file with mode: 0644]
open-vm-tools/services/Makefile.am [new file with mode: 0644]
open-vm-tools/services/plugins/COPYING [new file with mode: 0644]
open-vm-tools/services/plugins/Makefile.am [new file with mode: 0644]
open-vm-tools/services/plugins/guestInfo/COPYING [new file with mode: 0644]
open-vm-tools/services/plugins/guestInfo/Makefile.am [new file with mode: 0644]
open-vm-tools/services/plugins/guestInfo/guestInfoInt.h [new file with mode: 0644]
open-vm-tools/services/plugins/guestInfo/guestInfoServer.c [new file with mode: 0644]
open-vm-tools/services/plugins/guestInfo/perfMonLinux.c [new file with mode: 0644]
open-vm-tools/services/plugins/hgfsServer/COPYING [new file with mode: 0644]
open-vm-tools/services/plugins/hgfsServer/Makefile.am [new file with mode: 0644]
open-vm-tools/services/plugins/hgfsServer/hgfsPlugin.c [new file with mode: 0644]
open-vm-tools/services/plugins/powerOps/COPYING [new file with mode: 0644]
open-vm-tools/services/plugins/powerOps/Makefile.am [new file with mode: 0644]
open-vm-tools/services/plugins/powerOps/powerOps.c [new file with mode: 0644]
open-vm-tools/services/plugins/resolutionSet/COPYING [new file with mode: 0644]
open-vm-tools/services/plugins/resolutionSet/Makefile.am [new file with mode: 0644]
open-vm-tools/services/plugins/resolutionSet/libvmwarectrl.c [new file with mode: 0644]
open-vm-tools/services/plugins/resolutionSet/libvmwarectrl.h [new file with mode: 0644]
open-vm-tools/services/plugins/resolutionSet/resolutionInt.h [new file with mode: 0644]
open-vm-tools/services/plugins/resolutionSet/resolutionSet.c [new file with mode: 0644]
open-vm-tools/services/plugins/resolutionSet/resolutionX11.c [new file with mode: 0644]
open-vm-tools/services/plugins/resolutionSet/vmwarectrl.h [new file with mode: 0644]
open-vm-tools/services/plugins/resolutionSet/vmwarectrlproto.h [new file with mode: 0644]
open-vm-tools/services/plugins/timeSync/COPYING [new file with mode: 0644]
open-vm-tools/services/plugins/timeSync/Makefile.am [new file with mode: 0644]
open-vm-tools/services/plugins/timeSync/timeSync.c [new file with mode: 0644]
open-vm-tools/services/plugins/vix/COPYING [new file with mode: 0644]
open-vm-tools/services/plugins/vix/Makefile.am [new file with mode: 0644]
open-vm-tools/services/plugins/vix/foundryToolsDaemon.c [moved from open-vm-tools/guestd/foundryToolsDaemon.c with 100% similarity]
open-vm-tools/services/plugins/vix/foundryToolsDaemon.h [moved from open-vm-tools/guestd/foundryToolsDaemon.h with 100% similarity]
open-vm-tools/services/plugins/vix/vixPlugin.c [new file with mode: 0644]
open-vm-tools/services/plugins/vix/vixPluginInt.h [new file with mode: 0644]
open-vm-tools/services/plugins/vixUser/COPYING [new file with mode: 0644]
open-vm-tools/services/plugins/vixUser/Makefile.am [new file with mode: 0644]
open-vm-tools/services/plugins/vixUser/vixUser.c [new file with mode: 0644]
open-vm-tools/services/plugins/vmbackup/COPYING [new file with mode: 0644]
open-vm-tools/services/plugins/vmbackup/Makefile.am [new file with mode: 0644]
open-vm-tools/services/plugins/vmbackup/README [new file with mode: 0644]
open-vm-tools/services/plugins/vmbackup/scriptOps.c [new file with mode: 0644]
open-vm-tools/services/plugins/vmbackup/stateMachine.c [new file with mode: 0644]
open-vm-tools/services/plugins/vmbackup/syncDriverOps.c [new file with mode: 0644]
open-vm-tools/services/plugins/vmbackup/vmBackupInt.h [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/COPYING [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/Makefile.am [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/cmdLine.c [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/mainLoop.c [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/mainPosix.c [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/pluginMgr.c [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/serviceObj.c [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/serviceObj.h [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/svcSignals.gm [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/toolsCoreInt.h [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/toolsRpc.c [new file with mode: 0644]
open-vm-tools/tests/Makefile.am [new file with mode: 0644]
open-vm-tools/tests/testDebug/COPYING [new file with mode: 0644]
open-vm-tools/tests/testDebug/Makefile.am [new file with mode: 0644]
open-vm-tools/tests/testDebug/testDebug.c [new file with mode: 0644]
open-vm-tools/tests/testPlugin/COPYING [new file with mode: 0644]
open-vm-tools/tests/testPlugin/Makefile.am [new file with mode: 0644]
open-vm-tools/tests/testPlugin/testData.x [new file with mode: 0644]
open-vm-tools/tests/testPlugin/testPlugin.c [new file with mode: 0644]
open-vm-tools/tests/vmrpcdbg/COPYING [new file with mode: 0644]
open-vm-tools/tests/vmrpcdbg/Makefile.am [new file with mode: 0644]
open-vm-tools/tests/vmrpcdbg/debugChannel.c [new file with mode: 0644]
open-vm-tools/tests/vmrpcdbg/vmrpcdbg.c [new file with mode: 0644]
open-vm-tools/toolbox/Makefile.am
open-vm-tools/toolbox/toolbox-cmd.c
open-vm-tools/toolbox/toolbox-gtk.c
open-vm-tools/toolbox/toolboxAbout.c
open-vm-tools/toolbox/toolboxCmdInt.h
open-vm-tools/toolbox/toolboxGtkInt.h
open-vm-tools/toolbox/toolboxInt.c [new file with mode: 0644]
open-vm-tools/toolbox/toolboxInt.h
open-vm-tools/toolbox/toolboxRecord.c [deleted file]
open-vm-tools/toolbox/toolboxScripts.c
open-vm-tools/toolbox/toolboxcmd-record.c [deleted file]
open-vm-tools/toolbox/toolboxcmd-scripts.c
open-vm-tools/vmware-user/Makefile.am
open-vm-tools/vmware-user/copyPaste.cpp [new file with mode: 0644]
open-vm-tools/vmware-user/copyPasteUI.cpp [new file with mode: 0644]
open-vm-tools/vmware-user/copyPasteUI.h [new file with mode: 0644]
open-vm-tools/vmware-user/copyPasteV3.h [deleted file]
open-vm-tools/vmware-user/copyPasteWrapper.cpp [new file with mode: 0644]
open-vm-tools/vmware-user/copyPasteWrapper.h [new file with mode: 0644]
open-vm-tools/vmware-user/dnd.cpp [new file with mode: 0644]
open-vm-tools/vmware-user/foundryToolsDaemon.c [deleted file]
open-vm-tools/vmware-user/foundryToolsDaemon.h [deleted file]
open-vm-tools/vmware-user/stringxx/string.cc [new file with mode: 0644]
open-vm-tools/vmware-user/stringxx/string.hh [new file with mode: 0644]
open-vm-tools/vmware-user/stringxx/ubstr_t.hh [new file with mode: 0644]
open-vm-tools/vmware-user/vmware-user.cpp [moved from open-vm-tools/vmware-user/vmware-user.c with 94% similarity]
open-vm-tools/vmware-user/vmwareuserInt.h

index 27847cde40b4aec5cd4d50850c198bfef0d8c2eb..60bd98279618b7b4d136041d3a767c27414d3190 100644 (file)
-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>
index 4563b0d1e7c659b6798fe8250f62a3087475d43e..dc90b49685611b1255ad87af1b0a0a5cf8e0555f 100644 (file)
@@ -39,15 +39,15 @@ if BUILD_HGFSMOUNTER
 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
index b92a81a5100016cc62048a555a2353daf55739ba..822016ee8aec8625a647ec7b0cbe55f1ff5e7aff 100644 (file)
@@ -1,15 +1,33 @@
+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.
index 8572cc7e402a7d0f8a62388cd84a4f3109d9bbdc..c4e841b072cbec4ffbde2141711f0cc1b7f29928 100644 (file)
 ################################################################################
 # 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
 ################################################################################
 
 ###
@@ -41,7 +37,7 @@
 
 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
@@ -166,13 +162,19 @@ AC_ARG_WITH(
    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
@@ -241,79 +243,85 @@ 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
@@ -404,196 +412,63 @@ else
            # 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".
@@ -602,20 +477,33 @@ else
             [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).])])
 
@@ -642,8 +530,7 @@ AC_CHECK_FUNCS([fcvt])
 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).])])
 
@@ -665,22 +552,21 @@ else
 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
@@ -694,24 +580,38 @@ AC_ARG_WITH([dnet],
            [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
@@ -727,67 +627,34 @@ AC_ARG_WITH([icu],
             [],
             [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(
@@ -941,11 +808,22 @@ done
 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
 
@@ -1017,6 +895,11 @@ if test "$os" = "solaris"; then
       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")
@@ -1030,9 +913,9 @@ AM_CONDITIONAL(WITH_KERNEL_MODULES, test "$with_kernel_modules" = "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
@@ -1065,17 +948,49 @@ fi
 
 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])
@@ -1084,26 +999,15 @@ AC_SUBST([MODULES_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
 
@@ -1122,7 +1026,7 @@ AC_SUBST([LIBVMTOOLS_LIBADD])
 ### Program substs
 
 AC_SUBST([GUESTD_LDADD])
-
+AC_SUBST([VIX_LIBADD])
 AC_SUBST([VMWARE_USER_CPPFLAGS])
 AC_SUBST([VMWARE_USER_LDADD])
 
@@ -1138,6 +1042,7 @@ AC_CONFIG_FILES([                      \
    lib/conf/Makefile                   \
    lib/dict/Makefile                   \
    lib/dnd/Makefile                    \
+   lib/dndGuest/Makefile               \
    lib/dynxdr/Makefile                 \
    lib/err/Makefile                    \
    lib/eventManager/Makefile           \
@@ -1166,6 +1071,7 @@ AC_CONFIG_FILES([                      \
    lib/raster/Makefile                 \
    lib/region/Makefile                 \
    lib/resolution/Makefile             \
+   lib/rpcChannel/Makefile             \
    lib/rpcIn/Makefile                  \
    lib/rpcOut/Makefile                 \
    lib/rpcVmx/Makefile                 \
@@ -1188,6 +1094,17 @@ AC_CONFIG_FILES([                      \
    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                    \
@@ -1199,6 +1116,10 @@ AC_CONFIG_FILES([                      \
    xferlogs/Makefile                   \
    modules/Makefile                    \
    vmblock-fuse/Makefile               \
+   tests/Makefile                      \
+   tests/vmrpcdbg/Makefile             \
+   tests/testDebug/Makefile            \
+   tests/testPlugin/Makefile           \
    scripts/Makefile                   \
 ])
 
index 5cd0780375e026b704e1d4732958c40f5062d2db..23e7f4f1a27cceab5ab8306a241dd628f0d67f25 100644 (file)
@@ -19,6 +19,7 @@ sbin_PROGRAMS = vmware-guestd
 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
@@ -79,7 +80,7 @@ vmware_guestd_SOURCES =
 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
 
@@ -107,4 +108,4 @@ install-exec-hook:
        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
index d12f51f5199cd84385622c22461f756908f17b6f..90d658d38524ae1d166a4c3c4204863d453de4ae 100644 (file)
@@ -56,6 +56,7 @@ extern "C" {
 #include "guestApp.h"
 #include "rpcout.h"
 #include "rpcin.h"
+#include "hostinfo.h"
 #include "strutil.h"
 #include "str.h"
 #include "msg.h"
@@ -840,7 +841,7 @@ ToolsDaemonStateChangeDone(Bool status,  // IN
       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();
          }
       }
@@ -1056,7 +1057,7 @@ ToolsDaemonTcloCapReg(char const **result,     // OUT
     * 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");
    }
@@ -1175,7 +1176,7 @@ ToolsDaemonTcloCapReg(char const **result,     // OUT
 
 #if defined(WIN32)
    HgfsUsability_RegisterServiceCaps();
-   if (System_GetOSType() >= OS_VISTA) {
+   if (Hostinfo_GetOSType() >= OS_VISTA) {
       ServiceHelpers_SendResolutionCaps();
    }
 #endif
index 91cad0cb5c68921dd47cd5bcc4aa51472aeb783c..932287126c7887620c316b5daf0cc3913e7a4ab5 100644 (file)
@@ -30,7 +30,7 @@ mount_vmhgfs_SOURCES += stub-user-util.c
 
 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
@@ -39,7 +39,7 @@ endif WITH_ROOT_PRIVILEGES
        -$(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
@@ -49,5 +49,5 @@ endif 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
index bbf2c8b788e0ade2467f2f56d11ee12c1f14af8b..9a23b9dab52c1736e3ab97198f7a01bbb064f900 100644 (file)
@@ -39,6 +39,7 @@
 #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>
@@ -85,7 +84,7 @@
 #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
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -174,64 +166,6 @@ PrintVersion(void)
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * 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);
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -307,7 +241,8 @@ ParseShareName(const char *shareName,      // IN:  Share name to validate
                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, ':');
@@ -349,27 +284,40 @@ ParseShareName(const char *shareName,      // IN:  Share name to validate
  * 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
@@ -379,7 +327,6 @@ ParseUid(const char *uidString, // IN:  String with uid
       errno = 0;
       myUid = strtoul(uidString, NULL, 10);
       if (errno == 0) {
-         *uid = myUid;
          success = TRUE;
       } else {
          printf("Bad UID value \"%s\"\n", uidString);
@@ -390,14 +337,24 @@ ParseUid(const char *uidString, // IN:  String with uid
       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
 
 /*
  *-----------------------------------------------------------------------------
@@ -405,27 +362,40 @@ ParseUid(const char *uidString, // IN:  String with uid
  * 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
@@ -435,7 +405,6 @@ ParseGid(const char *gidString, // IN:  String with gid
       errno = 0;
       myGid = strtoul(gidString, NULL, 10);
       if (errno == 0) {
-         *gid = myGid;
          success = TRUE;
       } else {
          printf("Bad GID value \"%s\"\n", gidString);
@@ -446,15 +415,258 @@ ParseGid(const char *gidString, // IN:  String with gid
       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 }
+};
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -480,9 +692,10 @@ ParseOptions(const char *optionString, // IN:  Option string to parse
              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);
@@ -502,177 +715,103 @@ ParseOptions(const char *optionString, // IN:  Option string to parse
          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
 /*
@@ -923,6 +1062,8 @@ main(int argc,          // IN
 
    mountInfo.magicNumber = HGFS_SUPER_MAGIC;
    mountInfo.version = HGFS_PROTOCOL_VERSION;
+
+#ifndef sun
    mountInfo.fmask = 0;
    mountInfo.dmask = 0;
    mountInfo.uidSet = FALSE;
@@ -930,6 +1071,7 @@ main(int argc,          // IN
    mountInfo.ttl = HGFS_DEFAULT_TTL;
    mountInfo.shareNameHost = shareNameHost;
    mountInfo.shareNameDir = shareNameDir;
+#endif
 
    /*
     * This'll write the rest of the options into HgfsMountInfo and possibly
@@ -988,6 +1130,9 @@ main(int argc,          // IN
    }
 #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");
index 5a06cdbc1c992d07e40dc231b99ce57b910f86c3..81bcdc48e0ec7946a8e3c970449ca488f413ff6b 100644 (file)
@@ -26,6 +26,9 @@ SUBDIRS += conf
 SUBDIRS += dict
 SUBDIRS += deployPkg
 SUBDIRS += dnd
+if HAVE_GTKMM
+   SUBDIRS += dndGuest
+endif
 SUBDIRS += dynxdr
 SUBDIRS += err
 SUBDIRS += eventManager
@@ -61,6 +64,7 @@ endif
 if HAVE_X11
    SUBDIRS += resolution
 endif
+SUBDIRS += rpcChannel
 SUBDIRS += rpcIn
 SUBDIRS += rpcOut
 SUBDIRS += rpcVmx
index 6dbc534df7a59259e2a763c8a0ce77607c55d5bd..b7139194dbac11c691b11bb0930d574fee87d88a 100644 (file)
@@ -152,40 +152,63 @@ AppUtilCollectNamedIcons(GPtrArray *pixbufs,   // IN/OUT
        */
       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;
+                     }
                   }
                }
             }
index d8fab87dbf9b8d95d330c9512607ef6a7ccb00e2..2661ca0d233961a7c7964aa44fac02af31f57109 100644 (file)
@@ -18,5 +18,7 @@
 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
diff --git a/open-vm-tools/lib/dnd/dndClipboard.c b/open-vm-tools/lib/dnd/dndClipboard.c
new file mode 100644 (file)
index 0000000..08e0703
--- /dev/null
@@ -0,0 +1,638 @@
+/*********************************************************
+ * 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;
+}
diff --git a/open-vm-tools/lib/dnd/dndMsg.c b/open-vm-tools/lib/dnd/dndMsg.c
new file mode 100644 (file)
index 0000000..c297105
--- /dev/null
@@ -0,0 +1,499 @@
+/*********************************************************
+ * 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;
+}
diff --git a/open-vm-tools/lib/dndGuest/Makefile.am b/open-vm-tools/lib/dndGuest/Makefile.am
new file mode 100644 (file)
index 0000000..edbbad9
--- /dev/null
@@ -0,0 +1,35 @@
+################################################################################
+### 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
diff --git a/open-vm-tools/lib/dndGuest/copyPaste.cc b/open-vm-tools/lib/dndGuest/copyPaste.cc
new file mode 100644 (file)
index 0000000..dcec0ff
--- /dev/null
@@ -0,0 +1,391 @@
+/*********************************************************
+ * 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;
+      }
+   }
+}
+
+
diff --git a/open-vm-tools/lib/dndGuest/copyPasteRpcV3.cc b/open-vm-tools/lib/dndGuest/copyPasteRpcV3.cc
new file mode 100644 (file)
index 0000000..d413aa4
--- /dev/null
@@ -0,0 +1,266 @@
+/*********************************************************
+ * 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);
+}
diff --git a/open-vm-tools/lib/dndGuest/dnd.cc b/open-vm-tools/lib/dndGuest/dnd.cc
new file mode 100644 (file)
index 0000000..afb8fda
--- /dev/null
@@ -0,0 +1,727 @@
+/*********************************************************
+ * 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();
+}
+
diff --git a/open-vm-tools/lib/dndGuest/dndFileList.cc b/open-vm-tools/lib/dndGuest/dndFileList.cc
new file mode 100644 (file)
index 0000000..bc0d8ce
--- /dev/null
@@ -0,0 +1,566 @@
+/*********************************************************
+ * 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;
+}
+
diff --git a/open-vm-tools/lib/dndGuest/dndTransportGuestRpc.cc b/open-vm-tools/lib/dndGuest/dndTransportGuestRpc.cc
new file mode 100644 (file)
index 0000000..5bdaa2f
--- /dev/null
@@ -0,0 +1,385 @@
+/*********************************************************
+ * 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;
+   }
+}
index d3b24bdd91fd6fb12823b97b9756287dff991115..792eb4861076cbf5112981a67746055ff3e35e4d 100644 (file)
@@ -69,6 +69,15 @@ typedef struct DynXdrData {
 #  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
+
 
 /*
  *-----------------------------------------------------------------------------
@@ -177,11 +186,16 @@ DynXdrPutInt32(XDR *xdrs,                       // IN/OUT
  */
 
 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);
 }
 
index 65475b8e7eff5261f5d96bca2367418e781f1b4a..b603ac24d6fa63f575c9c401dc8d0ea96c5eb27e 100644 (file)
@@ -49,7 +49,7 @@
 #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>
@@ -1196,8 +1196,8 @@ FileIO_Truncate(FileIODescriptor *file, // IN
  *      Close a file
  *
  * Results:
- *      On success: 0
- *      On failure: non-zero
+ *      TRUE: an error occured
+ *      FALSE: no error occured
  *
  * Side effects:
  *      None
@@ -1205,14 +1205,14 @@ FileIO_Truncate(FileIODescriptor *file, // IN
  *----------------------------------------------------------------------
  */
 
-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);
 
@@ -1221,7 +1221,11 @@ FileIO_Close(FileIODescriptor *file) // IN
    FileIO_Cleanup(file);
    FileIO_Invalidate(file);
 
-   return retval;
+   if (err) {
+      errno = err;
+   }
+
+   return err != 0;
 }
 
 
index 9fa7730da63e57fe62540b5c35cc6322279e9d88..09e3c49d0b442c621e930c3aba441b57340c7566 100644 (file)
@@ -1180,13 +1180,11 @@ MakeDirectory(ConstUnicode pathName)  // IN:
 #if !defined(_WIN32)
    mode_t save;
 
-   ASSERT(pathName);
-
    save = umask(0);
-#else
-   ASSERT(pathName);
 #endif
 
+   ASSERT(pathName);
+
    err = FileCreateDirectoryRobust(pathName);
 
 #if !defined(_WIN32)
@@ -1253,9 +1251,9 @@ CreateEntryDirectory(const char *machineID,    // IN:
 
         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",
index 5745fc5eefa42a86916e9097b77382f688a8b9b7..891b40b5dc3b13b6898b9ea060dab0ef1fa65285 100644 (file)
@@ -1318,13 +1318,13 @@ end:
  *      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.
@@ -2090,8 +2090,8 @@ File_SupportsFileSize(ConstUnicode pathName,  // IN:
     * 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);
@@ -2101,9 +2101,9 @@ File_SupportsFileSize(ConstUnicode pathName,  // IN:
    }
 
    /* 
-    * 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)) {
@@ -2724,10 +2724,11 @@ File_MakeCfgFileExecutable(ConstUnicode 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.
index 0dc1783e933bb3be995e2dfe3d444263b88e7f0c..928b1bdcfb28f810ef931f7a9026a1540502935d 100644 (file)
@@ -451,7 +451,6 @@ VixMsg_AllocResponseMsg(const VixCommandRequestHeader *requestHeader, // IN
    VixCommandResponseHeader *responseHeader;
    size_t totalMessageSize;
 
-   ASSERT(responseBodyLength >= 0);
    ASSERT((NULL != responseBody) || (0 == responseBodyLength));
 
    /*
@@ -518,9 +517,9 @@ VixMsg_InitResponseMsg(VixCommandResponseHeader *responseHeader,     // IN
    size_t responseBodyLength;
 
    ASSERT(NULL != responseHeader);
+   ASSERT(totalMessageSize >= sizeof(VixCommandResponseHeader));
 
    responseBodyLength = totalMessageSize - sizeof(VixCommandResponseHeader);
-   ASSERT(responseBodyLength >= 0);
 
    /*
     * Fill in the response header.
index 16a55e935a8c665fdefb1e12b133cf4c28e477a6..7774f5f82f263ffff51a4d9b29348272f4ad06d8 100644 (file)
@@ -332,8 +332,12 @@ VixPropertyList_Serialize(VixPropertyListImpl    *propList,       // IN
 abort:
    if (VIX_OK != err) {
       free(serializeBuffer);
-      *resultBuffer = NULL;
-      *resultSize = 0;
+      if (NULL != resultBuffer) {
+         *resultBuffer = NULL;
+      }
+      if (NULL != resultSize) {
+         *resultSize = 0;
+      }
    }
 
    return err;
index 6787620457bce11e0e86640a5d58b9cf4ac762d4..fcc60008496f0b88dd89ff70882152ca19e2726c 100644 (file)
@@ -68,6 +68,8 @@ FoundryThreads_StartThread(FoundryThreadProc proc,    // IN
 {
    VixError err = VIX_OK;
    FoundryWorkerThread *threadState = NULL;
+   static const char *createThreadFailureMsg =
+      "%s: thread creation failed with error %d.\n";
 
    ASSERT(proc);
 
@@ -86,6 +88,7 @@ FoundryThreads_StartThread(FoundryThreadProc proc,    // IN
                                             0,
                                             &(threadState->threadId));
    if (NULL == threadState->threadHandle) {
+      Log(createThreadFailureMsg, __FUNCTION__, GetLastError());
       err = VIX_E_OUT_OF_MEMORY;
       goto abort;
    }
@@ -103,6 +106,7 @@ FoundryThreads_StartThread(FoundryThreadProc proc,    // IN
                               FoundryThreadWrapperProc, 
                               threadState);
       if (0 != result) {
+         Log(createThreadFailureMsg, __FUNCTION__, result);
          err = VIX_E_OUT_OF_MEMORY;
          goto abort;
       }
@@ -130,6 +134,7 @@ abort:
  *      None.
  *
  * Side effects:
+ *      May block while the given thread stops.
  *
  *-----------------------------------------------------------------------------
  */
@@ -137,33 +142,35 @@ abort:
 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);
 }
 
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -175,6 +182,7 @@ FoundryThreads_StopThread(FoundryWorkerThread *threadState)    // IN
  *      None.
  *
  * Side effects:
+ *      None.
  *
  *-----------------------------------------------------------------------------
  */
@@ -189,11 +197,12 @@ FoundryThreads_Free(FoundryWorkerThread *threadState)    // IN
 #else
       threadState->threadInfo = 0;
 #endif
-   }
 
-   free(threadState);
+      free(threadState);
+   }
 }
 
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -217,21 +226,10 @@ FoundryThreads_IsCurrentThread(struct FoundryWorkerThread *threadState)     // I
       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;
 }
 
 
@@ -263,10 +261,11 @@ FoundryThreadWrapperProc(void *threadParameter)      // IN
 
    threadState = (FoundryWorkerThread *) threadParameter;
    if (NULL == threadState) {
+      ASSERT(0);
       goto abort;
    }
-   
-   if (NULL != threadState) {
+
+   if (NULL != threadState->threadProc) {
       (*(threadState->threadProc))(threadState);
    }
 
index 5542cd824f2c505728f70c3b6e9711f74114c311..82de723222decf789edf384a3713111bd8aad00d 100644 (file)
@@ -47,8 +47,6 @@ extern "C" {
 #include "dictll.h"
 #include "msg.h"
 #include "file.h"
-#include "dynbuf.h"
-#include "vmstdio.h"
 #include "codeset.h"
 #include "productState.h"
 #include "posix.h"
@@ -1153,86 +1151,6 @@ GuestApp_GetLogPath(void)
 }
 
 
-/*
- *----------------------------------------------------------------------
- *
- * 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
-}
-
-
 /*
  *----------------------------------------------------------------------
  *
index 033c1be4a47846b165a7e1284bef7d4c69215194..8188bacf81d31f9fcbcf9b68c99bc00d22abe527 100644 (file)
@@ -23,13 +23,11 @@ libGuestInfo_la_SOURCES += guestInfoServer.c
 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)
 
index 7f28c68ee5d74f6d69f10aadb1c2c4441ea4c356..7d1c16277a0b57593a9cf88a0e934f7aef9cc00b 100644 (file)
@@ -158,48 +158,6 @@ GuestInfo_GetDiskInfo(PGuestDiskInfo di)     // IN/OUT
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * 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.
index 4da543aa93ba676f2960f0bec4315611a61b790a..de39df73876dbe6a522b64c35abc63c5dc6c7e46 100644 (file)
@@ -35,8 +35,6 @@ Bool GuestInfoGetFqdn(int outBufLen, char fqdn[]);
 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,
index c35f12c54d7ae2756caa4615b19ee96010ca7ef4..838b610486e03051133f07a44e9d0cf4b08dc123 100644 (file)
@@ -65,9 +65,10 @@ GuestInfo_PerfMon(GuestMemInfo *vmStats)   // OUT: filled vmstats
 {
 #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
index 43ddcd813a938789df05c256e925095cad993541..a02a4c40da1e85b91d4da0e0e5307611b6a40c00 100644 (file)
 #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},
-};
-
-
 
 /*
  *-----------------------------------------------------------------------------
@@ -319,456 +253,3 @@ GuestInfoGetNicInfo(GuestNicList *nicInfo)   // OUT
    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;
-}
index 076fca4bad3f70771e3f1c4486353d72e7476a44..3bb8064b6a8d1a3dc8c04a834be8e44e648ca7c2 100644 (file)
@@ -41,6 +41,7 @@
 #include "util.h"
 #include "rpcout.h"
 #include "rpcvmx.h"
+#include "hostinfo.h"
 #include "guestInfo.h"
 #include "guestApp.h"
 #include "guestInfoServer.h"
@@ -253,7 +254,8 @@ GuestInfoGather(void *clientData)   // IN: unused
    }
 
    /* 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)) {
index 27cde3ca3bec6b37310d5af083d8ec57ec95a2ea..7fc685fb1a0bb0fcc9cbdad0dc3405499c24900f 100644 (file)
@@ -60,67 +60,67 @@ clean-local:
 # 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
+
index dbf5c6ff1ddf65d6e86921bd5f22de45f7aeafaf..07bfd7c4e42a1974830ce6559fea1df4f3656670 100644 (file)
@@ -66,10 +66,12 @@ enum GuestLibV3TypeIds {
    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) {
@@ -113,5 +115,10 @@ 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;
 };
 
index d76220d3d3fce1a1eb32bd213f4d1cef04200b32..f79fff01ae920f06fa70c9cebc09af9a2b038608 100644 (file)
@@ -4404,6 +4404,7 @@ HgfsPackGetattrReply(HgfsFileAttrInfo *attr,     // IN: attr stucture
       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;
index 3a9036e7ba13872d619e2a01d80f6adf52bc483b..7dd21f4aa7f230a5622b154a813b4ca88bfc4375 100644 (file)
@@ -283,6 +283,7 @@ typedef struct HgfsFileAttrInfo {
    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 {
index 0213463d9c18a536f3bfe6b19293bc3ccd46341e..2ecb15a62ed55daa86e5527c1a4fa3ca5c081a67 100644 (file)
@@ -333,7 +333,9 @@ static HgfsInternalStatus HgfsSetattrFromName(char *cpName,
 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
 /*
  *-----------------------------------------------------------------------------
@@ -1196,6 +1198,8 @@ HgfsGetattrResolveAlias(char const *fileName,       // IN:  Input filename
    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
@@ -1205,7 +1209,7 @@ HgfsGetattrResolveAlias(char const *fileName,       // IN:  Input filename
    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;
    }
    /*
@@ -1225,7 +1229,7 @@ HgfsGetattrResolveAlias(char const *fileName,       // IN:  Input filename
                                                &wasAliased, kResolveAliasFileNoUI);
    if (osStatus != noErr) {
       LOG(4, ("HgfsGetattrResolveAlias: could not resolve reference: error "
-              "%lu\n", osStatus));
+              "%d\n", (int32)osStatus));
       goto exit;
    }
 
@@ -1776,6 +1780,42 @@ HgfsServerCaseConversionRequired()
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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;
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -1786,6 +1826,12 @@ HgfsServerCaseConversionRequired()
  *    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.
@@ -1954,6 +2000,22 @@ HgfsGetattrFromName(char *fileName,                    // IN/OUT:  Input filenam
     */
    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;
@@ -3677,15 +3739,18 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet
 
          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,
index ac09bf5e9d20beda68148d49a158f8d426a392f1..7bb991ad42cf0834df509c10dfc1ca5964535327 100644 (file)
 #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,
index 343be2ca8947c4215fd7f59f7e5c58ce2adceaca..7161abd07f0cf973fb900ac3234d9156499b3791 100644 (file)
@@ -1,12 +1,12 @@
 #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"
diff --git a/open-vm-tools/lib/include/copyPaste.hh b/open-vm-tools/lib/include/copyPaste.hh
new file mode 100644 (file)
index 0000000..721c894
--- /dev/null
@@ -0,0 +1,75 @@
+/*********************************************************
+ * 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
+
diff --git a/open-vm-tools/lib/include/copyPasteBase.h b/open-vm-tools/lib/include/copyPasteBase.h
new file mode 100644 (file)
index 0000000..ccd8b4b
--- /dev/null
@@ -0,0 +1,82 @@
+/*********************************************************
+ * 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
+
diff --git a/open-vm-tools/lib/include/copyPasteRpc.hh b/open-vm-tools/lib/include/copyPasteRpc.hh
new file mode 100644 (file)
index 0000000..0b33d50
--- /dev/null
@@ -0,0 +1,50 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/lib/include/copyPasteRpcV3.hh b/open-vm-tools/lib/include/copyPasteRpcV3.hh
new file mode 100644 (file)
index 0000000..19d8904
--- /dev/null
@@ -0,0 +1,49 @@
+/*********************************************************
+ * 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
index cec0cabd14788d987bda36a65b217e15f985c296..161f7001073bf2773d74ed2dfef6b96b6d2e43fd 100644 (file)
 
 #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
diff --git a/open-vm-tools/lib/include/dnd.hh b/open-vm-tools/lib/include/dnd.hh
new file mode 100644 (file)
index 0000000..816a35a
--- /dev/null
@@ -0,0 +1,94 @@
+/*********************************************************
+ * 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
+
diff --git a/open-vm-tools/lib/include/dndBase.h b/open-vm-tools/lib/include/dndBase.h
new file mode 100644 (file)
index 0000000..2c2b649
--- /dev/null
@@ -0,0 +1,121 @@
+/*********************************************************
+ * 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
+
diff --git a/open-vm-tools/lib/include/dndClipboard.h b/open-vm-tools/lib/include/dndClipboard.h
new file mode 100644 (file)
index 0000000..d7098bb
--- /dev/null
@@ -0,0 +1,112 @@
+/*********************************************************
+ * 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_
diff --git a/open-vm-tools/lib/include/dndFileContentsUtil.h b/open-vm-tools/lib/include/dndFileContentsUtil.h
new file mode 100644 (file)
index 0000000..9ec6b7f
--- /dev/null
@@ -0,0 +1,68 @@
+/*********************************************************
+ * 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_
diff --git a/open-vm-tools/lib/include/dndFileList.hh b/open-vm-tools/lib/include/dndFileList.hh
new file mode 100644 (file)
index 0000000..e430350
--- /dev/null
@@ -0,0 +1,76 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/lib/include/dndMsg.h b/open-vm-tools/lib/include/dndMsg.h
new file mode 100644 (file)
index 0000000..5b72cde
--- /dev/null
@@ -0,0 +1,148 @@
+/*********************************************************
+ * 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_ */
diff --git a/open-vm-tools/lib/include/dndRpc.hh b/open-vm-tools/lib/include/dndRpc.hh
new file mode 100644 (file)
index 0000000..76f2cc7
--- /dev/null
@@ -0,0 +1,62 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/lib/include/dndRpcV3.hh b/open-vm-tools/lib/include/dndRpcV3.hh
new file mode 100644 (file)
index 0000000..34e12fc
--- /dev/null
@@ -0,0 +1,64 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/lib/include/dndTransport.hh b/open-vm-tools/lib/include/dndTransport.hh
new file mode 100644 (file)
index 0000000..5061fa3
--- /dev/null
@@ -0,0 +1,45 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/lib/include/dndTransportGuestRpc.hh b/open-vm-tools/lib/include/dndTransportGuestRpc.hh
new file mode 100644 (file)
index 0000000..cb26f55
--- /dev/null
@@ -0,0 +1,62 @@
+/*********************************************************
+ * 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
index eb94bde52eb3b306025104d41b4fe0546d73a25f..4998d886c21db376510680de025a61c0552e4e49 100644 (file)
@@ -329,7 +329,7 @@ Bool    FileIO_SetAllocSize(const FileIODescriptor *fd, uint64 size);
 
 int64   FileIO_GetSizeByPath(ConstUnicode pathName);
 
-int     FileIO_Close(FileIODescriptor *file);
+Bool    FileIO_Close(FileIODescriptor *file);
 
 uint32  FileIO_GetFlags(FileIODescriptor *file);
 
index 141d8c10d48cd2c58811116280c765e7b70c9f7f..423a63dc05b7a63b69636c660f78bf64e38b6a52 100644 (file)
@@ -116,9 +116,6 @@ GuestApp_GetConfPath(void);
 char *
 GuestApp_GetLogPath(void);
 
-char *
-GuestApp_GetCmdOutput(const char *cmd); // IN
-
 Bool
 GuestApp_IsHgfsCapable(void);
 
index 6496b197707a153cd3cb6d3cdbbf62f826f462ca..e87ad991090ef82bda286bb74dbfb5690edfcb15 100644 (file)
@@ -72,13 +72,15 @@ typedef enum GuestOSType {
    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;
 
 
@@ -131,10 +133,12 @@ typedef enum GuestOSFamilyType {
                          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))
 
 
 /*
@@ -267,6 +271,14 @@ typedef enum GuestOSFamilyType {
 #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"
@@ -275,8 +287,18 @@ typedef enum GuestOSFamilyType {
 #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"
@@ -289,12 +311,24 @@ typedef enum GuestOSFamilyType {
 #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"
index 4c0537007ea793eb7b18fcd2dae209f8c32a2ec8..5dccac0deddad12ab09d2016795ef3769f2cc221 100644 (file)
@@ -178,6 +178,55 @@ typedef uint8 HgfsPermissions;
 #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).
@@ -356,6 +405,15 @@ typedef uint64 HgfsAttrValid;
  *       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)
 
 
 /*
@@ -400,7 +458,7 @@ struct HgfsAttrV2 {
    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"
index 11bc7a5ac2998c835e6bf20950a30c9aea74f24c..f641683f48a865c7a03bdd59c8225b878f5dc80b 100644 (file)
@@ -62,6 +62,12 @@ extern VmTimeType Hostinfo_SystemTimerUS(void);
 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);
@@ -117,6 +123,44 @@ extern Bool Hostinfo_HTDisabled(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);
diff --git a/open-vm-tools/lib/include/libExport.hh b/open-vm-tools/lib/include/libExport.hh
new file mode 100644 (file)
index 0000000..d7bb01e
--- /dev/null
@@ -0,0 +1,53 @@
+/*********************************************************
+ * 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
index 43efb4f74105b6944ef94d17b5bf31fdbefb1428..e8e81b1db9bbc1d05f2ebe7187af317b8f0aebbf 100644 (file)
@@ -29,8 +29,6 @@
 
 typedef void (LogBasicFunc)(const char *fmt, va_list args);
 
-struct LogState;
-
 typedef struct
 {
    const char *fileName;             // File name, if known
index 7d391b34973d3d44eee81416fcac7fcbffb5358d..809c539683cf90d7fce606a5463bceb4f031ee74 100644 (file)
@@ -67,7 +67,7 @@
 #   undef Bool
 typedef Display *       InitHandle;
 
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) || defined(RESOLUTION_WIN32)
 typedef void *          InitHandle;
 #else
 #   error Unknown display backend
diff --git a/open-vm-tools/lib/include/rpcChannel.h b/open-vm-tools/lib/include/rpcChannel.h
new file mode 100644 (file)
index 0000000..7ff672f
--- /dev/null
@@ -0,0 +1,175 @@
+/*********************************************************
+ * 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
+
index 2c68daeb3da43bd265f244ff2197c4422c6157bb..5e8ed6048551e6bf37b596d5f6d60d107c5a7bb5 100644 (file)
@@ -43,44 +43,10 @@ Bool System_IsACPI(void);
 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.
@@ -96,8 +62,6 @@ typedef struct {
 #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);
index f2bad872bc737729442be5a7fd066f6882b08689..6ae892ff05c4f0e2fe196532c9c6593aab9154ee 100644 (file)
@@ -119,6 +119,6 @@ EXTERN Bool TimeUtil_UTCTimeToSystemTime(const __time64_t utcTime,    // IN
                                          SYSTEMTIME *systemTime);     // OUT
 #endif
 
-EXTERN int TimeUtil_GetLocalWindowsTimeZoneIndex(void);
+EXTERN int TimeUtil_GetLocalWindowsTimeZoneIndexAndName(char **ptzName);
 
 #endif // _TIMEUTIL_H_
index 2cb40240b25b28329a01b8176735f4c67493bc9b..999c5d844477e644ba472ff7871973cb004589c0 100644 (file)
@@ -161,6 +161,7 @@ enum {
    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,
@@ -301,6 +302,7 @@ enum {
    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,
index e3850fb68b559cea589b3d22c926c450fc8e35d8..012c56138ff4e286b14239effd1ad23767f74cc3 100644 (file)
@@ -396,8 +396,10 @@ enum {
 #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);
 
@@ -406,6 +408,7 @@ 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
@@ -424,6 +427,7 @@ extern void VixAssert(const char *cond, const char *file, int lineNum);
 #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; \
@@ -431,7 +435,7 @@ extern void VixAssert(const char *cond, const char *file, int lineNum);
            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); \
@@ -442,6 +446,14 @@ extern void VixAssert(const char *cond, const char *file, int lineNum);
            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
index 809ed0e643d909f1e5dc00354d591506e593873e..6766ed53bdaeba0c005e92c5761d42a39d8f9598 100644 (file)
@@ -366,6 +366,20 @@ VMGuestLibError VMGuestLib_GetResourcePoolPath(VMGuestLibHandle handle, // IN
                                                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
 }
index 970bc700f5b33baa800971d1bd59d8c67f50064f..c98e39d54413d28e2911bfd15fcc9daae0bd4417 100644 (file)
@@ -83,10 +83,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index 763604b86d99b17bb656c773478ee95daee7306f..77260c79e7349e2330dd665d4fc5a4463302acbf 100644 (file)
@@ -196,10 +196,29 @@ static INLINE void
 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
 }
 
 
index 3032179f8da35c04ebc7b9e496ff55461c0f780c..9d43452c18abbc9cd570749a6f36f8ed735dc54e 100644 (file)
@@ -853,4 +853,21 @@ RDTSC(void)
 #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
index c4b9bbda006a159801ab771d1796fa63c30a1cc2..b1503b5d47a4d1f8824679f4494a2f46d6c943a0 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index eaefc1caa6db1fc3b0f947b0ab2e1fa2a3fc9ec1..8b1a01621411ab70d4291af6205f168f86f4a455 100644 (file)
 /*
  * 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"
diff --git a/open-vm-tools/lib/include/vmrpcdbg.h b/open-vm-tools/lib/include/vmrpcdbg.h
new file mode 100644 (file)
index 0000000..b906f9a
--- /dev/null
@@ -0,0 +1,183 @@
+/*********************************************************
+ * 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_ */
+
diff --git a/open-vm-tools/lib/include/vmtoolsApp.h b/open-vm-tools/lib/include/vmtoolsApp.h
new file mode 100644 (file)
index 0000000..ddc193f
--- /dev/null
@@ -0,0 +1,317 @@
+/*********************************************************
+ * 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_ */
+
diff --git a/open-vm-tools/lib/include/vmtoolsd_version.h b/open-vm-tools/lib/include/vmtoolsd_version.h
new file mode 100644 (file)
index 0000000..0c6c587
--- /dev/null
@@ -0,0 +1,27 @@
+/*********************************************************
+ * 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_ */
+
index ba534c9a48c4eea7fefdc73fa579236e3cbf14f5..38c2058ac850cb4d8e33837e1020f899e34ebba1 100644 (file)
@@ -440,7 +440,7 @@ FLAGDEF(  87, EDX, AMD,     4,  1, TM,                  NA,  IGNORE, 0, FALSE)
 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) \
@@ -644,6 +644,9 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #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)
+
 /*
  *----------------------------------------------------------------------
  *
@@ -815,6 +818,17 @@ CPUID_FAMILY_IS_K8STAR(uint32 _eax)
           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
index cd26d0aa183eca6ce6429839a85cfc2eddac414f..fc8931fb3715876ef86e1822679022fa7a768876 100644 (file)
 #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"
@@ -54,6 +58,71 @@ static Bool hostinfoOSVersionInitialized;
 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},
+};
+
 
 /*
  *----------------------------------------------------------------------
@@ -256,3 +325,531 @@ Hostinfo_GetSystemBitness(void)
    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;
+}
+
index 70d13448a8f3dee67b0a82b1d1c05f3967101073..badc1bbe219c184e53d21e45897a7c81548f6afe 100644 (file)
@@ -412,8 +412,9 @@ IdAuthCreate(void)
          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;
          }
       }
index d1b965ef59c0c65160a6c13f82af0a4ee8b60241..79cba7afbab3ce96e95b99e95fff5fbaefbac3af 100644 (file)
@@ -24,6 +24,7 @@
 
 
 #include "safetime.h"
+#include "unicode.h"
 
 #if defined(N_PLAT_NLM)
 #  include <sys/timeval.h>
@@ -78,10 +79,10 @@ static Bool TimeUtilIsValidDate(unsigned int year, unsigned int month, unsigned
 
 
 /*
- * 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)
 /*
@@ -953,9 +954,9 @@ TimeUtil_UTCTimeToSystemTime(const __time64_t utcTime,   // IN
 /*
  *----------------------------------------------------------------------
  *
- * 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
@@ -968,71 +969,78 @@ TimeUtil_UTCTimeToSystemTime(const __time64_t utcTime,   // IN
  *----------------------------------------------------------------------
  */
 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;
@@ -1234,15 +1242,11 @@ TimeUtilLoadDate(TimeUtil_Date *d,  // IN/OUT
 /*
  *----------------------------------------------------------------------
  *
- * 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.
@@ -1252,96 +1256,110 @@ TimeUtilLoadDate(TimeUtil_Date *d,  // IN/OUT
  *
  *----------------------------------------------------------------------
  */
-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;
       }
    }
 
index d3fd0d98b86b209f97e1ef184e4ad26744b0d195..55f6c94cc631ada152447e8aad0d63bd5ed7c73a 100644 (file)
@@ -315,9 +315,11 @@ Bool
 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;
    }
 
diff --git a/open-vm-tools/lib/rpcChannel/Makefile.am b/open-vm-tools/lib/rpcChannel/Makefile.am
new file mode 100644 (file)
index 0000000..96e956a
--- /dev/null
@@ -0,0 +1,25 @@
+################################################################################
+### 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@
diff --git a/open-vm-tools/lib/rpcChannel/bdoorChannel.c b/open-vm-tools/lib/rpcChannel/bdoorChannel.c
new file mode 100644 (file)
index 0000000..24879bc
--- /dev/null
@@ -0,0 +1,246 @@
+/*********************************************************
+ * 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;
+}
+
diff --git a/open-vm-tools/lib/rpcChannel/rpcChannel.c b/open-vm-tools/lib/rpcChannel/rpcChannel.c
new file mode 100644 (file)
index 0000000..9cedd0f
--- /dev/null
@@ -0,0 +1,511 @@
+/*********************************************************
+ * 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(&copy, data, sizeof copy);
+   }
+
+   ret = rpc->callback(&copy);
+
+   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);
+   }
+}
+
diff --git a/open-vm-tools/lib/rpcChannel/rpcChannelInt.h b/open-vm-tools/lib/rpcChannel/rpcChannelInt.h
new file mode 100644 (file)
index 0000000..f58f046
--- /dev/null
@@ -0,0 +1,35 @@
+/*********************************************************
+ * 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_ */
+
index 2965aa9a11a878311e13fbeef5426231d4792b7e..c7c7ccaaf9889c3c2d3de3a135ed4dceae260054 100644 (file)
@@ -24,12 +24,10 @@ libStubs_la_SOURCES += stub-warning.c
 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
 
index d57d478f9207f627d00e6a42861547e9f6743db0..8c5327e7b48815b4c3054f10949a56599f07436f 100644 (file)
@@ -658,8 +658,8 @@ System_IsUserAdmin(void)
  */
 
 char *
-System_GetEnv(Bool global,       // IN
-              char *valueName)   // IN: UTF-8
+System_GetEnv(Bool global,           // IN
+              const char *valueName) // IN: UTF-8
 {
    char *result;
    
@@ -698,8 +698,8 @@ System_GetEnv(Bool global,       // IN
 
 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);
index 46f8e733321b312545f1a65b7a2d0812efe6e768..839f3f5705ea6cb7262004d88df7092ed0ae5874 100644 (file)
@@ -452,6 +452,15 @@ UPWindowSetWindows(UnityPlatform *up,        // IN
       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
@@ -490,6 +499,10 @@ UPWindowSetWindows(UnityPlatform *up,        // IN
 #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
 
@@ -1711,7 +1724,6 @@ UnityPlatformArgvToWindowPaths(UnityPlatform *up,        // IN
    int numQueryArgs;
    int i;
    int err;
-   char *ctmp = NULL;
    char **argv;
    char *windowQueryString = NULL;
    char *execQueryString = NULL;
@@ -1736,6 +1748,7 @@ UnityPlatformArgvToWindowPaths(UnityPlatform *up,        // IN
    }
 
    if (argv[0][0] != '/') {
+      char *ctmp = NULL;
       if ((ctmp = AppUtil_CanonicalizeAppName(argv[0], cwd))) {
          char **newArgv;
          newArgv = alloca(argc * sizeof argv[0]);
@@ -2532,6 +2545,31 @@ UPWindowUpdateShape(UnityPlatform *up,        // IN
    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);
 
    /*
index 87df639f99ef56a4f5f7823887861e947243a93b..8507f590ae13364e84f46b779ff43c530bec8efd 100644 (file)
@@ -811,7 +811,8 @@ VixTools_GetToolsPropertiesImpl(GuestApp_Dict **confDictRef,      // IN
 #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;
    }
index d35afa82864983eb19c7c0cd9833b482db041bc6..2b61e4415b1313ff14622cbd57eb0863911d0e2a 100644 (file)
@@ -206,7 +206,7 @@ VmCheck_IsVirtualWorld(void)
    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;
    }
index bd23c2821fbf8909a5a540f26706f42df549016d..eb7ae956b7e6c9e121fc55455a437f00c47fad6b 100644 (file)
@@ -180,16 +180,17 @@ static INLINE Bool
 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;
    }
 
index d9cbf1c4fb04511f76d1ea79cf736233a927d2cf..0481b2584b366fe557d96a07b3784139e6919ce8 100644 (file)
@@ -1252,3 +1252,61 @@ VMGuestLib_GetResourcePoolPath(VMGuestLibHandle handle, // IN
 
    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;
+}
+
+
index b665b1f4258d90209b798f9ce20cffc0f83fdc56..9e5cafe0f9fc94ecac346ff152e8f9c8c8a369c3 100644 (file)
@@ -26,13 +26,19 @@ libvmtools_la_LIBADD += ../lib/err/libErr.la
 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
index 1711a2f87128aef010cb62d4fa0b15f180032c1e..dfe26d063c9157126ce4b711a6d38108c20b24fc 100644 (file)
@@ -124,6 +124,7 @@ VMToolsConfigUpgrade(GuestApp_Dict *old,
       { 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
index b4bbcb25d6ad7abce88b0f6fe1bc0b198c4d19db..40dd1748a197ad7d51d3e02c3c146265c6065425 100644 (file)
@@ -213,13 +213,16 @@ VMToolsLogFormat(const gchar *message,
        * 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;
 }
 
 
diff --git a/open-vm-tools/m4/COPYING b/open-vm-tools/m4/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/m4/vmtools.m4 b/open-vm-tools/m4/vmtools.m4
new file mode 100644 (file)
index 0000000..bff29c2
--- /dev/null
@@ -0,0 +1,210 @@
+################################################################################
+### 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++])
+])
+
index 41e16582b25ecc26bc00c54a62c26445cfc26a51..ab996be721418af616958c7c00713f204d5382f0 100644 (file)
@@ -6,7 +6,8 @@ modules: $(MODULES)
 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
@@ -23,14 +24,6 @@ export DEPMOD := depmod -a
 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
@@ -48,19 +41,27 @@ endif
 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          \
@@ -71,6 +72,6 @@ endif
 
 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"
index 48519d2c2d930f96f8f94793a682fe3695fffc3a..7fdaf824fb5b3fc4334b2a6a2df9b67f9addbcb6 100644 (file)
@@ -95,10 +95,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index 4c8255f7082ed229f264b278271a325fd27d6078..54a3b44773c58163461ed8b1503c2616303764e9 100644 (file)
@@ -350,6 +350,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -501,10 +504,11 @@ typedef uint64 MPN64;
  */
 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
index b902e6eb2285b5ea5c0fd3b6964be07db373ad70..84a44f063d9055018e9232758b4222110d0a0f3f 100644 (file)
 #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,
index b3ce70382d10d67f3a87a92f4eda886014872527..925a287c5eb754430f8e9cb897bd964d0a880810 100644 (file)
@@ -178,6 +178,55 @@ typedef uint8 HgfsPermissions;
 #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).
@@ -356,6 +405,15 @@ typedef uint64 HgfsAttrValid;
  *       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)
 
 
 /*
@@ -400,7 +458,7 @@ struct HgfsAttrV2 {
    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"
index 6c443265fbb98b04e9e7407cabb654a9fe2895c7..3757177fa0402f3b0a672165d663bd8b860d50be 100644 (file)
 #   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);
index 7aee00aeae362a9bd70cbd2bbc3674b9e6c789ed..476f5d4d0f84f218b2fe61f42292128030773260 100644 (file)
 #  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"
@@ -861,3 +864,56 @@ os_path_to_utf8_precomposed(char const *bufIn,  // IN
    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;
+}
index 6f7e8febac671caf3d9e8a74294bafd7a36b7a0b..151a9d3716cd7baa2d72316f8aa85780ebb321a1 100644 (file)
 /*
  * 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_
@@ -126,5 +128,8 @@ extern int os_path_to_utf8_precomposed(const char *bufIn, uint32 bufInSize, char
                                        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_
index 64ae6727121061ba554ce75129c2087e4c071c0c..f5034000ac5647d659314647eb8d519ed5f75ac4 100644 (file)
@@ -82,12 +82,13 @@ static int HgfsVnodeGetInt(struct vnode **vpp,
                            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,
@@ -95,7 +96,7 @@ 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 */
@@ -145,10 +146,11 @@ HgfsVnodeGet(struct vnode **vpp,        // OUT: Filled with address of created v
              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);
 }
 
 
@@ -178,7 +180,8 @@ HgfsVnodeGetRoot(struct vnode **vpp,      // OUT: Filled with address of created
                 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);
 }
 
 
@@ -430,7 +433,7 @@ HgfsFileHashTableIsEmpty(HgfsSuperInfo *sip,            // IN: Superinfo
  * 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.
@@ -440,10 +443,11 @@ HgfsFileHashTableIsEmpty(HgfsSuperInfo *sip,            // IN: Superinfo
 
 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);
 
@@ -453,9 +457,29 @@ HgfsCheckAndReferenceHandle(struct vnode *vp,       // IN: Vnode to check handle
    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);
       }
    }
 
@@ -485,7 +509,8 @@ HgfsCheckAndReferenceHandle(struct vnode *vp,       // IN: Vnode to check handle
 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;
 
@@ -497,6 +522,7 @@ HgfsSetOpenFileHandle(struct vnode *vp,          // IN: Vnode to set handle for
    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);
@@ -560,6 +586,7 @@ HgfsGetOpenFileHandle(struct vnode *vp,          // IN:  Vnode to get handle for
  *      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.
@@ -568,10 +595,11 @@ HgfsGetOpenFileHandle(struct vnode *vp,          // IN:  Vnode to get handle for
  */
 
 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);
@@ -582,21 +610,25 @@ HgfsReleaseOpenFileHandle(struct vnode *vp,            // IN
    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;
@@ -638,6 +670,7 @@ HgfsLookupExistingVnode(const char* fileName,
    /* 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 {
@@ -694,7 +727,8 @@ HgfsVnodeGetInt(struct vnode **vpp,        // OUT:  Filled with address of creat
                 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;
@@ -762,7 +796,7 @@ HgfsVnodeGetInt(struct vnode **vpp,        // OUT:  Filled with address of creat
    }
 
    /* 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;
@@ -821,7 +855,8 @@ HgfsVnodeGetInt(struct vnode **vpp,        // OUT
                 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;
@@ -842,13 +877,13 @@ HgfsVnodeGetInt(struct vnode **vpp,        // OUT
    }
 
    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;
@@ -884,7 +919,7 @@ HgfsVnodeGetInt(struct vnode **vpp,        // OUT
       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) {
@@ -958,7 +993,8 @@ HgfsAllocFile(const char *fileName,         // IN: Name of file
               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);
@@ -966,7 +1002,7 @@ HgfsAllocFile(const char *fileName,         // IN: Name of file
    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;
@@ -1001,7 +1037,7 @@ HgfsAllocFile(const char *fileName,         // IN: Name of file
 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;
 
@@ -1015,21 +1051,21 @@ HgfsInsertFile(const char *fileName,       // IN: Filename to get file for
    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);
    }
 
@@ -1100,7 +1136,8 @@ HgfsInitFile(HgfsFile *fp,              // IN: File to initialize
              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;
 
@@ -1137,6 +1174,9 @@ HgfsInitFile(HgfsFile *fp,              // IN: File to initialize
 
    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) {
@@ -1205,7 +1245,7 @@ destroyOut:
  */
 
 void
-HgfsFreeFile(HgfsFile *fp)
+HgfsFreeFile(HgfsFile *fp)   // IN: HgfsFile structure to free
 {
    ASSERT(fp);
    os_rw_lock_free(fp->handleLock);
@@ -1220,6 +1260,33 @@ HgfsFreeFile(HgfsFile *fp)
    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 */
 
 
@@ -1504,3 +1571,34 @@ HgfsIsModeCompatible(HgfsMode requestedMode,   // IN: Requested open mode
            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);
+   }
+}
index f897437ca6a372c49f3a2cc3f4a469b56ccd5546..f0caa6aaeee876c0cb29f0582ccc6d9ef265f549 100644 (file)
 #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
@@ -146,6 +152,20 @@ typedef struct HgfsFile {
    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. */
@@ -159,7 +179,8 @@ struct HgfsSuperInfo;
 
 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);
@@ -170,10 +191,12 @@ void HgfsDestroyFileHashTable(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_ */
index 2e70ae1fedee2456635335c3d1d0f9f773239ab1..d6bb8f7dbff72f46b559624fa6c19cb2b470e4ea 100644 (file)
@@ -83,10 +83,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index 5bc4d6b711ced2483232ec4c4fc445155c9e86ab..0180e391909505fb5f244d9f7bf03ec8f976319a 100644 (file)
@@ -853,4 +853,21 @@ RDTSC(void)
 #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
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index a958b58aeeb15fe911e9612f90592d2898ef5548..15f3c1650fbeb4179f125034a060ce78d17225c7 100644 (file)
@@ -216,7 +216,7 @@ struct vop_open_args {
    struct vnode *vp = ap->a_vp;
    int mode = ap->a_mode;
 
-   return HgfsOpenInt(vp, mode);
+   return HgfsOpenInt(vp, mode, FALSE);
 }
 
 
@@ -326,8 +326,30 @@ struct vop_access_args {
 {
    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);
 }
 
 
@@ -433,7 +455,7 @@ struct vop_read_args {
    struct vnode *vp = ap->a_vp;
    struct uio *uiop = ap->a_uio;
 
-   return HgfsReadInt(vp, uiop);
+   return HgfsReadInt(vp, uiop, FALSE);
 }
 
 
@@ -469,7 +491,7 @@ struct vop_write_args {
    struct uio *uiop = ap->a_uio;
    int ioflag = ap->a_ioflag;
 
-   return HgfsWriteInt(vp, uiop, ioflag);
+   return HgfsWriteInt(vp, uiop, ioflag, FALSE);
 }
 
 
index 072359a3fe61a753f87d64b8dd4146856f5b3456..b48699e53c8c3acc2cbef90dd34de7f52d229871 100644 (file)
@@ -39,7 +39,7 @@ int HgfsGetNextDirEntry(HgfsSuperInfo *sip, HgfsHandle handle,
                                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,
@@ -474,11 +474,9 @@ HgfsGetattrInt(struct vnode *vp,      // IN : vnode of the file
  *
  * 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.
  *
@@ -490,7 +488,7 @@ HgfsGetattrInt(struct vnode *vp,      // IN : vnode of the file
 
 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;
@@ -581,6 +579,10 @@ HgfsSetattrInt(struct vnode *vp,     // IN : vnode of the file
          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:
@@ -644,8 +646,6 @@ HgfsRmdirInt(struct vnode *dvp,          // IN: parent directory
  *      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.
  *
@@ -672,6 +672,9 @@ int HgfsRemoveInt(struct vnode *vp) // IN: Vnode to delete
       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);
 
@@ -763,7 +766,8 @@ HgfsCloseInt(struct vnode *vp, // IN: Vnode to close.
 
 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));
@@ -782,7 +786,7 @@ HgfsOpenInt(struct vnode *vp, // IN: Vnode to open.
           * 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:
@@ -863,7 +867,7 @@ HgfsLookupInt(struct vnode *dvp,         // IN : directory vnode
       *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.
@@ -936,7 +940,8 @@ HgfsLookupInt(struct vnode *dvp,         // IN : directory vnode
                       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);
@@ -1020,9 +1025,23 @@ int HgfsCreateInt(struct vnode *dvp,         // IN : Directory vnode
    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;
@@ -1063,7 +1082,8 @@ int HgfsCreateInt(struct vnode *dvp,         // IN : Directory vnode
 
 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;
@@ -1073,9 +1093,9 @@ HgfsReadInt(struct vnode *vp, // IN    : Vnode to read from
    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 */
@@ -1094,9 +1114,18 @@ HgfsReadInt(struct vnode *vp, // IN    : Vnode to read from
     */
    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
@@ -1119,7 +1148,8 @@ HgfsReadInt(struct vnode *vp, // IN    : Vnode to read from
             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);
@@ -1158,10 +1188,6 @@ HgfsReadInt(struct vnode *vp, // IN    : Vnode to read from
  *      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.
  *
@@ -1173,13 +1199,15 @@ HgfsReadInt(struct vnode *vp, // IN    : Vnode to read from
 
 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);
 
@@ -1207,6 +1235,11 @@ HgfsWriteInt(struct vnode *vp, // IN    : the vnode of the file
       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
@@ -1233,7 +1266,8 @@ HgfsWriteInt(struct vnode *vp, // IN    : the vnode of the file
           * 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. */
@@ -1241,10 +1275,20 @@ HgfsWriteInt(struct vnode *vp, // IN    : the vnode of the file
 
    } 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;
 }
 
 
@@ -1379,7 +1423,8 @@ HgfsMkdirInt(struct vnode *dvp,         // IN : directory vnode
    }
 
    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;
@@ -1440,7 +1485,7 @@ HgfsDirOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
     *  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)) {
@@ -1457,7 +1502,7 @@ HgfsDirOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
           * 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);
@@ -1491,7 +1536,8 @@ int
 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;
@@ -1549,7 +1595,7 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
     *  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;
@@ -1569,7 +1615,7 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
             * 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);
@@ -1581,14 +1627,14 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
        * 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;
 }
 
@@ -1627,7 +1673,7 @@ HgfsDirClose(HgfsSuperInfo *sip,        // IN: Superinfo pointer
     * 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));
@@ -1670,7 +1716,7 @@ HgfsFileClose(HgfsSuperInfo *sip,       // IN: Superinfo pointer
     * 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));
@@ -2421,7 +2467,7 @@ HgfsSymlinkInt(struct vnode *dvp,         // IN : directory vnode
    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;
       }
@@ -2552,6 +2598,7 @@ HgfsDoGetattrInt(const char *path,       // IN : Path to get attributes for
    return ret;
 }
 
+
 /*
  *----------------------------------------------------------------------------
  *
@@ -2698,12 +2745,12 @@ out:
 /*
  *----------------------------------------------------------------------------
  *
- * 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.
@@ -2711,95 +2758,164 @@ out:
  *----------------------------------------------------------------------------
  */
 
-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;
 }
index 9ed9472fa0ba81a31bff1f942801942977b86c98..303992d715f68136a08453b27867e7e957999114 100644 (file)
@@ -69,23 +69,26 @@ int HgfsRmdirInt(struct vnode *dvp, struct vnode *vp,
                 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_
index 0a2f3c6be12fdabdb1f70583226ded5006513ebd..337fd8cd9c82dbe09f8121f8a936bb4482a5a1f5 100644 (file)
@@ -440,7 +440,7 @@ FLAGDEF(  87, EDX, AMD,     4,  1, TM,                  NA,  IGNORE, 0, FALSE)
 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) \
@@ -644,6 +644,9 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #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)
+
 /*
  *----------------------------------------------------------------------
  *
@@ -815,6 +818,17 @@ CPUID_FAMILY_IS_K8STAR(uint32 _eax)
           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
index 2e70ae1fedee2456635335c3d1d0f9f773239ab1..d6bb8f7dbff72f46b559624fa6c19cb2b470e4ea 100644 (file)
@@ -83,10 +83,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index eaf6fbe592c9ca8bfb0450f6d4756e13b08efe09..b8dac81e50ddd4900e78e493f1472297dd260b0a 100644 (file)
@@ -1,5 +1,5 @@
 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;   \
index e026d0dafc6023528e3d76dfa0d09b94f966fffd..8f880b5a0e719de92f1e20d8194030f880015353 100644 (file)
@@ -61,7 +61,6 @@
 
 #define PVSCSI_LINUX_DRIVER_DESC "VMware PVSCSI driver"
 
-/* Module definitions */
 MODULE_DESCRIPTION(PVSCSI_LINUX_DRIVER_DESC);
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_LICENSE("GPL v2");
@@ -188,6 +187,9 @@ struct pvscsi_ctx {
        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 */
@@ -201,15 +203,19 @@ struct pvscsi_adapter {
        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;
@@ -267,12 +273,12 @@ static void __exit pvscsi_exit(void)
 
 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)
@@ -296,12 +302,18 @@ 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
@@ -312,16 +324,14 @@ static inline void pvscsi_shutdown_msi(struct pvscsi_adapter *adapter)
                                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);
@@ -333,26 +343,35 @@ static void pvscsi_release_resources(struct pvscsi_adapter *adapter)
                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;
 
@@ -360,10 +379,15 @@ static int __devinit pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
                                 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;
 }
 
@@ -383,20 +407,21 @@ static int __devinit pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
 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;
                }
@@ -425,14 +450,16 @@ pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        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,
@@ -515,8 +542,7 @@ pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                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++) {
@@ -607,7 +633,7 @@ pvscsi_find_context(const struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
 }
 
 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;
 
@@ -621,16 +647,11 @@ pvscsi_allocate_context(struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd)
        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;
 }
 
 /*
@@ -658,10 +679,10 @@ static int pvscsi_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 
        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;
        }
@@ -714,14 +735,29 @@ out:
 }
 
 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);
+        }
 }
 
 /*
@@ -739,8 +775,8 @@ static inline void pvscsi_reset_all(struct pvscsi_adapter *adapter)
                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);
                }
@@ -859,21 +895,12 @@ static irqreturn_t pvscsi_isr COMPAT_IRQ_HANDLER_ARGS(irq, devp)
        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);
@@ -914,27 +941,23 @@ static void pvscsi_remove(struct pci_dev *pdev)
  *
  **************************************************************/
 
-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.
@@ -951,21 +974,24 @@ pvscsi_map_buffers(struct pvscsi_adapter *adapter, struct pvscsi_ctx *ctx,
        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;
        }
 }
 
@@ -1000,19 +1026,22 @@ pvscsi_queue_ring(struct pvscsi_adapter *adapter, struct pvscsi_ctx *ctx,
        {
                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);
 
@@ -1060,7 +1089,9 @@ pvscsi_complete_request(struct pvscsi_adapter *adapter, const RingCmpDesc *e)
        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 &&
@@ -1146,8 +1177,6 @@ pvscsi_complete_request(struct pvscsi_adapter *adapter, const RingCmpDesc *e)
        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);
 }
 
@@ -1275,19 +1304,21 @@ static void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target)
 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);
index ee3edde1a6364e5409de531129d059c9655940a8..5949d6609fc1483a8b83dc986cca1d1648543aa5 100644 (file)
@@ -25,8 +25,8 @@
 #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_ */
index 2e70ae1fedee2456635335c3d1d0f9f773239ab1..d6bb8f7dbff72f46b559624fa6c19cb2b470e4ea 100644 (file)
@@ -83,10 +83,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index efb9fc44d1d6d1fe17d2093abb5b60b36a134bb6..a9696ebccb9234f983e1e74d81eddc7c31c8bf53 100644 (file)
@@ -271,6 +271,20 @@ static inline int compat_try_to_freeze(void) { return 0; }
 #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.
index 2e70ae1fedee2456635335c3d1d0f9f773239ab1..d6bb8f7dbff72f46b559624fa6c19cb2b470e4ea 100644 (file)
@@ -83,10 +83,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index efb9fc44d1d6d1fe17d2093abb5b60b36a134bb6..a9696ebccb9234f983e1e74d81eddc7c31c8bf53 100644 (file)
@@ -271,6 +271,20 @@ static inline int compat_try_to_freeze(void) { return 0; }
 #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.
index 6c443265fbb98b04e9e7407cabb654a9fe2895c7..3757177fa0402f3b0a672165d663bd8b860d50be 100644 (file)
 #   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);
index 2e70ae1fedee2456635335c3d1d0f9f773239ab1..d6bb8f7dbff72f46b559624fa6c19cb2b470e4ea 100644 (file)
@@ -83,10 +83,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index abfa5fccf429a6d290328f28a83d7c070e293839..37c8174c7589102cc9447c011caf0914a409f0b1 100644 (file)
@@ -196,10 +196,29 @@ static INLINE void
 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
 }
 
 
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index 11fa129138741ff5efe271a2779319ee6e0eb368..db7a551cb48cb4725241cf13c2d5148e8fb34b05 100644 (file)
@@ -1425,10 +1425,18 @@ VMCIHost_FinishAttach(PageStoreAttachInfo *attach,      // IN
    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;
@@ -1461,9 +1469,17 @@ VMCIHost_DetachMappings(PageStoreAttachInfo *attach)    // IN
    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
 }
 
 
@@ -1487,10 +1503,10 @@ VMCIHost_DetachMappings(PageStoreAttachInfo *attach)    // IN
 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],
@@ -1567,7 +1583,13 @@ errorDealloc:
    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) {
@@ -1611,7 +1633,9 @@ out:
       }
    }
    return err;
-
+#else
+   return FALSE;
+#endif
 #endif
 }
 
@@ -1663,6 +1687,13 @@ VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach)         // IN
                       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);
@@ -1676,6 +1707,7 @@ VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach)         // IN
    VMCI_FreeKernelMem(attach->consumeIoBuf,
                       sizeof *attach->consumeIoBuf);
 #endif
+#endif
 }
 
 #endif
index 05884f5c8860d784f6773eabf756975d36dce715..8d9e5c51f57469dae8c44cd7689ed2fdb437b063 100644 (file)
@@ -844,7 +844,7 @@ VMCIQueue_EnqueueV(VMCIQueue *produceQueue,       // IN:
  *
  * 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.
  *
@@ -860,7 +860,8 @@ __VMCIQueue_Dequeue(VMCIQueue *produceQueue,                    // IN:
                     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);
@@ -884,7 +885,11 @@ __VMCIQueue_Dequeue(VMCIQueue *produceQueue,                    // IN:
       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;
 }
 
@@ -918,7 +923,7 @@ VMCIQueue_Dequeue(VMCIQueue *produceQueue,       // IN:
                   size_t bufSize)                // IN:
 {
    return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
-                              buf, bufSize, VMCIMemcpyFromQueue);
+                              buf, bufSize, VMCIMemcpyFromQueue, TRUE);
 }
 
 
@@ -952,7 +957,75 @@ VMCIQueue_DequeueV(VMCIQueue *produceQueue,       // IN:
                    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
 
index b902e6eb2285b5ea5c0fd3b6964be07db373ad70..84a44f063d9055018e9232758b4222110d0a0f3f 100644 (file)
 #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,
index 4c469235fbd1ab287eb43ffac859545d251ded51..6239b829f0dce259ec9d6bb847f205066134b604 100644 (file)
@@ -278,6 +278,7 @@ HgfsBdHandler(void *data) // Ignored
       wait_event_interruptible(hgfsReqThreadWait,
                                test_bit(HGFS_REQ_THREAD_SEND,
                                         &hgfsReqThreadFlags) ||
+                               compat_wait_check_freezing() ||
                                compat_kthread_should_stop());
 
       /*
diff --git a/open-vm-tools/modules/linux/vmhgfs/compat_cred.h b/open-vm-tools/modules/linux/vmhgfs/compat_cred.h
new file mode 100644 (file)
index 0000000..e3bab07
--- /dev/null
@@ -0,0 +1,39 @@
+/*********************************************************
+ * 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__ */
diff --git a/open-vm-tools/modules/linux/vmhgfs/compat_pagemap.h b/open-vm-tools/modules/linux/vmhgfs/compat_pagemap.h
new file mode 100644 (file)
index 0000000..8b37c7d
--- /dev/null
@@ -0,0 +1,37 @@
+/*********************************************************
+ * 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__ */
index efb9fc44d1d6d1fe17d2093abb5b60b36a134bb6..a9696ebccb9234f983e1e74d81eddc7c31c8bf53 100644 (file)
@@ -271,6 +271,20 @@ static inline int compat_try_to_freeze(void) { return 0; }
 #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.
index d55e32013d22a63e3e276115f472a8fa1810bdca..ece9780d2b298b2611318596dc41712e832dc21b 100644 (file)
@@ -28,6 +28,7 @@
 #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"
@@ -634,7 +635,7 @@ HgfsOpen(struct inode *inode,  // IN: Inode of the file to open
             iparent = dparent->d_inode;
 
             HgfsSetUidGid(iparent, file->f_dentry,
-                          current->fsuid, current->fsgid);
+                          current_fsuid(), current_fsgid());
 
             dput(dparent);
          }
index e4103dd193fa0149fec2f745c8d6ac356dd147ab..4bcba9fe5b7c99d795af4b501a9d2d33799e94ee 100644 (file)
@@ -32,6 +32,7 @@
 #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"
@@ -256,13 +257,13 @@ HgfsInitSuperInfo(HgfsMountInfo *mountInfo) // IN: Passed down from the user
    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;
index b3ce70382d10d67f3a87a92f4eda886014872527..925a287c5eb754430f8e9cb897bd964d0a880810 100644 (file)
@@ -178,6 +178,55 @@ typedef uint8 HgfsPermissions;
 #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).
@@ -356,6 +405,15 @@ typedef uint64 HgfsAttrValid;
  *       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)
 
 
 /*
@@ -400,7 +458,7 @@ struct HgfsAttrV2 {
    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"
index 86b869f473b6eb4d5a27c9923d1a0debe0e78b00..e94b032faa8265e1c8517b4b7165c37c74d37f25 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/errno.h>
 #include <linux/pagemap.h>
 
+#include "compat_cred.h"
 #include "compat_fs.h"
 #include "compat_highmem.h"
 #include "compat_kernel.h"
@@ -1194,7 +1195,7 @@ HgfsMkdir(struct inode *dir,     // IN: Inode of parent directory
              * 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());
          }
 
          /*
@@ -1629,8 +1630,8 @@ HgfsPackSymlinkCreateRequest(struct dentry *dentry,   // IN: File pointer for th
    /* 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;
 }
index 6c443265fbb98b04e9e7407cabb654a9fe2895c7..3757177fa0402f3b0a672165d663bd8b860d50be 100644 (file)
 #   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);
index 4fc9b5352f59c2cb42b62854486ef26c5bea3fd4..81f2d8c493caa811919a1672f82a7b12c42bd48f 100644 (file)
@@ -31,6 +31,7 @@
 #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
@@ -758,10 +759,16 @@ HgfsDoWriteBegin(struct page *page,         // IN: Page to be written
                  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
@@ -864,7 +871,7 @@ HgfsWriteBegin(struct file *file,             // IN: File to be written
    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;
    }
index 2e70ae1fedee2456635335c3d1d0f9f773239ab1..d6bb8f7dbff72f46b559624fa6c19cb2b470e4ea 100644 (file)
@@ -83,10 +83,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index 5bc4d6b711ced2483232ec4c4fc445155c9e86ab..0180e391909505fb5f244d9f7bf03ec8f976319a 100644 (file)
@@ -853,4 +853,21 @@ RDTSC(void)
 #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
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index 0a2f3c6be12fdabdb1f70583226ded5006513ebd..337fd8cd9c82dbe09f8121f8a936bb4482a5a1f5 100644 (file)
@@ -440,7 +440,7 @@ FLAGDEF(  87, EDX, AMD,     4,  1, TM,                  NA,  IGNORE, 0, FALSE)
 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) \
@@ -644,6 +644,9 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #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)
+
 /*
  *----------------------------------------------------------------------
  *
@@ -815,6 +818,17 @@ CPUID_FAMILY_IS_K8STAR(uint32 _eax)
           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
index b902e6eb2285b5ea5c0fd3b6964be07db373ad70..84a44f063d9055018e9232758b4222110d0a0f3f 100644 (file)
 #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,
index efb9fc44d1d6d1fe17d2093abb5b60b36a134bb6..a9696ebccb9234f983e1e74d81eddc7c31c8bf53 100644 (file)
@@ -271,6 +271,20 @@ static inline int compat_try_to_freeze(void) { return 0; }
 #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.
index bf88e39281a9b53b72104d24c1ebbf8927c6e2e4..aab6567772ffda0ff8a8c99c736f58a1ff4b4191 100644 (file)
@@ -417,7 +417,9 @@ static int os_timer_thread_loop(void *data)
    /* 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()) {
index 2e70ae1fedee2456635335c3d1d0f9f773239ab1..d6bb8f7dbff72f46b559624fa6c19cb2b470e4ea 100644 (file)
@@ -83,10 +83,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
diff --git a/open-vm-tools/modules/linux/vmxnet/compat_pci_mapping.h b/open-vm-tools/modules/linux/vmxnet/compat_pci_mapping.h
new file mode 100644 (file)
index 0000000..fd91299
--- /dev/null
@@ -0,0 +1,84 @@
+/*********************************************************
+ * 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
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index 9917c1e9db310c5d8076aaae0ba2c6c1cafd3c9f..3c6d95edaca360e58963c1506e2da87b342147d9 100644 (file)
@@ -29,6 +29,7 @@
 #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>
@@ -97,10 +98,24 @@ static int debug = -1;
 #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>
@@ -128,17 +143,6 @@ static int debug = -1;
 
 #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
 
@@ -151,6 +155,15 @@ do{\
 
 #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
@@ -710,7 +723,6 @@ vmxnet_probe_device(struct pci_dev             *pdev, // IN: vmxnet PCI device
    Bool morphed = FALSE;
    Bool enhanced = FALSE;
    int i;
-   unsigned int driverDataSize;
 
    i = compat_pci_enable_device(pdev);
    if (i) {
@@ -904,7 +916,8 @@ vmxnet_probe_device(struct pci_dev             *pdev, // IN: vmxnet PCI device
    }
 
    if ((lp->capabilities & VMNET_CAP_LPD) &&
-       (lp->features & VMXNET_FEATURE_LPD)) {
+       (lp->features & VMXNET_FEATURE_LPD) &&
+       !disable_lro) {
       lp->lpd = TRUE;
       printk(" lpd");
    }
@@ -958,37 +971,28 @@ vmxnet_probe_device(struct pci_dev             *pdev, // IN: vmxnet PCI device
       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;
 
    /*
@@ -1020,16 +1024,13 @@ vmxnet_probe_device(struct pci_dev             *pdev, // IN: vmxnet PCI device
    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;
@@ -1088,8 +1089,16 @@ vmxnet_probe_device(struct pci_dev             *pdev, // IN: vmxnet PCI device
    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:;
@@ -1166,12 +1175,15 @@ vmxnet_remove_device(struct pci_dev* pdev)
    }
 
 #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);
 }
@@ -1221,7 +1233,7 @@ vmxnet_init_ring(struct net_device *dev)
               (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;
 
@@ -1233,7 +1245,10 @@ vmxnet_init_ring(struct net_device *dev)
         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;
@@ -1322,7 +1337,7 @@ vmxnet_open(struct net_device *dev)
 {
    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)) {
@@ -1330,18 +1345,16 @@ vmxnet_open(struct net_device *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
@@ -1588,12 +1601,16 @@ check_tx_queue(struct net_device *dev)
         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);
       }
@@ -1716,7 +1733,8 @@ vmxnet_tx(struct sk_buff *skb, struct net_device *dev)
                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)) {
 
@@ -1780,7 +1798,7 @@ vmxnet_tx(struct sk_buff *skb, struct net_device *dev)
             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);
@@ -1804,6 +1822,7 @@ vmxnet_tx(struct sk_buff *skb, struct net_device *dev)
 #endif
    {
       struct Vmxnet2_TxBuf *tb;
+      dma_addr_t dmaAddr;
 
       spin_lock_irqsave(&lp->txLock, flags);
 
@@ -1818,9 +1837,8 @@ vmxnet_tx(struct sk_buff *skb, struct net_device *dev)
 
       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;
 
@@ -2068,7 +2086,7 @@ vmxnet_rx(struct net_device *dev)
       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
@@ -2079,12 +2097,16 @@ vmxnet_rx(struct net_device *dev)
          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) {
@@ -2299,6 +2321,8 @@ vmxnet_close(struct net_device *dev)
 
    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;
       }
@@ -2307,7 +2331,8 @@ vmxnet_close(struct net_device *dev)
    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;
          }
index b56785dd0aa517d0bd5510fe47e1977df30077cd..e0e8c8820a680ddc413c952aff1970639e13710b 100644 (file)
@@ -30,9 +30,6 @@
 #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,
@@ -71,6 +68,8 @@ struct Vmxnet2_TxBuf {
  */
 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];
@@ -100,9 +99,9 @@ typedef struct Vmxnet_Private {
    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;
index d39dfb150f4b7f666fd766b32d1434fdaf6be596..e238993d4f088cec12760f83695b6fb3a3272d24 100644 (file)
@@ -25,8 +25,8 @@
 #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_ */
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index 52e2d0e8e0e0c7bc465bd54b83538c143b5cc9b1..bbc9631addff0127f1b0e6f09f3c226f1772f0af 100644 (file)
@@ -30,9 +30,9 @@
 #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"
@@ -155,6 +155,7 @@ static struct pci_driver vmxnet3_driver = {
 #endif
 };
 
+static int disable_lro = 0;
 
 /*
  *----------------------------------------------------------------------------
@@ -3101,8 +3102,10 @@ vmxnet3_declare_features(struct vmxnet3_adapter *adapter, Bool dma64)
    printk(" tsoIPv6");
 #endif
 
-   adapter->lro = TRUE;
-   printk(" lro");
+   if (!disable_lro) {
+      adapter->lro = TRUE;
+      printk(" lro");
+   }
 
    if (dma64) {
       netdev->features |= NETIF_F_HIGHDMA;
@@ -4558,5 +4561,5 @@ MODULE_VERSION(VMXNET3_DRIVER_VERSION_STRING);
  * by default (i.e., neither mkinitrd nor modprobe will accept it).
  */
 MODULE_INFO(supported, "external");
-
+module_param(disable_lro, int, 0);
 
index 0ee39d621eadbe473f9f5cf18a0e58cf5b8653dd..fb4334e6291af3af85daf59979f91e7ab3f39a60 100644 (file)
 #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_ */
index efb9fc44d1d6d1fe17d2093abb5b60b36a134bb6..a9696ebccb9234f983e1e74d81eddc7c31c8bf53 100644 (file)
@@ -271,6 +271,20 @@ static inline int compat_try_to_freeze(void) { return 0; }
 #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.
index 2e70ae1fedee2456635335c3d1d0f9f773239ab1..d6bb8f7dbff72f46b559624fa6c19cb2b470e4ea 100644 (file)
@@ -83,10 +83,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index abfa5fccf429a6d290328f28a83d7c070e293839..37c8174c7589102cc9447c011caf0914a409f0b1 100644 (file)
@@ -196,10 +196,29 @@ static INLINE void
 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
 }
 
 
index 5bc4d6b711ced2483232ec4c4fc445155c9e86ab..0180e391909505fb5f244d9f7bf03ec8f976319a 100644 (file)
@@ -853,4 +853,21 @@ RDTSC(void)
 #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
index 53ee917468e986573da078bd0048708d24d81dfd..638e9ce6c95c9a90f80e430910819112e527b499 100644 (file)
@@ -338,6 +338,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -489,10 +492,11 @@ typedef uint64 MPN64;
  */
 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
index e8e25a913c358ace2fedda3f35182d540ecf85bb..2a39e59b2e3c37534478f0329180779579899691 100644 (file)
 #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
 
 
@@ -76,15 +75,19 @@ int VMCIDatagram_Send(VMCIDatagram *msg);
 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
@@ -100,15 +103,10 @@ typedef struct VMCIQueue {
    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);
@@ -137,5 +135,12 @@ ssize_t VMCIQueue_DequeueV(VMCIQueue *produceQueue, const VMCIQueue *consumeQueu
                            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__ */
 
index 05884f5c8860d784f6773eabf756975d36dce715..8d9e5c51f57469dae8c44cd7689ed2fdb437b063 100644 (file)
@@ -844,7 +844,7 @@ VMCIQueue_EnqueueV(VMCIQueue *produceQueue,       // IN:
  *
  * 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.
  *
@@ -860,7 +860,8 @@ __VMCIQueue_Dequeue(VMCIQueue *produceQueue,                    // IN:
                     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);
@@ -884,7 +885,11 @@ __VMCIQueue_Dequeue(VMCIQueue *produceQueue,                    // IN:
       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;
 }
 
@@ -918,7 +923,7 @@ VMCIQueue_Dequeue(VMCIQueue *produceQueue,       // IN:
                   size_t bufSize)                // IN:
 {
    return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
-                              buf, bufSize, VMCIMemcpyFromQueue);
+                              buf, bufSize, VMCIMemcpyFromQueue, TRUE);
 }
 
 
@@ -952,7 +957,75 @@ VMCIQueue_DequeueV(VMCIQueue *produceQueue,       // IN:
                    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
 
index 0a2f3c6be12fdabdb1f70583226ded5006513ebd..337fd8cd9c82dbe09f8121f8a936bb4482a5a1f5 100644 (file)
@@ -440,7 +440,7 @@ FLAGDEF(  87, EDX, AMD,     4,  1, TM,                  NA,  IGNORE, 0, FALSE)
 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) \
@@ -644,6 +644,9 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #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)
+
 /*
  *----------------------------------------------------------------------
  *
@@ -815,6 +818,17 @@ CPUID_FAMILY_IS_K8STAR(uint32 _eax)
           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
index 1facc055adc3d8f689e519585140ec87d0ca5e1f..4d0ee72e69a155662377da063afcd20cfc83c476 100644 (file)
@@ -128,7 +128,7 @@ sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 #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"
@@ -138,14 +138,7 @@ sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 #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"
@@ -170,7 +163,6 @@ int VSockVmci_GetAFValue(void);
 /* 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);
@@ -194,7 +186,6 @@ static int VSockVmciRecvConnectingClient(struct sock *sk, VSockPacket *pkt);
 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,
@@ -207,7 +198,7 @@ static struct sock *__VSockVmciCreate(struct net *net,
                                       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);
 
@@ -220,38 +211,30 @@ static int VSockVmciBind(struct socket *sock,
                          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,
@@ -259,36 +242,30 @@ static int VSockVmciDgramSendmsg(struct kiocb *kiocb, struct socket *sock,
 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)
@@ -374,7 +351,6 @@ static struct proto_ops vsockVmciDgramOps = {
 #endif
 };
 
-#ifdef VMX86_TOOLS
 static struct proto_ops vsockVmciStreamOps = {
    .family     = VSOCK_INVALID_FAMILY,
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69)
@@ -399,7 +375,6 @@ static struct proto_ops vsockVmciStreamOps = {
    .sendpage   = sock_no_sendpage,
 #endif
 };
-#endif
 
 static struct file_operations vsockVmciDeviceOps = {
 #ifdef HAVE_UNLOCKED_IOCTL
@@ -431,14 +406,14 @@ static int devOpenCount = 0;
 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
@@ -711,7 +686,7 @@ VSockVmci_GetAFValue(void)
  *----------------------------------------------------------------------------
  */
 
-static inline void
+static void
 VSockVmciTestUnregister(void)
 {
    if (devOpenCount <= 0 && vsockVmciSocketCount <= 0 &&
@@ -740,17 +715,17 @@ VSockVmciTestUnregister(void)
  *----------------------------------------------------------------------------
  */
 
-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
@@ -763,8 +738,6 @@ VSockVmciUpdateQueueBucketCount(VMCIQueue *mainQueue,  // IN
 }
 #endif
 
-
-#ifdef VMX86_TOOLS
 /*
  *----------------------------------------------------------------------------
  *
@@ -784,7 +757,7 @@ VSockVmciUpdateQueueBucketCount(VMCIQueue *mainQueue,  // IN
 static Bool
 VSockVmciNotifyWaitingWrite(VSockVmciSock *vsk)    // IN
 {
-#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
    Bool retval;
    uint64 notifyLimit;
   
@@ -868,7 +841,7 @@ VSockVmciNotifyWaitingWrite(VSockVmciSock *vsk)    // IN
 static Bool
 VSockVmciNotifyWaitingRead(VSockVmciSock *vsk)  // IN
 {
-#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
    if (!vsk->peerWaitingRead) {
       return FALSE;
    }
@@ -910,7 +883,7 @@ VSockVmciHandleWrote(struct sock *sk,            // IN
                     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);
@@ -944,7 +917,7 @@ VSockVmciHandleRead(struct sock *sk,            // IN
                    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);
@@ -979,7 +952,7 @@ VSockVmciHandleWaitingWrite(struct sock *sk,            // IN
                             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);
@@ -1029,7 +1002,7 @@ VSockVmciHandleWaitingRead(struct sock *sk,             // IN
                            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);
@@ -1053,7 +1026,6 @@ VSockVmciHandleWaitingRead(struct sock *sk,             // IN
    }
 #endif
 }
-#endif
 
 
 /*
@@ -1112,7 +1084,6 @@ VSockVmciRecvDgramCB(void *data,           // IN
 }
 
 
-#ifdef VMX86_TOOLS
 /*
  *----------------------------------------------------------------------------
  *
@@ -1358,7 +1329,7 @@ out:
  *----------------------------------------------------------------------------
  */
 
-static INLINE void
+static void
 VSockVmciHandleDetach(struct sock *sk) // IN
 {
    VSockVmciSock *vsk;
@@ -1370,12 +1341,10 @@ VSockVmciHandleDetach(struct sock *sk) // IN
       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;
@@ -2412,7 +2381,6 @@ VSockVmciSendControlPkt(struct sock *sk,        // IN
 
    return err;
 }
-#endif
 
 
 /*
@@ -2562,7 +2530,6 @@ out:
 }
 
 
-#ifdef VMX86_TOOLS
 /*
  *----------------------------------------------------------------------------
  *
@@ -2586,7 +2553,7 @@ static Bool
 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;
@@ -2645,7 +2612,7 @@ static Bool
 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;
@@ -2748,7 +2715,6 @@ VSockVmciSendReadNotification(struct sock *sk)  // IN
    }
    return err;
 }
-#endif // VMX86_TOOLS
 
 
 /*
@@ -2868,7 +2834,6 @@ __VSockVmciCreate(struct net *net,       // IN: Network namespace
    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;
@@ -2889,7 +2854,6 @@ __VSockVmciCreate(struct net *net,       // IN: Network namespace
    vsk->rejected = FALSE;
    vsk->attachSubId = vsk->detachSubId = VMCI_INVALID_ID;
    vsk->peerShutdown = 0;
-#endif
 
    if (sock) {
       VSockVmciInsertBound(vsockUnboundSockets, sk);
@@ -2948,12 +2912,10 @@ __VSockVmciRelease(struct sock *sk) // IN
       }
 
       /* 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);
@@ -2989,7 +2951,6 @@ VSockVmciSkDestruct(struct sock *sk) // IN
 
    vsk = vsock_sk(sk);
 
-#ifdef VMX86_TOOLS
    if (vsk->attachSubId != VMCI_INVALID_ID) {
       VMCIEvent_Unsubscribe(vsk->attachSubId);
       vsk->attachSubId = VMCI_INVALID_ID;
@@ -3006,7 +2967,6 @@ VSockVmciSkDestruct(struct sock *sk) // IN
       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
@@ -3015,10 +2975,8 @@ VSockVmciSkDestruct(struct sock *sk) // IN
     */
    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
@@ -3107,12 +3065,10 @@ VSockVmciQueueRcvSkb(struct sock *sk,     // IN
  *----------------------------------------------------------------------------
  */
 
-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
@@ -3162,7 +3118,7 @@ VSockVmciRegisterProto(void)
  *----------------------------------------------------------------------------
  */
 
-static INLINE void
+static void
 VSockVmciUnregisterProto(void)
 {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
@@ -3183,11 +3139,11 @@ VSockVmciUnregisterProto(void)
       }
 
       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;
       }
 
    }
@@ -3230,6 +3186,7 @@ VSockVmciRegisterAddressFamily(void)
       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
@@ -3254,7 +3211,6 @@ VSockVmciRegisterAddressFamily(void)
       qpResumedSubId = VMCI_INVALID_ID;
       goto error;
    }
-#endif
 
    /*
     * Linux will not allocate an address family to code that is not part of the
@@ -3275,9 +3231,7 @@ VSockVmciRegisterAddressFamily(void)
          vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY;
       } else {
          vsockVmciDgramOps.family = i;
-#ifdef VMX86_TOOLS
          vsockVmciStreamOps.family = i;
-#endif
          break;
       }
    }
@@ -3289,13 +3243,11 @@ VSockVmciRegisterAddressFamily(void)
    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;
 }
 
@@ -3326,6 +3278,7 @@ VSockVmciUnregisterAddressFamily(void)
       /* Nothing was registered. */
       return;
    }
+#endif
 
    if (!VMCI_HANDLE_INVALID(vmciStreamHandle)) {
       if (VMCIDatagram_DestroyHnd(vmciStreamHandle) != VMCI_SUCCESS) {
@@ -3337,16 +3290,13 @@ VSockVmciUnregisterAddressFamily(void)
       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
 
 }
 
@@ -3486,7 +3436,6 @@ out:
 }
 
 
-#ifdef VMX86_TOOLS
 /*
  *----------------------------------------------------------------------------
  *
@@ -3740,7 +3689,6 @@ out:
    release_sock(listener);
    return err;
 }
-#endif
 
 
 /*
@@ -3864,7 +3812,6 @@ VSockVmciPoll(struct file *file,    // IN
       if (!(sk->compat_sk_shutdown & SEND_SHUTDOWN)) {
          mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
       }
-#ifdef VMX86_TOOLS
    } else if (sock->type == SOCK_STREAM) {
       VSockVmciSock *vsk;
 
@@ -3935,14 +3882,12 @@ VSockVmciPoll(struct file *file,    // IN
       }
 
       release_sock(sk);
-#endif
    }
 
    return mask;
 }
 
 
-#ifdef VMX86_TOOLS
 /*
  *----------------------------------------------------------------------------
  *
@@ -3997,7 +3942,6 @@ out:
    release_sock(sk);
    return err;
 }
-#endif
 
 
 /*
@@ -4051,12 +3995,10 @@ VSockVmciShutdown(struct socket *sock,  // IN
       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;
 }
@@ -4201,7 +4143,6 @@ out:
    return err;
 }
 
-#ifdef VMX86_TOOLS
 /*
  *----------------------------------------------------------------------------
  *
@@ -4290,9 +4231,7 @@ out:
    return err;
 }
 
-#endif
 
-#ifdef VMX86_TOOLS
 /*
  *----------------------------------------------------------------------------
  *
@@ -4364,10 +4303,8 @@ VSockVmciStreamGetsockopt(struct socket *sock,          // IN
     }
     return 0;
 }
-#endif
 
 
-#ifdef VMX86_TOOLS
 /*
  *----------------------------------------------------------------------------
  *
@@ -4416,7 +4353,7 @@ VSockVmciStreamSendmsg(struct kiocb *kiocb,          // UNUSED
    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
@@ -4528,7 +4465,7 @@ VSockVmciStreamSendmsg(struct kiocb *kiocb,          // UNUSED
        * 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
@@ -4541,7 +4478,7 @@ VSockVmciStreamSendmsg(struct kiocb *kiocb,          // UNUSED
          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
@@ -4575,7 +4512,7 @@ VSockVmciStreamSendmsg(struct kiocb *kiocb,          // UNUSED
             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
          }
@@ -4593,7 +4530,6 @@ out:
    release_sock(sk);
    return err;
 }
-#endif
 
 
 /*
@@ -4711,7 +4647,6 @@ out:
 }
 
 
-#ifdef VMX86_TOOLS
 /*
  *----------------------------------------------------------------------------
  *
@@ -4768,7 +4703,7 @@ VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
    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
@@ -4856,7 +4791,7 @@ VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
           !(vsk->peerShutdown & SEND_SHUTDOWN)) {
 
       if (ready < 0) {
-         /* 
+         /*
           * Invalid queue pair content. XXX This should be changed to
           * a connection reset in a later change.
           */
@@ -4926,49 +4861,61 @@ VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
     * 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);
@@ -4980,7 +4927,6 @@ out:
    release_sock(sk);
    return err;
 }
-#endif
 
 
 /*
@@ -5026,15 +4972,9 @@ VSockVmciCreate(struct net *net,      // IN
    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;
    }
index a38de68207e7d3b2166ac6535271dd525b52ec38..ea2ed5cf892bf140a6825b8b728ef8034a45ade7 100644 (file)
 #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)
@@ -51,7 +57,6 @@ typedef struct VSockVmciSock {
    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;
@@ -90,7 +95,6 @@ typedef struct VSockVmciSock {
    Bool rejected;
    compat_delayed_work dwork;
    uint32 peerShutdown;
-#endif
 } VSockVmciSock;
 
 #endif /* __AF_VSOCK_H__ */
index 7c355c20d18122308db9f055c258ec7c2f799cb0..53f2edb8e394a62c4e7f3bee05ab8df2a1a03b7d 100644 (file)
@@ -475,7 +475,6 @@ __VSockVmciInConnectedTable(struct sock *sk)     // IN
 }
 
 
-#ifdef VMX86_TOOLS
 /*
  *----------------------------------------------------------------------------
  *
@@ -854,4 +853,3 @@ VSockVmciIsPending(struct sock *sk)     // IN: socket
    vsk = vsock_sk(sk);
    return !list_empty(&vsk->pendingLinks);
 }
-#endif
index 6fc42d5cf33a9f3d08d2aef4b9637624bf8d29c5..fbf909169fa9b4924c9d85a4eeb50e7865f3f122 100644 (file)
@@ -86,7 +86,6 @@ struct sock *__VSockVmciFindConnectedSocket(struct sockaddr_vm *src,
 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);
@@ -97,7 +96,6 @@ void VSockVmciRemoveAccept(struct sock *listener, struct sock *connected);
 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);
index 86bb3a6dab355f3c8f5029808ed581db937f92a1..5b85beae703ccf9970999766c383470572659005 100644 (file)
@@ -98,6 +98,7 @@
 #  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
 
index bf48b948cda5969fdb706dde4ad8379cd4da6bd3..58254a750a3c03dbde0c8536a646a8ef8b56fe07 100644 (file)
@@ -45,37 +45,52 @@ CFLAGS   += -Wall -Werror
 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)
@@ -112,7 +127,11 @@ $(MODULE_32): $(SOLHGFS_32_OBJS)
        @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 $@
 
@@ -121,14 +140,18 @@ $(MODULE_64): $(SOLHGFS_64_OBJS)
        @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"
diff --git a/open-vm-tools/modules/solaris/vmhgfs/backdoor.c b/open-vm-tools/modules/solaris/vmhgfs/backdoor.c
new file mode 100644 (file)
index 0000000..2c4dcdc
--- /dev/null
@@ -0,0 +1,257 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/modules/solaris/vmhgfs/backdoor.h b/open-vm-tools/modules/solaris/vmhgfs/backdoor.h
new file mode 100644 (file)
index 0000000..ad7b422
--- /dev/null
@@ -0,0 +1,44 @@
+/*********************************************************
+ * 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_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/backdoorGcc32.c b/open-vm-tools/modules/solaris/vmhgfs/backdoorGcc32.c
new file mode 100644 (file)
index 0000000..98e06e3
--- /dev/null
@@ -0,0 +1,219 @@
+/*********************************************************
+ * 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
+
diff --git a/open-vm-tools/modules/solaris/vmhgfs/backdoorGcc64.c b/open-vm-tools/modules/solaris/vmhgfs/backdoorGcc64.c
new file mode 100644 (file)
index 0000000..6549b32
--- /dev/null
@@ -0,0 +1,183 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/modules/solaris/vmhgfs/backdoorInt.h b/open-vm-tools/modules/solaris/vmhgfs/backdoorInt.h
new file mode 100644 (file)
index 0000000..07222b4
--- /dev/null
@@ -0,0 +1,24 @@
+/*********************************************************
+ * 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);
diff --git a/open-vm-tools/modules/solaris/vmhgfs/backdoor_def.h b/open-vm-tools/modules/solaris/vmhgfs/backdoor_def.h
new file mode 100644 (file)
index 0000000..7f66e0d
--- /dev/null
@@ -0,0 +1,176 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/modules/solaris/vmhgfs/backdoor_types.h b/open-vm-tools/modules/solaris/vmhgfs/backdoor_types.h
new file mode 100644 (file)
index 0000000..d53cef0
--- /dev/null
@@ -0,0 +1,116 @@
+/*********************************************************
+ * 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_ */
index 0e6be244622db2a95eb6f8c10d9b993e5fc364b5..b82476fdd2581172396f1e4e8e776ca39b257e4f 100644 (file)
@@ -145,7 +145,8 @@ HgfsDebugPrintVfs(char *str, struct vfs *vfsp)
  */
 
 INLINE void
-HgfsDebugPrintVnode(uint32 level, char *str, struct vnode *vnodep)
+HgfsDebugPrintVnode(uint32 level, char *str,
+                    struct vnode *vnodep, Bool printFileName)
 {
    ASSERT(str);
    ASSERT(vnodep);
@@ -172,7 +173,7 @@ HgfsDebugPrintVnode(uint32 level, char *str, struct vnode *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));
    }
 }
@@ -409,11 +410,6 @@ HgfsDebugPrintReqPool(const char *str)
 }
 
 
-/*
- * 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
@@ -426,58 +422,62 @@ HgfsDebugPrintReqPool(const char *str)
  * 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
index 9811fd0dde416c041d85d4a56a09a6441de700f8..657eff0ffd3fc373f01e0e0417daf02c8ddaf913 100644 (file)
 #ifndef __DEBUG_H_
 #define __DEBUG_H_
 
+#ifdef _KERNEL
+
 #include <sys/vnode.h>
 #include <sys/vfs.h>
 
 #include "hgfsSolaris.h"
 #include "filesystem.h"
 
+#endif
 
 /*
  * Debugging
@@ -71,7 +74,6 @@
 #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_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/device.c b/open-vm-tools/modules/solaris/vmhgfs/device.c
deleted file mode 100644 (file)
index 3948f68..0000000
+++ /dev/null
@@ -1,1111 +0,0 @@
-/*********************************************************
- * 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];
-}
diff --git a/open-vm-tools/modules/solaris/vmhgfs/device.h b/open-vm-tools/modules/solaris/vmhgfs/device.h
deleted file mode 100644 (file)
index f9403f0..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*********************************************************
- * 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_ */
index c8d38de1447941ee9f99526f2d6936a011e43997..d10e3d9baef03b1afd09291aa561828825f257e5 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include <sys/param.h>          /* MAXNAMELEN */
+#include <sys/file.h>           /* FKIOCTL */
 
 #include "hgfsSolaris.h"
 #include "hgfsState.h"
@@ -55,6 +56,15 @@ void HgfsFreevfs(struct vfs *vfsp);
 #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
 /*
@@ -129,7 +139,7 @@ HgfsInit(int fstype,    // IN: Filesystem type
    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),
@@ -154,16 +164,23 @@ HgfsInit(int fstype,    // IN: Filesystem type
 
    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;
@@ -171,6 +188,33 @@ HgfsInit(int fstype,    // IN: Filesystem type
 
 #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
@@ -212,73 +256,48 @@ HgfsMount(struct vfs *vfsp,     // IN: Filesystem to mount
    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;
    }
 
    /*
@@ -286,9 +305,9 @@ HgfsMount(struct vfs *vfsp,     // IN: Filesystem to mount
     * 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);
@@ -334,10 +353,14 @@ HgfsMount(struct vfs *vfsp,     // IN: Filesystem to mount
    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;
    }
@@ -357,6 +380,8 @@ HgfsMount(struct vfs *vfsp,     // IN: Filesystem to mount
                       &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;
    }
@@ -366,25 +391,14 @@ HgfsMount(struct vfs *vfsp,     // IN: Filesystem to mount
    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;
 }
 
@@ -411,15 +425,15 @@ HgfsUnmount(struct vfs *vfsp,   // IN: This filesystem
             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.
     */
@@ -436,51 +450,60 @@ HgfsUnmount(struct vfs *vfsp,   // IN: This filesystem
       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;
 }
 
 
index 704903a0dbba44c4ce491287d19914992bd297ce..69900ea19ee05f380b8ef69046ee5f6f0fac0d96 100644 (file)
@@ -60,7 +60,7 @@
 #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;
@@ -104,6 +104,7 @@ typedef struct HgfsMountData {
 /* To abstract Solaris 9 and 10 differences in suser() calls */
 int HgfsSuser(struct cred *cr);
 
+void HgfsFreeVfsOps(void);
 
 /*
  * Extern variables
diff --git a/open-vm-tools/modules/solaris/vmhgfs/guest_msg_def.h b/open-vm-tools/modules/solaris/vmhgfs/guest_msg_def.h
new file mode 100644 (file)
index 0000000..a90e1ad
--- /dev/null
@@ -0,0 +1,90 @@
+/*********************************************************
+ * 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_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsBd.c b/open-vm-tools/modules/solaris/vmhgfs/hgfsBd.c
new file mode 100644 (file)
index 0000000..284704a
--- /dev/null
@@ -0,0 +1,410 @@
+/*********************************************************
+ * 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;
+}
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsBd.h b/open-vm-tools/modules/solaris/vmhgfs/hgfsBd.h
new file mode 100644 (file)
index 0000000..0439dc5
--- /dev/null
@@ -0,0 +1,50 @@
+/*********************************************************
+ * 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_
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsBdGlue.c b/open-vm-tools/modules/solaris/vmhgfs/hgfsBdGlue.c
new file mode 100644 (file)
index 0000000..8d302ab
--- /dev/null
@@ -0,0 +1,190 @@
+/*********************************************************
+ * 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);
+}
+
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsBdGlue.h b/open-vm-tools/modules/solaris/vmhgfs/hgfsBdGlue.h
new file mode 100644 (file)
index 0000000..b39bc50
--- /dev/null
@@ -0,0 +1,31 @@
+/*********************************************************
+ * 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_
index 637306aba816803eb88510d4a9c62cb0b437bcd5..04b665b3e3200e787e58ba3d679a54c2206850d2 100644 (file)
@@ -176,6 +176,55 @@ typedef uint8 HgfsPermissions;
 #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).
@@ -354,6 +403,15 @@ typedef uint64 HgfsAttrValid;
  *       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)
 
 
 /*
@@ -398,7 +456,7 @@ struct HgfsAttrV2 {
    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"
index c32d57918fc42fdf618fb066ca711e2866dc970c..5a1f8871bcfbbf75d3d9515c9e6179f0eac4aa55 100644 (file)
@@ -84,9 +84,6 @@
 /* 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)
 
@@ -132,39 +119,6 @@ typedef HgfsRequest HgfsRequestHeader;
  */
 #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
@@ -191,30 +145,45 @@ typedef struct HgfsReq {
                                            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
index 9b008095151e444f567d22731625dee2e15e07b6..56a00471381eb264657a92119daa843ddd4d45e7 100644 (file)
@@ -170,7 +170,7 @@ HgfsVnodeGet(struct vnode **vpp,        // OUT: Filled with address of created v
     * 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;
    }
 
@@ -483,7 +483,7 @@ HgfsNodeIdGet(HgfsFileHashTable *htp,   // IN:  File hash table
  *    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.
@@ -491,7 +491,7 @@ HgfsNodeIdGet(HgfsFileHashTable *htp,   // IN:  File hash table
  *----------------------------------------------------------------------------
  */
 
-int
+void
 HgfsInitFileHashTable(HgfsFileHashTable *htp)   // IN: Hash table to initialize
 {
    int i;
@@ -503,8 +503,6 @@ HgfsInitFileHashTable(HgfsFileHashTable *htp)   // IN: Hash table to initialize
    for (i = 0; i < ARRAYSIZE(htp->hashTable); i++) {
       DblLnkLst_Init(&htp->hashTable[i]);
    }
-
-   return 0;
 }
 
 
index 337e7e43d3571b22f416f71d37f5a5e00da15725..bfaa44233a040a074366e34d12da8c9c7e3456b5 100644 (file)
@@ -172,7 +172,7 @@ int HgfsFileNameToVnode(const char *fileName, struct vnode **vpp,
                         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 */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/kernelStubs.h b/open-vm-tools/modules/solaris/vmhgfs/kernelStubs.h
new file mode 100644 (file)
index 0000000..20cbb3e
--- /dev/null
@@ -0,0 +1,148 @@
+/*********************************************************
+ * 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__ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/kernelStubsSolaris.c b/open-vm-tools/modules/solaris/vmhgfs/kernelStubsSolaris.c
new file mode 100644 (file)
index 0000000..75ae9b9
--- /dev/null
@@ -0,0 +1,380 @@
+/*********************************************************
+ * 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;
+}
+
+
diff --git a/open-vm-tools/modules/solaris/vmhgfs/message.c b/open-vm-tools/modules/solaris/vmhgfs/message.c
new file mode 100644 (file)
index 0000000..7a7e3ab
--- /dev/null
@@ -0,0 +1,296 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/modules/solaris/vmhgfs/message.h b/open-vm-tools/modules/solaris/vmhgfs/message.h
new file mode 100644 (file)
index 0000000..92c6b2a
--- /dev/null
@@ -0,0 +1,104 @@
+/*********************************************************
+ * 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__ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/messageBackdoor.c b/open-vm-tools/modules/solaris/vmhgfs/messageBackdoor.c
new file mode 100644 (file)
index 0000000..9c72011
--- /dev/null
@@ -0,0 +1,626 @@
+/*********************************************************
+ * 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
index 04dbd4bd2cad644d54a1751d40fe5ec2c6dddbae..62cef6b66e5bdc9006bd751d3df5aaedba5966e8 100644 (file)
  * 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
  */
@@ -234,17 +152,11 @@ static struct modlfs HgfsModlfs = {
 
 
 /*
- * 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 */
    }
@@ -281,56 +193,14 @@ _init(void)
 
    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;
 }
 
 
@@ -353,21 +223,17 @@ error:
 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);
@@ -376,15 +242,8 @@ _fini(void)
       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;
index 9d498af27b2b3902ed6af142400ce6ac43fe9bd0..1dab9d6d8bcbc730444b9f3a1e959700f8181754 100644 (file)
 
 #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
  */
index 58c5d1f06eabe1343720637989d200203ad95e8a..644a437defb325405faf594cca1e7d7efb5019b1 100644 (file)
@@ -56,22 +56,8 @@ HgfsInitRequestList(HgfsSuperInfo *sip) // IN: Pointer to superinfo structure
    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);
@@ -88,7 +74,6 @@ HgfsInitRequestList(HgfsSuperInfo *sip) // IN: Pointer to superinfo structure
    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);
@@ -104,16 +89,14 @@ HgfsInitRequestList(HgfsSuperInfo *sip) // IN: Pointer to superinfo structure
  *
  * 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.
  *
  *----------------------------------------------------------------------------
  */
@@ -122,71 +105,23 @@ void
 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");
 }
 
@@ -275,22 +210,22 @@ HgfsGetNewReq(HgfsSuperInfo *sip)       // IN: Superinfo containing free list
    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;
 }
 
@@ -312,24 +247,24 @@ out:
  *----------------------------------------------------------------------------
  */
 
-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
@@ -337,7 +272,7 @@ HgfsDestroyReq(HgfsSuperInfo *sip,      // IN: Superinfo containing free list
     */
    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);
@@ -353,9 +288,10 @@ HgfsDestroyReq(HgfsSuperInfo *sip,      // IN: Superinfo containing free list
 /*
  *----------------------------------------------------------------------------
  *
- * 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.
@@ -370,84 +306,24 @@ HgfsDestroyReq(HgfsSuperInfo *sip,      // IN: Superinfo containing free list
  *----------------------------------------------------------------------------
  */
 
-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;
 }
 
 
@@ -489,77 +365,3 @@ HgfsWakeWaitingClient(HgfsSuperInfo *sip,       // IN: Superinfo with request mu
 //   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;
-}
index d197665239215be79919745b8c5885f63faa90c3..6d081bc7bc2d74eb16ac9633aafe3789d1cd6382 100644 (file)
@@ -57,11 +57,8 @@ void HgfsInitRequestList(HgfsSuperInfo *sip);
 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_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/rpcout.c b/open-vm-tools/modules/solaris/vmhgfs/rpcout.c
new file mode 100644 (file)
index 0000000..0c2561c
--- /dev/null
@@ -0,0 +1,464 @@
+/*********************************************************
+ * 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;
+}
+
+
diff --git a/open-vm-tools/modules/solaris/vmhgfs/rpcout.h b/open-vm-tools/modules/solaris/vmhgfs/rpcout.h
new file mode 100644 (file)
index 0000000..8b026c4
--- /dev/null
@@ -0,0 +1,57 @@
+/*********************************************************
+ * 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__ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/str.h b/open-vm-tools/modules/solaris/vmhgfs/str.h
new file mode 100644 (file)
index 0000000..b79c313
--- /dev/null
@@ -0,0 +1,202 @@
+/*********************************************************
+ * 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_ */
index 80b5490bdf200a58a4c260d5f91592c5ee78423a..f03920614a525f4edaf57dc2fc232a0f39dba9c1 100644 (file)
@@ -81,10 +81,26 @@ EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
  */
 
 #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
 
index 7d83e29a35858d08d85a8602b59ddb877ebb5ebd..483b830f8274fe60ba9aac0ecd3495ad319e988b 100644 (file)
@@ -851,4 +851,21 @@ RDTSC(void)
 #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
index 05feb1219d1ce96fd268f806ca13e1aac5686b05..dc0ad610841ae6390f3ff6bcd907f8c59af2b6f7 100644 (file)
@@ -336,6 +336,9 @@ typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
 #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
@@ -487,10 +490,11 @@ typedef uint64 MPN64;
  */
 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
index 25f02f6fa5988dfa350721ea1440a89ad266c11f..982a2639484c842158f1528825004c995df5a7c4 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "hgfsSolaris.h"
 #include "hgfsState.h"
+#include "hgfsBdGlue.h"
 #include "vnode.h"
 #include "filesystem.h"
 #include "request.h"
@@ -90,10 +91,6 @@ static int HgfsDoWrite(HgfsSuperInfo *sip, HgfsHandle handle, int ioflag,
                        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,
@@ -328,7 +325,7 @@ static int HgfsVnevent(struct vnode *vp, vnevent_t event, vnode_t *dvp,
 
 #if HGFS_VFS_VERSION == 2
 /* vnode Operations Structure */
-struct vnodeops HgfsVnodeOps = {
+struct vnodeops hgfsVnodeOps = {
    HgfsOpen,            /* vop_open() */
    HgfsClose,           /* vop_close() */
    HgfsRead,            /* vop_read() */
@@ -374,8 +371,15 @@ struct vnodeops HgfsVnodeOps = {
    HgfsShrlock          /* vop_shrlock() */
 };
 
+#else
+
+/* Will be set up during HGFS initialization (see HgfsInit) */
+static struct vnodeops *hgfsVnodeOpsP;
+
 #endif
 
+static HgfsSuperInfo hgfsSuperInfo;
+
 
 /*
  * Vnode Entry Points
@@ -546,7 +550,7 @@ HgfsClose(struct vnode *vp,        // IN: Vnode of file that is being closed
 
    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;
    }
 
@@ -957,8 +961,8 @@ HgfsGetattr(struct vnode *vp,      // IN: Vnode of file to get attributes for
       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;
@@ -972,7 +976,6 @@ HgfsGetattr(struct vnode *vp,      // IN: Vnode of file to get attributes for
     */
    ret = HgfsSubmitRequest(sip, req);
    if (ret) {
-      /* HgfsSubmitRequest destroys the request if necessary */
       goto out;
    }
 
@@ -981,7 +984,7 @@ HgfsGetattr(struct vnode *vp,      // IN: Vnode of file to get attributes for
    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) {
@@ -1014,9 +1017,8 @@ HgfsGetattr(struct vnode *vp,      // IN: Vnode of file to get attributes for
       break;
    }
 
-destroy_out:
-   HgfsDestroyReq(sip, req);
 out:
+   HgfsDestroyReq(sip, req);
    return ret;
 }
 
@@ -1095,8 +1097,8 @@ HgfsSetattr(struct vnode *vp,       // IN: Vnode of file to get attributes for
       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. */
@@ -1105,8 +1107,8 @@ HgfsSetattr(struct vnode *vp,       // IN: Vnode of file to get attributes for
       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;
@@ -1116,7 +1118,6 @@ HgfsSetattr(struct vnode *vp,       // IN: Vnode of file to get attributes for
 
    ret = HgfsSubmitRequest(sip, req);
    if (ret) {
-      /* HgfsSubmitRequest() destroys the request if necessary. */
       goto out;
    }
 
@@ -1125,7 +1126,7 @@ HgfsSetattr(struct vnode *vp,       // IN: Vnode of file to get attributes for
    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) {
@@ -1137,26 +1138,25 @@ HgfsSetattr(struct vnode *vp,       // IN: Vnode of file to get attributes for
    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;
 }
 
@@ -1340,8 +1340,7 @@ HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
                           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);
@@ -1388,7 +1387,7 @@ HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
        * per-open state for it.
        */
       DEBUG(VM_DEBUG_DONE, "HgfsLookup: created per-open state from filename.\n");
-      goto out;
+      return 0;
    }
 #endif
 
@@ -1411,8 +1410,8 @@ HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
       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;
 
@@ -1425,8 +1424,7 @@ HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
    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) {
@@ -1441,7 +1439,7 @@ HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
       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);
@@ -1457,7 +1455,7 @@ HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
          DEBUG(VM_DEBUG_COMM,
                "HgfsLookup: invalid packet size received for \"%s\".\n", nm);
          ret = EIO;
-         goto destroy_out;
+         goto out;
       }
       /* Success */
       break;
@@ -1465,7 +1463,7 @@ HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
    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:
@@ -1476,12 +1474,12 @@ HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
        */
       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;
    }
 
    /*
@@ -1500,7 +1498,7 @@ HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
    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);
@@ -1509,9 +1507,8 @@ HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
 
    ret = 0;     /* Return success */
 
-destroy_out:
-   HgfsDestroyReq(sip, req);
 out:
+   HgfsDestroyReq(sip, req);
    return ret;
 }
 
@@ -1856,8 +1853,8 @@ HgfsRename(struct vnode *sdvp,     // IN: Source directory that contains file to
             "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;
@@ -1877,8 +1874,8 @@ HgfsRename(struct vnode *sdvp,     // IN: Source directory that contains file to
             "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;
@@ -1888,7 +1885,6 @@ HgfsRename(struct vnode *sdvp,     // IN: Source directory that contains file to
 
    ret = HgfsSubmitRequest(sip, req);
    if (ret) {
-      /* HgfsSubmitRequest() destroys the request if necessary. */
       goto out;
    }
 
@@ -1898,7 +1894,7 @@ HgfsRename(struct vnode *sdvp,     // IN: Source directory that contains file to
    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. */
@@ -1910,28 +1906,28 @@ HgfsRename(struct vnode *sdvp,     // IN: Source directory that contains file to
    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;
    }
 
 
@@ -1939,9 +1935,8 @@ HgfsRename(struct vnode *sdvp,     // IN: Source directory that contains file to
    ret = 0;
    DEBUG(VM_DEBUG_DONE, "HgfsRename: done.\n");
 
-destroy_out:
-   HgfsDestroyReq(sip, req);
 out:
+   HgfsDestroyReq(sip, req);
    return ret;
 }
 
@@ -2045,8 +2040,8 @@ HgfsMkdir(struct vnode *dvp,      // IN: Vnode of directory to create directory
       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;
@@ -2054,10 +2049,9 @@ HgfsMkdir(struct vnode *dvp,      // IN: Vnode of directory to create directory
    /* 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;
    }
 
@@ -2066,7 +2060,7 @@ HgfsMkdir(struct vnode *dvp,      // IN: Vnode of directory to create directory
    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) {
@@ -2077,16 +2071,16 @@ HgfsMkdir(struct vnode *dvp,      // IN: Vnode of directory to create directory
    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. */
@@ -2094,15 +2088,14 @@ HgfsMkdir(struct vnode *dvp,      // IN: Vnode of directory to create 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;
 }
 
@@ -3697,8 +3690,8 @@ HgfsDirOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
    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;
@@ -3708,7 +3701,6 @@ HgfsDirOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
    /* Submit the request to the Hgfs server */
    ret = HgfsSubmitRequest(sip, req);
    if (ret) {
-      /* HgfsSubmitRequest destroys the request if necessary */
       goto out;
    }
 
@@ -3719,7 +3711,7 @@ HgfsDirOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
    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);
@@ -3731,7 +3723,7 @@ HgfsDirOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
       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;
@@ -3740,13 +3732,13 @@ HgfsDirOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
       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() */
@@ -3754,17 +3746,16 @@ HgfsDirOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
    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;
 }
@@ -3822,8 +3813,8 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
       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;
@@ -3835,8 +3826,8 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
       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;
@@ -3851,8 +3842,8 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
       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;
 
@@ -3861,7 +3852,6 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
 
    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;
    }
@@ -3871,7 +3861,7 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
    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) {
@@ -3879,7 +3869,7 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
       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. */
@@ -3890,31 +3880,31 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
       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;
    }
 
    /*
@@ -3925,17 +3915,16 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
    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;
 }
 
@@ -3989,15 +3978,14 @@ HgfsDirClose(HgfsSuperInfo *sip,        // IN: Superinfo pointer
             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;
    }
 
@@ -4007,7 +3995,7 @@ HgfsDirClose(HgfsSuperInfo *sip,        // IN: Superinfo pointer
    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);
@@ -4016,7 +4004,7 @@ HgfsDirClose(HgfsSuperInfo *sip,        // IN: Superinfo pointer
    /* 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. */
@@ -4024,17 +4012,16 @@ HgfsDirClose(HgfsSuperInfo *sip,        // IN: Superinfo pointer
    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;
 }
 
@@ -4084,15 +4071,14 @@ HgfsFileClose(HgfsSuperInfo *sip,       // IN: Superinfo pointer
       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;
    }
@@ -4100,7 +4086,7 @@ HgfsFileClose(HgfsSuperInfo *sip,       // IN: Superinfo pointer
    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;
@@ -4115,32 +4101,31 @@ HgfsFileClose(HgfsSuperInfo *sip,       // IN: Superinfo pointer
       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;
 }
@@ -4203,7 +4188,6 @@ HgfsGetNextDirEntry(HgfsSuperInfo *sip,         // IN: Superinfo pointer
 
    ret = HgfsSubmitRequest(sip, req);
    if (ret) {
-      /* HgfsSubmitRequest will destroy the request if necessary. */
       DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: HgfsSubmitRequest failed.\n");
       goto out;
    }
@@ -4214,7 +4198,7 @@ HgfsGetNextDirEntry(HgfsSuperInfo *sip,         // IN: Superinfo pointer
    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",
@@ -4226,14 +4210,14 @@ HgfsGetNextDirEntry(HgfsSuperInfo *sip,         // IN: Superinfo pointer
       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 */
@@ -4241,7 +4225,7 @@ HgfsGetNextDirEntry(HgfsSuperInfo *sip,         // IN: Superinfo pointer
       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 */
@@ -4249,7 +4233,7 @@ HgfsGetNextDirEntry(HgfsSuperInfo *sip,         // IN: Superinfo pointer
        (reply->fileName.length > HGFS_PAYLOAD_MAX(reply)) ) {
       DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: filename is too long.\n");
       ret = EOVERFLOW;
-      goto destroy_out;
+      goto out;
    }
 
    /*
@@ -4262,9 +4246,8 @@ HgfsGetNextDirEntry(HgfsSuperInfo *sip,         // IN: Superinfo pointer
    ret = 0;
 
    DEBUG(VM_DEBUG_DONE, "HgfsGetNextDirEntry: done.\n");
-destroy_out:
-   HgfsDestroyReq(sip, req);
 out:
+   HgfsDestroyReq(sip, req);
    return ret;
 }
 
@@ -4332,8 +4315,7 @@ HgfsDoRead(HgfsSuperInfo *sip,  // IN: Superinfo pointer
    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;
@@ -4345,13 +4327,13 @@ HgfsDoRead(HgfsSuperInfo *sip,  // IN: Superinfo pointer
    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;
    }
 
    /*
@@ -4370,7 +4352,7 @@ HgfsDoRead(HgfsSuperInfo *sip,  // IN: Superinfo pointer
       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 */
@@ -4380,16 +4362,15 @@ HgfsDoRead(HgfsSuperInfo *sip,  // IN: Superinfo pointer
       /* 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;
 }
 
@@ -4464,8 +4445,8 @@ HgfsDoWrite(HgfsSuperInfo *sip, // IN: Superinfo pointer
             "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. */
@@ -4487,30 +4468,29 @@ HgfsDoWrite(HgfsSuperInfo *sip, // IN: Superinfo pointer
    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;
 }
 
@@ -4561,8 +4541,8 @@ HgfsDelete(HgfsSuperInfo *sip,          // IN: Superinfo
    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;
@@ -4572,10 +4552,9 @@ HgfsDelete(HgfsSuperInfo *sip,          // IN: Superinfo
 
    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;
    }
 
@@ -4585,7 +4564,7 @@ HgfsDelete(HgfsSuperInfo *sip,          // IN: Superinfo
    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. */
@@ -4597,40 +4576,39 @@ HgfsDelete(HgfsSuperInfo *sip,          // IN: Superinfo
    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;
 }
 
@@ -4658,23 +4636,65 @@ out:
  */
 
 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;
 }
 
 
@@ -4685,16 +4705,6 @@ HgfsGetSuperInfo()
  *
  *    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.
  *
@@ -4705,40 +4715,22 @@ HgfsGetSuperInfo()
  */
 
 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;
 }
@@ -4753,10 +4745,6 @@ HgfsSetVnodeOps(HgfsSuperInfo *sip,     // IN: Superinfo pointer
  *    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.
  *
@@ -4766,11 +4754,12 @@ HgfsSetVnodeOps(HgfsSuperInfo *sip,     // IN: Superinfo pointer
  *----------------------------------------------------------------------------
  */
 
-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),
@@ -4824,11 +4813,9 @@ HgfsMakeVnodeOps(HgfsSuperInfo *sip)    // IN: Superinfo
       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
@@ -4837,21 +4824,47 @@ HgfsMakeVnodeOps(HgfsSuperInfo *sip)    // IN: Superinfo
    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
+}
 
 
 /*
@@ -4864,7 +4877,7 @@ HgfsMakeVnodeOps(HgfsSuperInfo *sip)    // IN: Superinfo
  *
  * 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
@@ -4886,64 +4899,32 @@ HgfsSubmitRequest(HgfsSuperInfo *sip,   // IN: Superinfo containing request list
                                         //     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);
@@ -4953,7 +4934,7 @@ HgfsSubmitRequest(HgfsSuperInfo *sip,   // IN: Superinfo containing request list
       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
@@ -4970,20 +4951,18 @@ HgfsSubmitRequest(HgfsSuperInfo *sip,   // IN: Superinfo containing request list
 
          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);
@@ -4992,9 +4971,9 @@ HgfsSubmitRequest(HgfsSuperInfo *sip,   // IN: Superinfo containing request list
    /* 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;
 }
 
 
@@ -5023,7 +5002,7 @@ HgfsValidateReply(HgfsReq *req,         // IN: Request that contains reply data
    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;
@@ -5519,7 +5498,7 @@ HgfsMakeFullName(const char *path,      // IN:  Path of directory containing fil
    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:
index 3ea55194595b4c686029cc32642bc889df1570b4..e1a1551a73aacf4891eea62a1f611c85a04cd9f6 100644 (file)
 
 #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
index eae114d7723fd4329db704454eb5914ee3781b9f..31b6cdd241b78475284ffd76fd71794c6f32b476 100644 (file)
@@ -438,7 +438,7 @@ FLAGDEF(  87, EDX, AMD,     4,  1, TM,                  NA,  IGNORE, 0, FALSE)
 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) \
@@ -642,6 +642,9 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #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)
+
 /*
  *----------------------------------------------------------------------
  *
@@ -813,6 +816,17 @@ CPUID_FAMILY_IS_K8STAR(uint32 _eax)
           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
diff --git a/open-vm-tools/modules/solaris/vmxnet/COPYING.CDDL b/open-vm-tools/modules/solaris/vmxnet/COPYING.CDDL
new file mode 100644 (file)
index 0000000..883d599
--- /dev/null
@@ -0,0 +1,365 @@
+
+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.
+
diff --git a/open-vm-tools/modules/solaris/vmxnet/Makefile b/open-vm-tools/modules/solaris/vmxnet/Makefile
new file mode 100644 (file)
index 0000000..9d94e0f
--- /dev/null
@@ -0,0 +1,111 @@
+#!/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)
diff --git a/open-vm-tools/modules/solaris/vmxnet/includeCheck.h b/open-vm-tools/modules/solaris/vmxnet/includeCheck.h
new file mode 100644 (file)
index 0000000..3da2e00
--- /dev/null
@@ -0,0 +1,130 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/modules/solaris/vmxnet/net.h b/open-vm-tools/modules/solaris/vmxnet/net.h
new file mode 100644 (file)
index 0000000..ac71a38
--- /dev/null
@@ -0,0 +1,134 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/modules/solaris/vmxnet/net_sg.h b/open-vm-tools/modules/solaris/vmxnet/net_sg.h
new file mode 100644 (file)
index 0000000..c90e376
--- /dev/null
@@ -0,0 +1,70 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/modules/solaris/vmxnet/vm_basic_types.h b/open-vm-tools/modules/solaris/vmxnet/vm_basic_types.h
new file mode 100644 (file)
index 0000000..dc0ad61
--- /dev/null
@@ -0,0 +1,956 @@
+/*********************************************************
+ * 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_ */
diff --git a/open-vm-tools/modules/solaris/vmxnet/vm_device_version.h b/open-vm-tools/modules/solaris/vmxnet/vm_device_version.h
new file mode 100644 (file)
index 0000000..a27b23a
--- /dev/null
@@ -0,0 +1,193 @@
+/*********************************************************
+ * 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 */
diff --git a/open-vm-tools/modules/solaris/vmxnet/vmnet_def.h b/open-vm-tools/modules/solaris/vmxnet/vmnet_def.h
new file mode 100644 (file)
index 0000000..c02c5fe
--- /dev/null
@@ -0,0 +1,62 @@
+/*********************************************************
+ * 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_
diff --git a/open-vm-tools/modules/solaris/vmxnet/vmxnet.c b/open-vm-tools/modules/solaris/vmxnet/vmxnet.c
new file mode 100644 (file)
index 0000000..e0046d8
--- /dev/null
@@ -0,0 +1,2438 @@
+/*********************************************************
+ * 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)&regs, &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));
+}
+
diff --git a/open-vm-tools/modules/solaris/vmxnet/vmxnet2_def.h b/open-vm-tools/modules/solaris/vmxnet/vmxnet2_def.h
new file mode 100644 (file)
index 0000000..5fede92
--- /dev/null
@@ -0,0 +1,414 @@
+/*********************************************************
+ * 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
+
diff --git a/open-vm-tools/modules/solaris/vmxnet/vmxnet_def.h b/open-vm-tools/modules/solaris/vmxnet/vmxnet_def.h
new file mode 100644 (file)
index 0000000..841a250
--- /dev/null
@@ -0,0 +1,168 @@
+/*********************************************************
+ * 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_ */
diff --git a/open-vm-tools/services/Makefile.am b/open-vm-tools/services/Makefile.am
new file mode 100644 (file)
index 0000000..21b7928
--- /dev/null
@@ -0,0 +1,25 @@
+################################################################################
+### 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
+
diff --git a/open-vm-tools/services/plugins/COPYING b/open-vm-tools/services/plugins/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/services/plugins/Makefile.am b/open-vm-tools/services/plugins/Makefile.am
new file mode 100644 (file)
index 0000000..cd0a63b
--- /dev/null
@@ -0,0 +1,31 @@
+################################################################################
+### 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
+
diff --git a/open-vm-tools/services/plugins/guestInfo/COPYING b/open-vm-tools/services/plugins/guestInfo/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/services/plugins/guestInfo/Makefile.am b/open-vm-tools/services/plugins/guestInfo/Makefile.am
new file mode 100644 (file)
index 0000000..89c5c89
--- /dev/null
@@ -0,0 +1,38 @@
+################################################################################
+### 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)
+
diff --git a/open-vm-tools/services/plugins/guestInfo/guestInfoInt.h b/open-vm-tools/services/plugins/guestInfo/guestInfoInt.h
new file mode 100644 (file)
index 0000000..76a2731
--- /dev/null
@@ -0,0 +1,30 @@
+/*********************************************************
+ * 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);
+
diff --git a/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c b/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c
new file mode 100644 (file)
index 0000000..c82b2e9
--- /dev/null
@@ -0,0 +1,1043 @@
+/*********************************************************
+ * 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 &regData;
+}
+
diff --git a/open-vm-tools/services/plugins/guestInfo/perfMonLinux.c b/open-vm-tools/services/plugins/guestInfo/perfMonLinux.c
new file mode 100644 (file)
index 0000000..dc7afc2
--- /dev/null
@@ -0,0 +1,209 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/services/plugins/hgfsServer/COPYING b/open-vm-tools/services/plugins/hgfsServer/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/services/plugins/hgfsServer/Makefile.am b/open-vm-tools/services/plugins/hgfsServer/Makefile.am
new file mode 100644 (file)
index 0000000..5839e92
--- /dev/null
@@ -0,0 +1,41 @@
+################################################################################
+### 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
+
diff --git a/open-vm-tools/services/plugins/hgfsServer/hgfsPlugin.c b/open-vm-tools/services/plugins/hgfsServer/hgfsPlugin.c
new file mode 100644 (file)
index 0000000..6861e3f
--- /dev/null
@@ -0,0 +1,173 @@
+/*********************************************************
+ * 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, &regData }
+      };
+      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 &regData;
+}
diff --git a/open-vm-tools/services/plugins/powerOps/COPYING b/open-vm-tools/services/plugins/powerOps/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/services/plugins/powerOps/Makefile.am b/open-vm-tools/services/plugins/powerOps/Makefile.am
new file mode 100644 (file)
index 0000000..68fbfad
--- /dev/null
@@ -0,0 +1,35 @@
+################################################################################
+### 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)
+
diff --git a/open-vm-tools/services/plugins/powerOps/powerOps.c b/open-vm-tools/services/plugins/powerOps/powerOps.c
new file mode 100644 (file)
index 0000000..8540cf0
--- /dev/null
@@ -0,0 +1,465 @@
+/*********************************************************
+ * 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, &regData }
+   };
+   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 &regData;
+}
+
diff --git a/open-vm-tools/services/plugins/resolutionSet/COPYING b/open-vm-tools/services/plugins/resolutionSet/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/services/plugins/resolutionSet/Makefile.am b/open-vm-tools/services/plugins/resolutionSet/Makefile.am
new file mode 100644 (file)
index 0000000..bce9db0
--- /dev/null
@@ -0,0 +1,41 @@
+################################################################################
+### 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)
+
diff --git a/open-vm-tools/services/plugins/resolutionSet/libvmwarectrl.c b/open-vm-tools/services/plugins/resolutionSet/libvmwarectrl.c
new file mode 100644 (file)
index 0000000..80abd41
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * 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
diff --git a/open-vm-tools/services/plugins/resolutionSet/libvmwarectrl.h b/open-vm-tools/services/plugins/resolutionSet/libvmwarectrl.h
new file mode 100644 (file)
index 0000000..83ae096
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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_ */
diff --git a/open-vm-tools/services/plugins/resolutionSet/resolutionInt.h b/open-vm-tools/services/plugins/resolutionSet/resolutionInt.h
new file mode 100644 (file)
index 0000000..1cc3462
--- /dev/null
@@ -0,0 +1,81 @@
+/*********************************************************
+ * 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_
diff --git a/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c b/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c
new file mode 100644 (file)
index 0000000..4177925
--- /dev/null
@@ -0,0 +1,385 @@
+/*********************************************************
+ * 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, &regData },
+      { TOOLS_CORE_SIG_SHUTDOWN, ResolutionSetShutdown, &regData }
+   };
+   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 &regData;
+}
diff --git a/open-vm-tools/services/plugins/resolutionSet/resolutionX11.c b/open-vm-tools/services/plugins/resolutionSet/resolutionX11.c
new file mode 100644 (file)
index 0000000..c4ed0fd
--- /dev/null
@@ -0,0 +1,471 @@
+/*********************************************************
+ * 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;
+}
diff --git a/open-vm-tools/services/plugins/resolutionSet/vmwarectrl.h b/open-vm-tools/services/plugins/resolutionSet/vmwarectrl.h
new file mode 100644 (file)
index 0000000..a671ae1
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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_ */
diff --git a/open-vm-tools/services/plugins/resolutionSet/vmwarectrlproto.h b/open-vm-tools/services/plugins/resolutionSet/vmwarectrlproto.h
new file mode 100644 (file)
index 0000000..76f157f
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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_ */
diff --git a/open-vm-tools/services/plugins/timeSync/COPYING b/open-vm-tools/services/plugins/timeSync/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/services/plugins/timeSync/Makefile.am b/open-vm-tools/services/plugins/timeSync/Makefile.am
new file mode 100644 (file)
index 0000000..3570cae
--- /dev/null
@@ -0,0 +1,35 @@
+################################################################################
+### 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)
+
diff --git a/open-vm-tools/services/plugins/timeSync/timeSync.c b/open-vm-tools/services/plugins/timeSync/timeSync.c
new file mode 100644 (file)
index 0000000..22972af
--- /dev/null
@@ -0,0 +1,579 @@
+/*********************************************************
+ * 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, &regData },
+      { TOOLS_CORE_SIG_SHUTDOWN, TimeSyncShutdown, &regData }
+   };
+   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 &regData;
+}
+
diff --git a/open-vm-tools/services/plugins/vix/COPYING b/open-vm-tools/services/plugins/vix/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/services/plugins/vix/Makefile.am b/open-vm-tools/services/plugins/vix/Makefile.am
new file mode 100644 (file)
index 0000000..3a82875
--- /dev/null
@@ -0,0 +1,46 @@
+################################################################################
+### 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
+
diff --git a/open-vm-tools/services/plugins/vix/vixPlugin.c b/open-vm-tools/services/plugins/vix/vixPlugin.c
new file mode 100644 (file)
index 0000000..d236da6
--- /dev/null
@@ -0,0 +1,100 @@
+/*********************************************************
+ * 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 &regData;
+}
+
diff --git a/open-vm-tools/services/plugins/vix/vixPluginInt.h b/open-vm-tools/services/plugins/vix/vixPluginInt.h
new file mode 100644 (file)
index 0000000..5381489
--- /dev/null
@@ -0,0 +1,60 @@
+/*********************************************************
+ * 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_ */
+
diff --git a/open-vm-tools/services/plugins/vixUser/COPYING b/open-vm-tools/services/plugins/vixUser/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/services/plugins/vixUser/Makefile.am b/open-vm-tools/services/plugins/vixUser/Makefile.am
new file mode 100644 (file)
index 0000000..860c630
--- /dev/null
@@ -0,0 +1,39 @@
+################################################################################
+### 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)
+
diff --git a/open-vm-tools/services/plugins/vixUser/vixUser.c b/open-vm-tools/services/plugins/vixUser/vixUser.c
new file mode 100644 (file)
index 0000000..c424dd0
--- /dev/null
@@ -0,0 +1,379 @@
+/*********************************************************
+ * 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 &regData;
+}
diff --git a/open-vm-tools/services/plugins/vmbackup/COPYING b/open-vm-tools/services/plugins/vmbackup/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/services/plugins/vmbackup/Makefile.am b/open-vm-tools/services/plugins/vmbackup/Makefile.am
new file mode 100644 (file)
index 0000000..6aab916
--- /dev/null
@@ -0,0 +1,37 @@
+################################################################################
+### 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)
+
diff --git a/open-vm-tools/services/plugins/vmbackup/README b/open-vm-tools/services/plugins/vmbackup/README
new file mode 100644 (file)
index 0000000..763d658
--- /dev/null
@@ -0,0 +1,42 @@
+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.
+
diff --git a/open-vm-tools/services/plugins/vmbackup/scriptOps.c b/open-vm-tools/services/plugins/vmbackup/scriptOps.c
new file mode 100644 (file)
index 0000000..e4ac106
--- /dev/null
@@ -0,0 +1,485 @@
+/*********************************************************
+ * 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;
+}
+
diff --git a/open-vm-tools/services/plugins/vmbackup/stateMachine.c b/open-vm-tools/services/plugins/vmbackup/stateMachine.c
new file mode 100644 (file)
index 0000000..c18ab24
--- /dev/null
@@ -0,0 +1,649 @@
+/*********************************************************
+ * 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 &regData;
+   }
+
+   return NULL;
+}
+
diff --git a/open-vm-tools/services/plugins/vmbackup/syncDriverOps.c b/open-vm-tools/services/plugins/vmbackup/syncDriverOps.c
new file mode 100644 (file)
index 0000000..5acb2a4
--- /dev/null
@@ -0,0 +1,381 @@
+/*********************************************************
+ * 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;
+}
+
diff --git a/open-vm-tools/services/plugins/vmbackup/vmBackupInt.h b/open-vm-tools/services/plugins/vmbackup/vmBackupInt.h
new file mode 100644 (file)
index 0000000..f9e2da3
--- /dev/null
@@ -0,0 +1,212 @@
+/*********************************************************
+ * 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_*/
+
diff --git a/open-vm-tools/services/vmtoolsd/COPYING b/open-vm-tools/services/vmtoolsd/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/services/vmtoolsd/Makefile.am b/open-vm-tools/services/vmtoolsd/Makefile.am
new file mode 100644 (file)
index 0000000..661e992
--- /dev/null
@@ -0,0 +1,69 @@
+################################################################################
+### 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
diff --git a/open-vm-tools/services/vmtoolsd/cmdLine.c b/open-vm-tools/services/vmtoolsd/cmdLine.c
new file mode 100644 (file)
index 0000000..a1c74ee
--- /dev/null
@@ -0,0 +1,255 @@
+/*********************************************************
+ * 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;
+}
+
diff --git a/open-vm-tools/services/vmtoolsd/mainLoop.c b/open-vm-tools/services/vmtoolsd/mainLoop.c
new file mode 100644 (file)
index 0000000..9b3364d
--- /dev/null
@@ -0,0 +1,245 @@
+/*********************************************************
+ * 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;
+}
+
diff --git a/open-vm-tools/services/vmtoolsd/mainPosix.c b/open-vm-tools/services/vmtoolsd/mainPosix.c
new file mode 100644 (file)
index 0000000..1d3e296
--- /dev/null
@@ -0,0 +1,123 @@
+/*********************************************************
+ * 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;
+}
+
diff --git a/open-vm-tools/services/vmtoolsd/pluginMgr.c b/open-vm-tools/services/vmtoolsd/pluginMgr.c
new file mode 100644 (file)
index 0000000..46a065a
--- /dev/null
@@ -0,0 +1,309 @@
+/*********************************************************
+ * 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;
+}
+
diff --git a/open-vm-tools/services/vmtoolsd/serviceObj.c b/open-vm-tools/services/vmtoolsd/serviceObj.c
new file mode 100644 (file)
index 0000000..1e1a994
--- /dev/null
@@ -0,0 +1,198 @@
+/*********************************************************
+ * 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;
+}
+
diff --git a/open-vm-tools/services/vmtoolsd/serviceObj.h b/open-vm-tools/services/vmtoolsd/serviceObj.h
new file mode 100644 (file)
index 0000000..4b771f3
--- /dev/null
@@ -0,0 +1,48 @@
+/*********************************************************
+ * 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_ */
+
diff --git a/open-vm-tools/services/vmtoolsd/svcSignals.gm b/open-vm-tools/services/vmtoolsd/svcSignals.gm
new file mode 100644 (file)
index 0000000..973f3a0
--- /dev/null
@@ -0,0 +1,36 @@
+##########################################################
+# 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
+
diff --git a/open-vm-tools/services/vmtoolsd/toolsCoreInt.h b/open-vm-tools/services/vmtoolsd/toolsCoreInt.h
new file mode 100644 (file)
index 0000000..bb8408a
--- /dev/null
@@ -0,0 +1,106 @@
+/*********************************************************
+ * 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_ */
+
diff --git a/open-vm-tools/services/vmtoolsd/toolsRpc.c b/open-vm-tools/services/vmtoolsd/toolsRpc.c
new file mode 100644 (file)
index 0000000..daaf1f1
--- /dev/null
@@ -0,0 +1,329 @@
+/*********************************************************
+ * 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);
+   }
+}
+
diff --git a/open-vm-tools/tests/Makefile.am b/open-vm-tools/tests/Makefile.am
new file mode 100644 (file)
index 0000000..f0ce8db
--- /dev/null
@@ -0,0 +1,22 @@
+################################################################################
+### 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
+
diff --git a/open-vm-tools/tests/testDebug/COPYING b/open-vm-tools/tests/testDebug/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/tests/testDebug/Makefile.am b/open-vm-tools/tests/testDebug/Makefile.am
new file mode 100644 (file)
index 0000000..f35c225
--- /dev/null
@@ -0,0 +1,34 @@
+################################################################################
+### 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
+
diff --git a/open-vm-tools/tests/testDebug/testDebug.c b/open-vm-tools/tests/testDebug/testDebug.c
new file mode 100644 (file)
index 0000000..eccb5ee
--- /dev/null
@@ -0,0 +1,243 @@
+/*********************************************************
+ * 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 &regData;
+}
+
diff --git a/open-vm-tools/tests/testPlugin/COPYING b/open-vm-tools/tests/testPlugin/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/tests/testPlugin/Makefile.am b/open-vm-tools/tests/testPlugin/Makefile.am
new file mode 100644 (file)
index 0000000..3cc523b
--- /dev/null
@@ -0,0 +1,60 @@
+################################################################################
+### 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
+
diff --git a/open-vm-tools/tests/testPlugin/testData.x b/open-vm-tools/tests/testPlugin/testData.x
new file mode 100644 (file)
index 0000000..5c5e86d
--- /dev/null
@@ -0,0 +1,28 @@
+/*********************************************************
+ * 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>;
+};
+
diff --git a/open-vm-tools/tests/testPlugin/testPlugin.c b/open-vm-tools/tests/testPlugin/testPlugin.c
new file mode 100644 (file)
index 0000000..5ccb6cd
--- /dev/null
@@ -0,0 +1,302 @@
+/*********************************************************
+ * 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, &regData },
+      { TOOLS_CORE_SIG_SHUTDOWN, TestPluginShutdown, &regData },
+      { TOOLS_CORE_SIG_CAPABILITIES, TestPluginCapabilities, &regData },
+      { TOOLS_CORE_SIG_SET_OPTION, TestPluginSetOption, &regData },
+#if defined(G_PLATFORM_WIN32)
+      { TOOLS_CORE_SIG_SESSION_CHANGE, TestPluginSessionChange, &regData },
+#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 &regData;
+}
+
diff --git a/open-vm-tools/tests/vmrpcdbg/COPYING b/open-vm-tools/tests/vmrpcdbg/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 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!
diff --git a/open-vm-tools/tests/vmrpcdbg/Makefile.am b/open-vm-tools/tests/vmrpcdbg/Makefile.am
new file mode 100644 (file)
index 0000000..3fa481d
--- /dev/null
@@ -0,0 +1,35 @@
+################################################################################
+### 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
+
diff --git a/open-vm-tools/tests/vmrpcdbg/debugChannel.c b/open-vm-tools/tests/vmrpcdbg/debugChannel.c
new file mode 100644 (file)
index 0000000..3b954b1
--- /dev/null
@@ -0,0 +1,316 @@
+/*********************************************************
+ * 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;
+}
+
diff --git a/open-vm-tools/tests/vmrpcdbg/vmrpcdbg.c b/open-vm-tools/tests/vmrpcdbg/vmrpcdbg.c
new file mode 100644 (file)
index 0000000..9679efc
--- /dev/null
@@ -0,0 +1,165 @@
+/*********************************************************
+ * 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;
+   }
+}
+
index c70d92d149da3f08b173c7e807e2cb4fb30e355b..a223de54d9815f8013469c616ed321bc391caa32 100644 (file)
@@ -60,10 +60,14 @@ if HAVE_X11
    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:
@@ -87,29 +91,27 @@ endif
        $(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@
@@ -121,5 +123,3 @@ else
    vmware_toolbox_cmd_LINK = $(LINK)
 endif
 
-endif
-
index 30e621d36dbe84087259124ad44ce4580de0e6b6..f5706d9b7630890d8b532eb2b6e423f2362f0967 100644 (file)
@@ -78,13 +78,11 @@ static int DiskCommand(char **argv, int argc);
 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);
@@ -100,7 +98,6 @@ static CmdTable commands[] = {
    { "disk", DiskCommand, TRUE, DiskHelp},
    { "stat", StatCommand, FALSE, StatHelp},
    { "device", DeviceCommand, FALSE, DeviceHelp},
-   { "record", RecordCommand, FALSE, RecordHelp},
    { "help", HelpCommand, FALSE, ToolboxCmdHelp},
    { NULL, } };
 
@@ -155,14 +152,14 @@ CheckArgumentLength(char **argv, // IN: The command line arguments.
 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);
 }
 
 
@@ -185,20 +182,20 @@ DeviceHelp(char *progName) // IN: The name of the program obtained from argv[0]
 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);
 }
 
 
@@ -221,13 +218,12 @@ ToolboxCmdHelp(char *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);
 }
 
 
@@ -250,14 +246,14 @@ TimeSyncHelp(char *progName) // IN: The name of the program obtained from argv[0
 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);
 }
 
 
@@ -308,47 +304,20 @@ DiskHelp(char *progName) // IN: The name of the program obtained from argv[0]
 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);
 }
 
 
@@ -621,42 +590,6 @@ TimeSyncCommand(char **argv, // IN: command line arguments
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * 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;
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -721,7 +654,7 @@ main(int argc,    // IN: length of command line arguments
     * 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);
    }
 
index 8f1659e76a8a9574aef9c8e61e726c0807d0dcc1..69f14976f4033a9527be12570f0f82418164578b 100644 (file)
@@ -71,7 +71,7 @@ RpcIn *gRpcInCtlPanel;
 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[] = {
@@ -80,7 +80,6 @@ static const char *gHelpPages[] = {
    "tools_devices.htm",
    "tools_scripts.htm",
    "tools_shrink.htm",
-   NULL,                        // Record/Replay
    "tools_about.htm",
 };
 
@@ -602,8 +601,6 @@ ToolsMain_Create(void)
                             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
@@ -611,8 +608,6 @@ ToolsMain_Create(void)
                             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
@@ -901,13 +896,13 @@ OnViewportSizeRequest(GtkWidget *widget,           // IN
  */
 
 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;
 
@@ -918,14 +913,14 @@ InitHelpDir(GuestApp_Dict *pConfDict)   // IN
 
       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;
    }
 }
 
@@ -987,7 +982,7 @@ main(int argc,                  // IN: ARRAY_SIZEOF(argv)
 {
    Bool optIconify, optHelp, optVersion;
    struct sigaction olds[ARRAYSIZE(gSignals)];
-   GuestApp_Dict *pConfDict;
+   GKeyFile *pConfDict;
 
    if (!VmCheck_IsVirtualWorld()) {
 #ifndef ALLOW_TOOLS_IN_FOREIGN_VM
@@ -1003,11 +998,14 @@ main(int argc,                  // IN: ARRAY_SIZEOF(argv)
       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;
 
@@ -1130,7 +1128,7 @@ main(int argc,                  // IN: ARRAY_SIZEOF(argv)
 
    gdk_pixmap_unref(pixmap);
    gdk_bitmap_unref(bitmask);
-   free(hlpDir);
+   g_free(hlpDir);
 
    return 0;
 }
index de9b924d1e79fd65fff80bfefb8c43360da5bbef..abf9cdf564e47e0d1e2bf54ce3ea575e4521259b 100644 (file)
@@ -134,7 +134,7 @@ About_Create(GtkWidget* mainWnd)
    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);
index 8cf14e3fe93334bfd925b8f97fdad1ee0546b178..452342bdafc6af052cba9c7fafccc605723d1bc0 100644 (file)
@@ -111,10 +111,4 @@ int Stat_GetMemorySwapped(void);
 int Stat_GetMemoryLimit(void);
 int Stat_GetMemoryReservation(void);
 
-/*
- * Record commands
- */
-Bool Record_StartRecording(void);
-Bool Record_StopRecording(void);
-
 #endif /*_TOOLBOX_CMD_H_*/
index 1cb1d78d465dc264a5bed2b8b8d9ad193adc1b81..29ac2bdf26d5a04a23f54e0f32a54670099c583c 100644 (file)
 #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
 
@@ -71,7 +69,6 @@ GtkWidget* Devices_Create(GtkWidget* mainWnd);
 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);
@@ -84,5 +81,6 @@ extern GdkColormap* colormap;
 extern GtkWidget *optionsTimeSync;
 extern DblLnkLst_Links *gEventQueue;
 extern GtkWidget *scriptsApply;
+extern const char **gNativeEnviron;
 
 #endif // _TOOLBOX_INT_H_
diff --git a/open-vm-tools/toolbox/toolboxInt.c b/open-vm-tools/toolbox/toolboxInt.c
new file mode 100644 (file)
index 0000000..8869024
--- /dev/null
@@ -0,0 +1,112 @@
+/*********************************************************
+ * 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;
+}
+
index 0d8d12eff60f3dcfb610f4a92c964cb06da1307b..62616a1fcd14e27b103bdf2edbb6637290458dc9 100644 (file)
@@ -24,6 +24,7 @@
 #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_*/
diff --git a/open-vm-tools/toolbox/toolboxRecord.c b/open-vm-tools/toolbox/toolboxRecord.c
deleted file mode 100644 (file)
index 7fbfc2b..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*********************************************************
- * 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);
-   }
-}
-
index 45a3d7bedf14b549a98fe8caa842d66dbed953b3..d0a7470cffc7b981c443b249ba1d323936eaa985 100644 (file)
 #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
@@ -51,7 +54,7 @@ GtkWidget *scriptsApply;
 /* 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;
@@ -103,7 +106,7 @@ Scripts_Create(GtkWidget* mainWnd)
    GList *items = NULL;
    GSList *radiobtn_group = NULL;
 
-   confDict = Conf_Load();
+   confDict = Toolbox_LoadToolsConf();
 
    scriptstab = gtk_vbox_new(FALSE, 10);
    gtk_widget_show(scriptstab);
@@ -144,7 +147,7 @@ Scripts_Create(GtkWidget* mainWnd)
 #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
@@ -157,13 +160,13 @@ Scripts_Create(GtkWidget* mainWnd)
                          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";
@@ -341,26 +344,33 @@ void
 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);
@@ -369,7 +379,7 @@ Scripts_OnComboChanged(gpointer entry, // IN: the entry selected
                                     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);
    }
@@ -394,6 +404,7 @@ Scripts_OnComboChanged(gpointer entry, // IN: the entry selected
                                       GTK_SIGNAL_FUNC(Scripts_OnUseScriptToggled),
                                       NULL);
    Scripts_UpdateEnabled();
+   g_free(path);
 }
 
 
@@ -472,8 +483,9 @@ Scripts_OnApply(gpointer btn,  // IN: unused
                 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));
@@ -486,9 +498,11 @@ Scripts_OnApply(gpointer btn,  // IN: unused
    } 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));
 
@@ -496,15 +510,15 @@ Scripts_OnApply(gpointer btn,  // IN: unused
       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);
 
@@ -539,8 +553,10 @@ void
 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 "
@@ -548,20 +564,46 @@ Scripts_OnEdit(gpointer btn,  // IN: unused
       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);
 }
 
 
@@ -587,12 +629,22 @@ Scripts_OnRun(gpointer btn,  // IN: unused
               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);
 }
 
 
diff --git a/open-vm-tools/toolbox/toolboxcmd-record.c b/open-vm-tools/toolbox/toolboxcmd-record.c
deleted file mode 100644 (file)
index f759769..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*********************************************************
- * 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;
-   }
-}
-
index 67ed129c9f52015f6c1c6cd56ae4e3898abdcade..2b3f170aea4162af6406c0c0a0a4318f80397079 100644 (file)
  *     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"
@@ -43,7 +46,6 @@ typedef enum ScriptType {
 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);
 
 
 /*
@@ -82,12 +84,13 @@ GetConfName(char *apm) // IN: apm name.
 /*
  *-----------------------------------------------------------------------------
  *
- * 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.
@@ -95,66 +98,79 @@ GetConfName(char *apm) // IN: apm name.
  *-----------------------------------------------------------------------------
  */
 
-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;
 }
 
 
@@ -234,8 +250,11 @@ ScriptToggle(char *apm,       // IN: APM name
 {
    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) {
@@ -243,15 +262,25 @@ ScriptToggle(char *apm,       // IN: APM name
       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;
 }
 
 
@@ -328,20 +357,35 @@ Script_Set(char *apm,        // IN: APM name
            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;
 }
 
index e2ef67b3185676c55471a35a4d5cd98e5b0e1ae3..814386bffe67dd53a10b74f545c5a974d5128d96 100644 (file)
@@ -19,13 +19,21 @@ bin_PROGRAMS = vmware-user
 
 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
@@ -70,6 +78,7 @@ vmware_user_LDADD += ../lib/err/libErr.la
 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
@@ -87,7 +96,14 @@ if ENABLE_UNITY
    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
@@ -98,14 +114,21 @@ endif
 
 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@
@@ -118,7 +141,7 @@ endif
 
 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
diff --git a/open-vm-tools/vmware-user/copyPaste.cpp b/open-vm-tools/vmware-user/copyPaste.cpp
new file mode 100644 (file)
index 0000000..75ba686
--- /dev/null
@@ -0,0 +1,2088 @@
+/*********************************************************
+ * 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);
+   }
+}
diff --git a/open-vm-tools/vmware-user/copyPasteUI.cpp b/open-vm-tools/vmware-user/copyPasteUI.cpp
new file mode 100644 (file)
index 0000000..bba9781
--- /dev/null
@@ -0,0 +1,934 @@
+/*********************************************************
+ * 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. */
+}
+
diff --git a/open-vm-tools/vmware-user/copyPasteUI.h b/open-vm-tools/vmware-user/copyPasteUI.h
new file mode 100644 (file)
index 0000000..efc3a0b
--- /dev/null
@@ -0,0 +1,101 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/vmware-user/copyPasteV3.h b/open-vm-tools/vmware-user/copyPasteV3.h
deleted file mode 100644 (file)
index cdd9ab7..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*********************************************************
- * 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
diff --git a/open-vm-tools/vmware-user/copyPasteWrapper.cpp b/open-vm-tools/vmware-user/copyPasteWrapper.cpp
new file mode 100644 (file)
index 0000000..61b4924
--- /dev/null
@@ -0,0 +1,241 @@
+/*********************************************************
+ * 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__);
+   }
+}
+
+
diff --git a/open-vm-tools/vmware-user/copyPasteWrapper.h b/open-vm-tools/vmware-user/copyPasteWrapper.h
new file mode 100644 (file)
index 0000000..95b1e3f
--- /dev/null
@@ -0,0 +1,63 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/vmware-user/dnd.cpp b/open-vm-tools/vmware-user/dnd.cpp
new file mode 100644 (file)
index 0000000..926a85f
--- /dev/null
@@ -0,0 +1,2698 @@
+/*********************************************************
+ * 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;
+}
diff --git a/open-vm-tools/vmware-user/foundryToolsDaemon.c b/open-vm-tools/vmware-user/foundryToolsDaemon.c
deleted file mode 100644 (file)
index a0b8a2e..0000000
+++ /dev/null
@@ -1,1835 +0,0 @@
-/*********************************************************
- * 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
-
diff --git a/open-vm-tools/vmware-user/foundryToolsDaemon.h b/open-vm-tools/vmware-user/foundryToolsDaemon.h
deleted file mode 100644 (file)
index 5b0fc2a..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*********************************************************
- * 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__ */
diff --git a/open-vm-tools/vmware-user/stringxx/string.cc b/open-vm-tools/vmware-user/stringxx/string.cc
new file mode 100644 (file)
index 0000000..c2a0351
--- /dev/null
@@ -0,0 +1,2174 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/vmware-user/stringxx/string.hh b/open-vm-tools/vmware-user/stringxx/string.hh
new file mode 100644 (file)
index 0000000..442e786
--- /dev/null
@@ -0,0 +1,308 @@
+/*********************************************************
+ * 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
diff --git a/open-vm-tools/vmware-user/stringxx/ubstr_t.hh b/open-vm-tools/vmware-user/stringxx/ubstr_t.hh
new file mode 100644 (file)
index 0000000..2330934
--- /dev/null
@@ -0,0 +1,923 @@
+/*********************************************************
+ * 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
similarity index 94%
rename from open-vm-tools/vmware-user/vmware-user.c
rename to open-vm-tools/vmware-user/vmware-user.cpp
index 6a8d0b5abddb204745e835959cd44e3931889d34..e489d88f5e5cdbd0c3029b63efca0810514155f3 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * 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>
@@ -62,6 +65,7 @@
 #include "vmwareuser_version.h"
 
 #include "embed_version.h"
+} // extern "C"
 VM_EMBED_VERSION(VMWAREUSER_VERSION_STRING);
 
 #ifdef _DEBUG
@@ -94,14 +98,17 @@ Bool VMwareUserRpcInCapRegCB   (char const **result, size_t *resultLen,
                                 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);
 
 
 /*
@@ -110,7 +117,6 @@ static void ReloadSelf(void);
 
 static Bool gOpenUrlRegistered;
 static Bool gDnDRegistered;
-static Bool gCopyPasteRegistered;
 static Bool gHgfsServerRegistered;
 static pid_t gParentPid;
 static char gLogFilePath[PATH_MAX];
@@ -135,7 +141,6 @@ GtkWidget *gGHWnd;
 
 Window gXRoot;
 DblLnkLst_Links *gEventQueue;
-Bool optionCopyPaste;
 Bool optionDnD;
 Bool gCanUseVMwareCtrl;
 Bool gCanUseVMwareCtrlTopologySet;
@@ -198,9 +203,10 @@ void VMwareUserCleanupRpc(void)
          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;
@@ -244,7 +250,11 @@ void VMwareUserSignalHandler(int sig) // IN
       VMwareUserCleanupRpc();
    }
 
+#if defined(HAVE_GTKMM)
+   Gtk::Main::quit();
+#else
    gtk_main_quit();
+#endif
 }
 
 
@@ -270,7 +280,11 @@ VMwareUser_OnDestroy(GtkWidget *widget, // IN: Unused
                      gpointer data)     // IN: Unused
 {
    VMwareUserCleanupRpc();
+#if defined(HAVE_GTKMM)
+   Gtk::Main::quit();
+#else
    gtk_main_quit();
+#endif
 }
 
 
@@ -361,8 +375,9 @@ VMwareUserRpcInResetCB(RpcInData *data)   // IN/OUT
    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);
 }
@@ -439,16 +454,7 @@ VMwareUserRpcInCapRegCB(char const **result,     // OUT
       }
    }
 
-   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");
@@ -461,6 +467,39 @@ VMwareUserRpcInCapRegCB(char const **result,     // OUT
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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();
+      }
+   }
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -519,17 +558,9 @@ VMwareUserRpcInSetOptionCB(char const **result,     // OUT
     */
    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;
@@ -711,7 +742,6 @@ main(int argc, char *argv[])
 
    gOpenUrlRegistered = FALSE;
    gDnDRegistered = FALSE;
-   gCopyPasteRegistered = FALSE;
    gHgfsServerRegistered = FALSE;
    gBlockFd = -1;
    gReloadSelf = FALSE;
@@ -734,7 +764,11 @@ main(int argc, char *argv[])
    /* 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
@@ -918,7 +952,11 @@ main(int argc, char *argv[])
       /*
        * 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;
@@ -931,9 +969,9 @@ main(int argc, char *argv[])
             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");
@@ -1013,7 +1051,9 @@ InitGroupLeader(Window *groupLeader,    // OUT: group leader window
 {
    Window myGroupLeader;
    Window myRootWindow;
-   XSetWindowAttributes attr = { .override_redirect = True };
+   XSetWindowAttributes attr;
+
+   attr.override_redirect = True;
 
    ASSERT(groupLeader);
    ASSERT(rootWindow);
index a649717569c3bbaffe10d8a5cbd81a27e038628e..f2759878530bf1f435e2e450cf8dc24611830e10 100644 (file)
@@ -119,7 +119,6 @@ extern Display *gXDisplay;
 extern Window gXRoot;
 extern DblLnkLst_Links *gEventQueue;
 extern GtkWidget *gUserMainWidget;
-extern Bool optionCopyPaste;
 extern int gBlockFd;
 
 #endif // _VMWAREUSER_INT_H_