]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Internal branch sync. Included in this change:
authorVMware, Inc <>
Tue, 24 Aug 2010 18:41:49 +0000 (11:41 -0700)
committerMarcelo Vanzin <mvanzin@vmware.com>
Tue, 24 Aug 2010 18:41:49 +0000 (11:41 -0700)
. vix: add new opcodes for intiateFileTransfer[To|From]Guest operations.

. add new vmbackup entry point that allows more configurability of the
  quiescing operation (only enabled on Win32 currently).

. changes in shared code that don't affect open-vm-tools functionality.

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
13 files changed:
open-vm-tools/lib/foundryMsg/foundryMsg.c
open-vm-tools/lib/foundryMsg/vixTranslateErrOpenSource.c
open-vm-tools/lib/include/vixCommands.h
open-vm-tools/lib/include/vixOpenSource.h
open-vm-tools/lib/include/vm_device_version.h
open-vm-tools/lib/include/vm_version.h
open-vm-tools/lib/include/vmware/guestrpc/vmbackup.h
open-vm-tools/services/plugins/vix/vixTools.c
open-vm-tools/services/plugins/vix/vixTools.h
open-vm-tools/services/plugins/vix/vixToolsInt.h [new file with mode: 0644]
open-vm-tools/services/plugins/vmbackup/scriptOps.c
open-vm-tools/services/plugins/vmbackup/stateMachine.c
open-vm-tools/services/plugins/vmbackup/vmBackupInt.h

index c90f49085f5e24d9c52736157c42d486acb40930..aacb80b08cca7c08d6c6daa807a55913a2ecbd6a 100644 (file)
@@ -456,6 +456,12 @@ static const VixCommandInfo vixCommandInfoTable[] = {
    VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_READ_ENV_VARIABLES,
                            VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED),
 
+   VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST,
+                           VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED),
+
+   VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_INITIATE_FILE_TRANSFER_TO_GUEST,
+                           VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED),
+
 };
 
 
index be2568e25b2aa15a1a13b9ac64d273cc2bd69d5d..b7d78dc962fb256b89976a4572d09efbb9c41d52 100644 (file)
@@ -75,6 +75,9 @@ Vix_TranslateSystemError(int systemError) // IN
    case ERROR_BUFFER_OVERFLOW: 
       err = VIX_E_FILE_NOT_FOUND;
       break;
+   case ERROR_DIR_NOT_EMPTY:
+      err = VIX_E_DIRECTORY_NOT_EMPTY;
+      break;
    case ERROR_TOO_MANY_OPEN_FILES:
    case ERROR_NO_MORE_FILES:
    case ERROR_WRITE_FAULT:
@@ -138,14 +141,18 @@ Vix_TranslateSystemError(int systemError) // IN
    case EFBIG:
       err = VIX_E_FILE_TOO_BIG;
       break;
+   case ENOTEMPTY:
+      err = VIX_E_DIRECTORY_NOT_EMPTY;
+      break;
+   case ENOTDIR:
+      err = VIX_E_NOT_A_DIRECTORY;
+      break;
    case ETIMEDOUT:
    case EIO:
    case EMFILE:
    case ENFILE:
    case EMLINK:
    case ENOBUFS:
-   case ENOTDIR:
-   case ENOTEMPTY:
    case EROFS:
       Log("%s: system error = %d\n", __FUNCTION__,
                         systemError);
index 4bd840958c4ed26e9defdc7ef1c366b870fdad00..926bf2cc0c9b2ff859a2ea4d67469c4128ab2dae 100644 (file)
@@ -756,6 +756,18 @@ struct VixMsgListFilesRequest {
 #include "vmware_pack_end.h"
 VixMsgListFilesRequest;
 
+typedef
+#include "vmware_pack_begin.h"
+struct VixCommandInitiateFileTransferToGuestRequest {
+   VixCommandRequestHeader header;
+
+   int32                   options;
+   uint32                  guestPathNameLength;
+   Bool                    overwrite;
+}
+#include "vmware_pack_end.h"
+VixCommandInitiateFileTransferToGuestRequest;
+
 
 /*
  * This is used to reply to several operations, like testing whether
@@ -2328,6 +2340,10 @@ enum {
 
    VIX_COMMAND_READ_ENV_VARIABLES               = 187,
 
+   VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST   = 188,
+
+   VIX_COMMAND_INITIATE_FILE_TRANSFER_TO_GUEST     = 189,
+
    /*
     * HOWTO: Adding a new Vix Command. Step 2a.
     *
@@ -2338,7 +2354,7 @@ enum {
     * Once a new command is added here, a command info field needs to be added
     * in bora/lib/foundryMsg/foundryMsg.c as well.
     */
-   VIX_COMMAND_LAST_NORMAL_COMMAND              = 188,
+   VIX_COMMAND_LAST_NORMAL_COMMAND              = 190,
 
    VIX_TEST_UNSUPPORTED_TOOLS_OPCODE_COMMAND    = 998,
    VIX_TEST_UNSUPPORTED_VMX_OPCODE_COMMAND      = 999,
index 4a5ddc28ca75666c37739d232cbc9e9a698285e6..7dc0380108433dab615bd8cb00204a72d6af22cd 100644 (file)
@@ -98,6 +98,9 @@ VixError Vix_TranslateCOMError(HRESULT comError);
 enum {
    VIX_E_OP_NOT_SUPPORTED_ON_NON_VMWARE_VM         = 3038,
 
+   /* File Errors */
+   VIX_E_DIRECTORY_NOT_EMPTY                       = 20006,
+
    /* Reg Errors*/
    VIX_E_REG_INCORRECT_VALUE_TYPE                  = 25000
    /* WARNING. Do not exceed 2**16 */
index cceed4fe0bb5f9962b9e13d72229da16f1e8db81..ab5c89e2f0fba5026cf026d431a622d9ce51405d 100644 (file)
 #define E1000E_PCI_SUB_VENDOR_ID_CONFIG_STR "e1000e.pci.subVendorID"
 #define E1000E_PCI_SUB_DEVICE_ID_CONFIG_STR "e1000e.pci.subDeviceID"
 
+/*
+ * Fresco Logic xHCI (USB 3.0) Controller
+ */
+#define PCI_VENDOR_ID_FRESCO            0x1B73
+#define PCI_DEVICE_ID_FRESCO_FL1000     0x1000   // Original 1-port chip
+#define PCI_DEVICE_ID_FRESCO_FL1009     0x1009   // New 2-port chip (Driver 3.0.98+)
+#define PCI_DEVICE_ID_FRESCO_DEVEL      0x1400   // Unknown (development hardware?)
+
+/*
+ * NEC/Renesas xHCI (USB 3.0) Controller
+ */
+#define PCI_VENDOR_ID_NEC               0x1033
+#define PCI_DEVICE_ID_NEC_UPD720200     0x0194
+#define PCI_REVISION_NEC_UPD720200      0x03
+#define PCI_FIRMWARE_NEC_UPD720200      0x3015
+
 
 /************* Strings for IDE Identity Fields **************************/
 #define VIDE_ID_SERIAL_STR     "00000000000000000001"  /* Must be 20 Bytes */
 /************* Ethernet implementation limits ***************************/
 #define MAX_ETHERNET_CARDS      10
 
+/********************** Floppy limits ***********************************/
+#define MAX_FLOPPY_DRIVES      2
+
 /************* PCI Passthrough implementation limits ********************/
 #define MAX_PCI_PASSTHRU_DEVICES 6
 
index f90be91b3b50c3905cd9b1f859c83ecc69d6f4ee..bc545bd5a9a80358eb3e84b79b69b9ef3f2ec6fa 100644 (file)
@@ -90,6 +90,9 @@
    #define PRODUCT_VERSION    1,0,0,PRODUCT_BUILD_NUMBER_NUMERIC
 #elif defined(VMX86_VLICENSE)
    #define PRODUCT_VERSION    1,1,2,PRODUCT_BUILD_NUMBER_NUMERIC
+#elif defined(VMX86_VPX)
+   /* this should be kept in sync with the corresponding vpx branch. */
+   #define PRODUCT_VERSION    5,0,0,PRODUCT_BUILD_NUMBER_NUMERIC
 #else
    #define PRODUCT_VERSION    3,1,0,PRODUCT_BUILD_NUMBER_NUMERIC  /* PLAYER_VERSION_NUMBER below has to match this */
 #endif
  * VMI 2.0      : 3.1.0
  * P2VA 3.0     : 3.?.?
  */
-#define VIE_FILEVERSION 3,2,0,PRODUCT_BUILD_NUMBER_NUMERIC
+#define VIE_FILEVERSION 5,0,0,PRODUCT_BUILD_NUMBER_NUMERIC
 
 /*
  * This string can be a little more "free form".  The license
 #define FUSION_VERSION "e.x.p"
 
 // These must match VIE_FILEVERSION above
-#define SYSIMAGE_VERSION "4.0.0"
+#define SYSIMAGE_VERSION "5.0.0"
 #define SYSIMAGE_FILE_VERSION VIE_FILEVERSION
 
 #define VCB_VERSION "4.0.0"
 #define VCB_FILE_VERSION 4,0,0,0
-#define VPX_VERSION "e.x.p"
-#define WBC_VERSION "e.x.p"
+#define VIM_VERSION "5.0.0"
+#define VPX_VERSION "5.0.0"
+#define WBC_VERSION "5.0.0"
 #define SDK_VERSION "4.1.0"
 #define FOUNDRY_VERSION "1.10.0"
 #define FOUNDRY_FILE_VERSION 1,10,0,PRODUCT_BUILD_NUMBER_NUMERIC
 #elif defined(VMX86_API)
 #  define PRODUCT_VERSION_NUMBER API_SCRIPTING_VERSION
 #elif defined(VMX86_VPX)
-#  define PRODUCT_VERSION_NUMBER VPX_VERSION
+#  if defined(XVP)
+#     define PRODUCT_VERSION_NUMBER XVP_VERSION
+#  else
+#     define PRODUCT_VERSION_NUMBER VPX_VERSION
+#  endif
 #elif defined(VMX86_WBC)
 #  define PRODUCT_VERSION_NUMBER WBC_VERSION
 #elif defined(VMX86_SDK)
 #      define PRODUCT_LICENSE_VERSION "7.0"
 #    endif
 #  elif defined(VMX86_VPX)
-#    define PRODUCT_LICENSE_VERSION "1.0"
+#    define PRODUCT_LICENSE_VERSION "5.0"
 #  elif defined(VMX86_WBC)
 #    define PRODUCT_LICENSE_VERSION "1.0"
 #  elif defined(VMX86_SDK)
index 76780187dc39e0a24b5c050cadf3b2afdba4b7c4..db2dadf8a887768bd4ee6ce6d6be41cc9d91c53c 100644 (file)
@@ -50,6 +50,7 @@
 /* These are RPC messages used between the VMX and the Tools. */
 #define VMBACKUP_PROTOCOL_PREFIX          "vmbackup."
 #define VMBACKUP_PROTOCOL_START           VMBACKUP_PROTOCOL_PREFIX"start"
+#define VMBACKUP_PROTOCOL_START_WITH_OPTS VMBACKUP_PROTOCOL_PREFIX"startWithOpts"
 #define VMBACKUP_PROTOCOL_ABORT           VMBACKUP_PROTOCOL_PREFIX"abort"
 #define VMBACKUP_PROTOCOL_SNAPSHOT_DONE   VMBACKUP_PROTOCOL_PREFIX"snapshotDone"
 #define VMBACKUP_PROTOCOL_EVENT_SET       VMBACKUP_PROTOCOL_PREFIX"eventSet"
index f44da4b5f20ae6c2de001f64b9bc960ef7337605..29a3896db874700ada90bee656b64353a1daf77e 100644 (file)
@@ -99,6 +99,7 @@
 
 #include "vixOpenSource.h"
 #include "vixTools.h"
+#include "vixToolsInt.h"
 
 #ifdef _WIN32
 #include "registryWin32.h"
@@ -349,6 +350,8 @@ static VixError VixToolsListFiles(VixCommandRequestHeader *requestMsg,
                                   size_t maxBufferSize,
                                   char **result);
 
+static VixError VixToolsInitiateFileTransferToGuest(VixCommandRequestHeader *requestMsg);
+
 static VixError VixToolsKillProcess(VixCommandRequestHeader *requestMsg);
 
 static VixError VixToolsCreateDirectory(VixCommandRequestHeader *requestMsg);
@@ -3098,6 +3101,156 @@ abort:
 } // VixToolsMoveObject
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VixToolsInitiateFileTransferToGuest --
+ *
+ * Return value:
+ *    VixError
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VixError
+VixToolsInitiateFileTransferToGuest(VixCommandRequestHeader *requestMsg)  // IN
+{
+   VixError err = VIX_OK;
+   char *guestPathName = NULL;
+   Bool impersonatingVMWareUser = FALSE;
+   void *userToken = NULL;
+   Bool overwrite = TRUE;
+   char *dirName = NULL;
+   char *baseName = NULL;
+#if defined(_WIN32)
+   int fd = -1;
+   char *tempFilePath = NULL;
+#else
+   FileIOResult res;
+#endif
+
+   VixCommandInitiateFileTransferToGuestRequest *commandRequest =
+      (VixCommandInitiateFileTransferToGuestRequest *) requestMsg;
+
+   ASSERT(NULL != requestMsg);
+
+   guestPathName = ((char *) commandRequest) + sizeof(*commandRequest);
+   overwrite = commandRequest->overwrite;
+
+   if ((requestMsg->commonHeader.bodyLength +
+        requestMsg->commonHeader.headerLength) !=
+       (((uint64) sizeof(*commandRequest)) +
+        commandRequest->guestPathNameLength + 1)) {
+      ASSERT(0);
+      Debug("%s: Invalid request message received\n", __FUNCTION__);
+      err = VIX_E_INVALID_MESSAGE_BODY;
+      goto abort;
+   }
+
+   if (0 == *guestPathName) {
+      err = VIX_E_INVALID_ARG;
+      goto abort;
+   }
+
+   err = VixToolsImpersonateUser(requestMsg, &userToken);
+   if (VIX_OK != err) {
+      goto abort;
+   }
+   impersonatingVMWareUser = TRUE;
+
+   if (File_Exists(guestPathName)) {
+      if (File_IsDirectory(guestPathName)) {
+         err = VIX_E_NOT_A_FILE;
+         goto abort;
+      } else if (!overwrite) {
+         err = VIX_E_FILE_ALREADY_EXISTS;
+         goto abort;
+      }
+   }
+
+   File_GetPathName(guestPathName, &dirName, &baseName);
+   if ((NULL == dirName) || (NULL == baseName)) {
+      err = VIX_E_FILE_NAME_INVALID;
+      goto abort;
+   }
+
+   if (!File_IsDirectory(dirName)) {
+      err = VIX_E_FILE_NAME_INVALID;
+      goto abort;
+   }
+
+#if defined(_WIN32)
+   /*
+    * Ideally, we just need to check if the user has proper write
+    * access to create a child inside the directory. This can be
+    * checked by calling FileIO_Access(). FileIO_Access works perfectly
+    * fine for linux platforms. But on Windows, FileIO_Access just
+    * checks the read-only attribute of the directory and returns the result
+    * based on that. This is not the proper way to check the write
+    * permissions.
+    *
+    * One other way to check the write access is to call CreateFile()
+    * with GENERIC_WRITE and OPEN_EXISTING flags. Check the documentation
+    * for CreateFile() at
+    * http://msdn.microsoft.com/en-us/library/aa363858%28v=VS.85%29.aspx.
+    * But this has got few limitations. CreateFile() doesn't return proper
+    * result when called for directories on NTFS systems.
+    * Checks the KB article available at
+    * http://support.microsoft.com/kb/810881.
+    *
+    * So, for windows, the best bet is to create an empty temporary file
+    * inside the directory and immediately unlink that. If creation is
+    * successful, it ensures that the user has proper write access for
+    * the directory.
+    *
+    * Since we are just checking the write access, there is no need to
+    * create the temporary file with the exact specified filename. Any name
+    * would be fine.
+    */
+   fd = File_MakeTempEx(dirName, baseName, &tempFilePath);
+
+   if (fd > 0) {
+      close(fd);
+   } else {
+      err = FoundryToolsDaemon_TranslateSystemErr();
+      Debug("Unable to create a tmp file to test directory permissions,"
+            " errno is %d\n", errno);
+      goto abort;
+   }
+
+   free(tempFilePath);
+#else
+   /*
+    * We need to check if the user has write access to create
+    * a child inside the directory. Call FileIO_Access() to check
+    * for the proper write permissions for the directory.
+    */
+   res = FileIO_Access(dirName, FILEIO_ACCESS_WRITE);
+
+   if (FILEIO_SUCCESS != res) {
+      err = FoundryToolsDaemon_TranslateSystemErr();
+      Debug("Unable to get access permissions for the directory: %s\n",
+            dirName);
+      goto abort;
+   }
+#endif
+
+abort:
+   free(baseName);
+   free(dirName);
+
+   if (impersonatingVMWareUser) {
+      VixToolsUnimpersonateUser(userToken);
+   }
+   VixToolsLogoutUser(userToken);
+
+   return err;
+} // VixToolsInitiateFileTransferToGuest
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -3672,6 +3825,12 @@ abort:
  *
  * VixToolsListFiles --
  *
+ *    This function is called to implement two opcodes i.e.
+ *    VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST and
+ *    VIX_COMMAND_LIST_FILES.
+ *
+ *    If the opcode is VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST,
+ *    then the specified filepath should not point to a directory.
  *
  * Return value:
  *    VixError
@@ -3716,6 +3875,17 @@ VixToolsListFiles(VixCommandRequestHeader *requestMsg,    // IN
    GError *gerr = NULL;
 #endif
 
+   ASSERT(NULL != requestMsg);
+
+   if ((VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST != requestMsg->opCode) &&
+       (VIX_COMMAND_LIST_FILES != requestMsg->opCode)) {
+      ASSERT(0);
+      err = VIX_E_FAIL;
+      Debug("%s: Received a request with an invalid opcode: %d\n",
+            __FUNCTION__, requestMsg->opCode);
+      goto abort;
+   }
+
    listRequest = (VixMsgListFilesRequest *) requestMsg;
    offset = listRequest->offset;
    index = listRequest->index;
@@ -3759,6 +3929,17 @@ VixToolsListFiles(VixCommandRequestHeader *requestMsg,    // IN
    }
 
    if (File_IsDirectory(dirPathName)) {
+      /*
+       * Ideally we should not overload VixToolsListFiles(). We should
+       * implement a separate function for implementing VIX_COMMAND_LIST_FILES
+       * and VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST. For now, adding
+       * this check is OK. But, we should revisit this later.
+       */
+      if (VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST == requestMsg->opCode) {
+         err = VIX_E_NOT_A_FILE;
+         goto abort;
+      }
+
       numFiles = File_ListDirectory(dirPathName, &fileNameList);
       if (numFiles < 0) {
          err = FoundryToolsDaemon_TranslateSystemErr();
@@ -5221,6 +5402,24 @@ VixToolsGetTempFile(VixCommandRequestHeader *requestMsg,   // IN
        */
 
       if (VIX_SUCCEEDED(err)) {
+
+         /*
+          * If the specified directory path doesn't exist or points to an
+          * existing regular file, then File_MakeTempEx2() returns different
+          * errors on Windows and Linux platforms. So, check for the proper
+          * filetype and return proper errors before calling
+          * File_MakeTempEx2().
+          */
+         if (!File_Exists(directoryPath)) {
+            err = VIX_E_FILE_NOT_FOUND;
+            goto abort;
+         }
+
+         if (File_IsFile(directoryPath)) {
+            err = VIX_E_NOT_A_FILE;
+            goto abort;
+         }
+
          fd = File_MakeTempEx2(directoryPath,
                                createTempFile,
                                VixToolsGetTempFileCreateNameFunc,
@@ -5249,6 +5448,23 @@ VixToolsGetTempFile(VixCommandRequestHeader *requestMsg,   // IN
          directoryPath = File_GetTmpDir(TRUE);
       }
 
+      /*
+       * If the specified directory path doesn't exist or points to an
+       * existing regular file, then File_MakeTempEx2() returns different
+       * errors on Windows and Linux platforms. So, check for the proper
+       * filetype and return proper errors before calling
+       * File_MakeTempEx2().
+       */
+      if (!File_Exists(directoryPath)) {
+         err = VIX_E_FILE_NOT_FOUND;
+         goto abort;
+      }
+
+      if (File_IsFile(directoryPath)) {
+         err = VIX_E_NOT_A_FILE;
+         goto abort;
+      }
+
       fd = File_MakeTempEx2(directoryPath,
                             createTempFile,
                             VixToolsGetTempFileCreateNameFunc,
@@ -6091,6 +6307,16 @@ VixToolsCheckIfVixCommandEnabled(int opcode,                          // IN
                                 VIX_TOOLS_CONFIG_API_CHANGE_FILE_ATTRS_NAME);
          break;
 
+      case VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST:
+         enabled = !VixToolsGetAPIDisabledFromConf(confDictRef,
+                                VIX_TOOLS_CONFIG_API_INITIATE_FILE_TRANSFER_FROM_GUEST_NAME);
+         break;
+
+      case VIX_COMMAND_INITIATE_FILE_TRANSFER_TO_GUEST:
+         enabled = !VixToolsGetAPIDisabledFromConf(confDictRef,
+                                VIX_TOOLS_CONFIG_API_INITIATE_FILE_TRANSFER_TO_GUEST_NAME);
+         break;
+
       /*
        * None of these opcode have a matching config entry (yet),
        * so they can all share.
@@ -6232,6 +6458,7 @@ VixTools_ProcessVixCommand(VixCommandRequestHeader *requestMsg,   // IN
          break;
 
       ////////////////////////////////////
+      case VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST:
       case VIX_COMMAND_LIST_FILES:
          err = VixToolsListFiles(requestMsg,
                                  maxResultBufferSize,
@@ -6386,6 +6613,11 @@ VixTools_ProcessVixCommand(VixCommandRequestHeader *requestMsg,   // IN
          // resultValue is static. Do not free it.
          break;
 
+      ////////////////////////////////////
+      case VIX_COMMAND_INITIATE_FILE_TRANSFER_TO_GUEST:
+         err = VixToolsInitiateFileTransferToGuest(requestMsg);
+         break;
+
       ////////////////////////////////////
       default:
          break;
index a4ab1b50d391a41b2336ebbdee860054eb0f78cf..2c1562d2cd889ceab1c0e3a3c4ef6550ab7e8096 100644 (file)
@@ -102,13 +102,6 @@ void VixToolsUnimpersonateUser(void *userToken);
 
 void VixToolsLogoutUser(void *userToken);
 
-#ifdef _WIN32
-VixError VixToolsGetUserTmpDir(void *userToken,
-                               char **tmpDirPath);
-
-Bool VixToolsUserIsMemberOfAdministratorGroup(VixCommandRequestHeader *requestMsg);
-#endif // _WIN32
-
 #endif /* __VIX_TOOLS_H__ */
 
 
diff --git a/open-vm-tools/services/plugins/vix/vixToolsInt.h b/open-vm-tools/services/plugins/vix/vixToolsInt.h
new file mode 100644 (file)
index 0000000..7b45224
--- /dev/null
@@ -0,0 +1,41 @@
+/*********************************************************
+ * Copyright (C) 2010 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.
+ *
+ *********************************************************/
+
+/*
+ * vixToolsInt.h --
+ *
+ *      Helper routines shared between different files in the vixTools
+ *      module.
+ */
+
+#ifndef __VIX_TOOLS_INT_H__
+#define __VIX_TOOLS_INT_H__
+
+#include "vmware.h"
+#include "vix.h"
+
+
+#ifdef _WIN32
+VixError VixToolsGetUserTmpDir(void *userToken,
+                               char **tmpDirPath);
+
+Bool VixToolsUserIsMemberOfAdministratorGroup(VixCommandRequestHeader *requestMsg);
+#endif // _WIN32
+
+
+#endif // #ifndef __VIX_TOOLS_INT_H__
index db573134c6af54c3725c73d9cb45dd910c0fd6fb..1c483343d99597ec979c87ffb80e719dc16cddbe 100644 (file)
@@ -155,12 +155,24 @@ VmBackupRunNextScript(VmBackupScriptOp *op)  // IN/OUT
       char *cmd;
 
       if (File_IsFile(scripts[index].path)) {
-         cmd = Str_Asprintf(NULL, "\"%s\" %s", scripts[index].path, scriptOp);
+         if (op->state->scriptArg != NULL) {
+            cmd = Str_Asprintf(NULL, "\"%s\" %s \"%s\"", scripts[index].path,
+                               scriptOp, op->state->scriptArg);
+         } else {
+            cmd = Str_Asprintf(NULL, "\"%s\" %s", scripts[index].path,
+                               scriptOp);
+         }
          if (cmd != NULL) {
+            g_debug("Running script: %s\n", cmd);
             scripts[index].proc = ProcMgr_ExecAsync(cmd, NULL);
+         } else {
+            g_debug("Failed to allocate memory to run script: %s\n",
+                    scripts[index].path);
+            scripts[index].proc = NULL;
          }
+         vm_free(cmd);
 
-         if (cmd == NULL || scripts[index].proc == NULL) {
+         if (scripts[index].proc == NULL) {
             if (op->type == VMBACKUP_SCRIPT_FREEZE) {
                ret = -1;
                break;
index 45fb4012a738071175a91687e7fcb291558c429f..ee966378f6274f9d4023260d01bcfd88bf807ad5 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "vmBackupInt.h"
 
+#include "dynxdr.h"
 #include <glib-object.h>
 #include <gmodule.h>
 #include "guestApp.h"
 #include "strutil.h"
 #include "util.h"
 #include "vmBackupSignals.h"
+#if defined(_WIN32)
+#include "vmware/guestrpc/guestQuiesce.h"
+#endif
 #include "vmware/tools/utils.h"
 #include "vmware/tools/vmbackup.h"
+#include "xdrutil.h"
 
 #if !defined(__APPLE__)
 #include "embed_version.h"
@@ -205,6 +210,7 @@ VmBackupFinalize(void)
    }
 
    gBackupState->provider->release(gBackupState->provider);
+   g_free(gBackupState->scriptArg);
    g_free(gBackupState->volumes);
    g_free(gBackupState->snapshots);
    g_free(gBackupState);
@@ -247,7 +253,8 @@ VmBackupStartScripts(VmBackupScriptType type)
          NOT_REACHED();
    }
 
-   if (!VmBackup_SetCurrentOp(gBackupState,
+   if (gBackupState->execScripts &&
+       !VmBackup_SetCurrentOp(gBackupState,
                               VmBackup_NewScriptOp(type, gBackupState),
                               NULL,
                               opName)) {
@@ -530,29 +537,56 @@ VmBackupEnableSync(void)
 }
 
 
-/* RpcIn callbacks. */
+/**
+ * Get boolean entry for the key from the config file.
+ *
+ * @param[in]  config        Config file to read the key from.
+ * @param[in]  key           Key to look for in the config file.
+ * @param[in]  defaultValue  Default value if the key is not found.
+ */
+
+static gboolean
+VmBackupConfigGetBoolean(GKeyFile *config,
+                         const char *key,
+                         gboolean defValue)
+{
+   GError *err = NULL;
+   gboolean value = defValue;
+
+   if (key != NULL) {
+      value = g_key_file_get_boolean(config,
+                                     "vmbackup",
+                                     key,
+                                     &err);
+      if (err != NULL) {
+         g_clear_error(&err);
+         value = defValue;
+      }
+   }
+   return value;
+}
 
 
 /**
- * Handler for the "vmbackup.start" message. Starts the "freeze" scripts
- * unless there's another backup operation going on or some other
- * unexpected error occurs.
+ * Starts the quiesce operation according to the supplied specification unless
+ * some unexpected error occurs.
  *
- * @param[in]  data     RPC data.
+ * @param[in]  data      RPC data.
+ * @param[in]  forceVss  Only allow Vss quiescing or no quiescing.
  *
  * @return TRUE on success.
  */
 
 static gboolean
-VmBackupStart(RpcInData *data)
+VmBackupStartCommon(RpcInData *data,
+                    gboolean forceVss)
 {
    GError *err = NULL;
-   guint timeout;
    ToolsAppCtx *ctx = data->appCtx;
    VmBackupSyncProvider *provider = NULL;
 
    size_t i;
-   
+
    /* List of available providers, in order of preference for loading. */
    struct SyncProvider {
       VmBackupSyncProvider *(*ctor)(void);
@@ -565,31 +599,32 @@ VmBackupStart(RpcInData *data)
       { VmBackup_NewNullProvider, NULL },
    };
 
-   g_debug("*** %s\n", __FUNCTION__);
-   if (gBackupState != NULL) {
-      return RPCIN_SETRETVALS(data, "Backup operation already in progress.", FALSE);
-   }
-
-   /* Instantiate the sync provider. */
-   for (i = 0; i < ARRAYSIZE(providers); i++) {
-      gboolean enabled = TRUE;
-      struct SyncProvider *sp = &providers[i];
-
-      if (sp->cfgEntry != NULL) {
-         enabled = g_key_file_get_boolean(ctx->config,
-                                          "vmbackup",
-                                          sp->cfgEntry,
-                                          &err);
-         if (err != NULL) {
-            g_clear_error(&err);
-            enabled = TRUE;
-         }
+   if (forceVss) {
+      if (gBackupState->quiesceApps || gBackupState->quiesceFS) {
+          /* If quiescing is requested, only allow VSS provider */
+#if defined(_WIN32)
+          if (VmBackupConfigGetBoolean(ctx->config, "enableVSS", TRUE)) {
+             provider = VmBackup_NewVssProvider();
+          }
+#endif
+      } else {
+         /* If no quiescing is requested only allow null provider */
+         provider = VmBackup_NewNullProvider();
       }
-
-      if (enabled) {
-         provider = sp->ctor();
-         if (provider != NULL) {
-            break;
+      if (provider == NULL) {
+         g_warning("Requested quiescing cannot be initialized.");
+         goto error;
+      }
+   } else {
+      /* Instantiate the sync provider. */
+      for (i = 0; i < ARRAYSIZE(providers); i++) {
+         struct SyncProvider *sp = &providers[i];
+
+         if (VmBackupConfigGetBoolean(ctx->config, sp->cfgEntry, TRUE)) {
+            provider = sp->ctor();
+            if (provider != NULL) {
+               break;
+            }
          }
       }
    }
@@ -597,24 +632,18 @@ VmBackupStart(RpcInData *data)
    ASSERT(provider != NULL);
 
    /* Instantiate the backup state and start the operation. */
-   gBackupState = g_new0(VmBackupState, 1);
    gBackupState->ctx = data->appCtx;
    gBackupState->pollPeriod = 1000;
    gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
    gBackupState->provider = provider;
-
-   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 = g_strndup(data->args + index, data->argsSize - index);
-      }
-   }
+   g_debug("Using quiesceApps = %d, quiesceFS = %d, allowHWProvider = %d,"
+           "execScripts = %d, scriptArg = %s, timeout = %u\n",
+           gBackupState->quiesceApps, gBackupState->quiesceFS,
+           gBackupState->allowHWProvider, gBackupState->execScripts,
+           (gBackupState->scriptArg != NULL) ? gBackupState->scriptArg : "",
+           gBackupState->timeout);
+   g_debug("Quiescing volumes: %s",
+           (gBackupState->volumes) ? gBackupState->volumes : "(null)");
 
    gBackupState->configDir = GuestApp_GetConfPath();
    if (gBackupState->configDir == NULL) {
@@ -636,20 +665,27 @@ VmBackupStart(RpcInData *data)
     * anyone wants to play with it), so that we abort any ongoing operation
     * if we also hit that timeout.
     *
+    * First check if the timeout is specified by the RPC command, if not,
+    * check the tools.conf file, otherwise use the default.
+    *
     * See bug 506106.
     */
-   timeout = (guint) g_key_file_get_integer(gBackupState->ctx->config,
-                                            "vmbackup",
-                                            "timeout",
-                                            &err);
-   if (err != NULL) {
-      g_clear_error(&err);
-      timeout = 15 * 60;
+   if (gBackupState->timeout == 0) {
+      gBackupState->timeout = (guint) g_key_file_get_integer(
+                                               gBackupState->ctx->config,
+                                               "vmbackup",
+                                               "timeout",
+                                               &err);
+      if (err != NULL) {
+         g_clear_error(&err);
+         gBackupState->timeout = 15 * 60;
+      }
    }
 
    /* Treat "0" as no timeout. */
-   if (timeout != 0) {
-      gBackupState->abortTimer = g_timeout_source_new_seconds(timeout);
+   if (gBackupState->timeout != 0) {
+      gBackupState->abortTimer =
+          g_timeout_source_new_seconds(gBackupState->timeout);
       VMTOOLSAPP_ATTACH_SOURCE(gBackupState->ctx,
                                gBackupState->abortTimer,
                                VmBackupAbortTimer,
@@ -661,12 +697,130 @@ VmBackupStart(RpcInData *data)
    return RPCIN_SETRETVALS(data, "", TRUE);
 
 error:
-   gBackupState->provider->release(gBackupState->provider);
+   if (gBackupState->provider) {
+      gBackupState->provider->release(gBackupState->provider);
+   }
+   g_free(gBackupState->scriptArg);
+   g_free(gBackupState->volumes);
    g_free(gBackupState);
+   gBackupState = NULL;
    return RPCIN_SETRETVALS(data, "Error initializing backup.", FALSE);
 }
 
 
+/* 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 gboolean
+VmBackupStart(RpcInData *data)
+{
+   g_debug("*** %s\n", __FUNCTION__);
+   if (gBackupState != NULL) {
+      return RPCIN_SETRETVALS(data, "Backup operation already in progress.", FALSE);
+   }
+   gBackupState = g_new0(VmBackupState, 1);
+   if (data->argsSize > 0) {
+      int generateManifests = 0;
+      uint32 index = 0;
+
+      if (StrUtil_GetNextIntToken(&generateManifests, &index, data->args, " ")) {
+         gBackupState->generateManifests = generateManifests;
+      }
+      gBackupState->quiesceApps = TRUE;
+      gBackupState->quiesceFS = TRUE;
+      gBackupState->allowHWProvider = TRUE;
+      gBackupState->execScripts = TRUE;
+      gBackupState->scriptArg = NULL;
+      gBackupState->timeout = 0;
+
+      /* get volume uuids if provided */
+      if (data->args[index] != '\0') {
+         gBackupState->volumes = g_strndup(data->args + index,
+                                           data->argsSize - index);
+      }
+   }
+   return VmBackupStartCommon(data, FALSE);
+}
+
+#if defined(_WIN32)
+
+/**
+ * Handler for the "vmbackup.startWithOpts" message. Starts processing the
+ * quiesce operation according to the supplied specification unless there's
+ * another backup operation going on or some other unexpected error occurs.
+ *
+ * . If createManifest is true, the guest generates a manifest about the
+ *   application involved during quiescing.
+ * . If quiesceApps is true, the guest involves applications during
+ *   quiescing. If quiesceFS is true, the guest performs file system
+ *   quiescing. If both quiesceApps and quiesceFS are true, the guest
+ *   falls back to file system quiescing if application quiescing is not
+ *   supported in the guest. If both quiesceApps and quiesceFS are false,
+ *   the guest performs no quiescing but will still run the custom scripts
+ *   provided execScripts is true.
+ * . If writableSnapshot is true, the guest assumes that writable snapshot
+ *   based quiescing can be performed.
+ * . If execScripts is true, the guest calls pre-freeze and post-thaw
+ *   scripts before and after quiescing.
+ * . The scriptArg string is passed to the pre-freeze and post-thaw scripts
+ *   as an argument so that the scripts can be configured to perform
+ *   actions based this argument.
+ * . The timeout in seconds overrides the default timeout of 15 minutes
+ *   that the guest uses to abort a long quiesce operation. If the timeout
+ *   is 0, the default timeout is used.
+ * . The volumes argument is a list of diskUuids separated by space.
+ *
+ * @param[in]  data     RPC data.
+ *
+ * @return TRUE on success.
+ */
+
+static gboolean
+VmBackupStartWithOpts(RpcInData *data)
+{
+   GuestQuiesceParams *params;
+   GuestQuiesceParamsV1 *paramsV1;
+   gboolean retval;
+
+   g_debug("*** %s\n", __FUNCTION__);
+   if (gBackupState != NULL) {
+      return RPCIN_SETRETVALS(data, "Backup operation already in progress.",
+                              FALSE);
+   }
+   params = (GuestQuiesceParams *)data->args;
+   if (params->ver != GUESTQUIESCEPARAMS_V1) {
+      g_warning("%s: Incompatible quiesce parameter version. \n", __FUNCTION__);
+      return RPCIN_SETRETVALS(data, "Incompatible quiesce parameter version",
+                              FALSE);
+   }
+   gBackupState = g_new0(VmBackupState, 1);
+   paramsV1 = params->GuestQuiesceParams_u.guestQuiesceParamsV1;
+   gBackupState->generateManifests = paramsV1->createManifest;
+   gBackupState->quiesceApps = paramsV1->quiesceApps;
+   gBackupState->quiesceFS = paramsV1->quiesceFS;
+   gBackupState->allowHWProvider = paramsV1->writableSnapshot;
+   gBackupState->execScripts = paramsV1->execScripts;
+   gBackupState->scriptArg = g_strndup(paramsV1->scriptArg,
+                                       strlen(paramsV1->scriptArg));
+   gBackupState->timeout = paramsV1->timeout;
+   gBackupState->volumes = g_strndup(paramsV1->diskUuids,
+                                     strlen(paramsV1->diskUuids));
+   retval = VmBackupStartCommon(data, TRUE);
+   return retval;
+}
+
+#endif
+
 /**
  * Aborts the current operation if one is active, and stops the backup
  * process. If the sync provider has been activated, tell it to abort
@@ -809,6 +963,11 @@ ToolsOnLoad(ToolsAppCtx *ctx)
 
    RpcChannelCallback rpcs[] = {
       { VMBACKUP_PROTOCOL_START, VmBackupStart, NULL, NULL, NULL, 0 },
+#if defined(_WIN32)
+      /* START_WITH_OPTS command supported only on Windows for now */
+      { VMBACKUP_PROTOCOL_START_WITH_OPTS, VmBackupStartWithOpts, NULL,
+                    xdr_GuestQuiesceParams, NULL, sizeof (GuestQuiesceParams) },
+#endif
       { VMBACKUP_PROTOCOL_ABORT, VmBackupAbort, NULL, NULL, NULL, 0 },
       { VMBACKUP_PROTOCOL_SNAPSHOT_DONE, VmBackupSnapshotDone, NULL, NULL, NULL, 0 }
    };
index 1a58fc5f3113c4933a0fb04a7027fc2408dac80e..d6382a642ae00414b77920a41a8fbc07f519caed 100644 (file)
@@ -90,6 +90,12 @@ typedef struct VmBackupState {
    Bool (*callback)(struct VmBackupState *);
    Bool           forceRequeue;
    Bool           generateManifests;
+   Bool           quiesceApps;
+   Bool           quiesceFS;
+   Bool           allowHWProvider;
+   Bool           execScripts;
+   char          *scriptArg;
+   guint          timeout;
    gpointer       clientData;
    void          *scripts;
    const char    *configDir;