Blame SOURCES/open-vm-tools-10.0.5-quiesce-files-bz1398802.patch

0e2628
--- open-vm-tools-10.0.5-3227872/lib/include/vmware/guestrpc/vmbackup.h	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/lib/include/vmware/guestrpc/vmbackup.h	2017-01-11 02:08:21.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2007-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2007-2016 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -54,6 +54,8 @@ 
0e2628
 #define VMBACKUP_PROTOCOL_ABORT           VMBACKUP_PROTOCOL_PREFIX"abort"
0e2628
 #define VMBACKUP_PROTOCOL_SNAPSHOT_DONE   VMBACKUP_PROTOCOL_PREFIX"snapshotDone"
0e2628
 #define VMBACKUP_PROTOCOL_EVENT_SET       VMBACKUP_PROTOCOL_PREFIX"eventSet"
0e2628
+#define VMBACKUP_PROTOCOL_SNAPSHOT_COMPLETED \
0e2628
+   VMBACKUP_PROTOCOL_PREFIX"snapshotCompleted"
0e2628
 
0e2628
 /* These are responses to messages sent to the guest. */
0e2628
 #define VMBACKUP_PROTOCOL_ERROR           "protocol.error"
0e2628
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/guestQuiesce.x	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/guestQuiesce.x	2017-01-11 02:08:21.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2010-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2010-2016 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -24,12 +24,14 @@ 
0e2628
  */
0e2628
 
0e2628
 enum GuestQuiesceParamsVersion {
0e2628
-   GUESTQUIESCEPARAMS_V1 = 1
0e2628
+   GUESTQUIESCEPARAMS_V1 = 1,
0e2628
+   GUESTQUIESCEPARAMS_V2 = 2
0e2628
 };
0e2628
 
0e2628
 const GUESTQUIESCE_SCRIPTARG_MAX_LEN = 256;
0e2628
 const GUESTQUIESCE_DISKUUID_MAX_LEN = 3200;   /* (UUID_MAXLEN + 1) * 64 disks */
0e2628
 
0e2628
+
0e2628
 /*  Guest Quiescing parameters. */
0e2628
 struct GuestQuiesceParamsV1 {
0e2628
    Bool createManifest;     /* Create manifest describing the operations */
0e2628
@@ -42,7 +44,19 @@ 
0e2628
    string diskUuids<GUESTQUIESCE_DISKUUID_MAX_LEN>;   /* disk Uuids */
0e2628
 };
0e2628
 
0e2628
+/*  Guest Quiescing parameters V2. */
0e2628
+struct GuestQuiesceParamsV2 {
0e2628
+   struct GuestQuiesceParamsV1 paramsV1;
0e2628
+   uint32 vssBackupContext;
0e2628
+   uint32 vssBackupType;
0e2628
+   Bool vssBootableSystemState;
0e2628
+   Bool vssPartialFileSupport;
0e2628
+};
0e2628
+
0e2628
+
0e2628
 union GuestQuiesceParams switch (GuestQuiesceParamsVersion ver) {
0e2628
 case GUESTQUIESCEPARAMS_V1:
0e2628
    struct GuestQuiesceParamsV1 *guestQuiesceParamsV1;
0e2628
+case GUESTQUIESCEPARAMS_V2:
0e2628
+   struct GuestQuiesceParamsV2 *guestQuiesceParamsV2;
0e2628
 };
0e2628
--- open-vm-tools-10.0.5-3227872/lib/include/vmware/tools/utils.h	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/lib/include/vmware/tools/utils.h	2017-01-11 02:07:50.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2008-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2008-2016 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -121,6 +121,24 @@ 
0e2628
                           const gchar *domain,
0e2628
                           GKeyFile *conf);
0e2628
 
0e2628
+gboolean
0e2628
+VMTools_ConfigGetBoolean(GKeyFile *config,
0e2628
+                         const gchar *section,
0e2628
+                         const gchar *key,
0e2628
+                         gboolean defValue);
0e2628
+
0e2628
+gint
0e2628
+VMTools_ConfigGetInteger(GKeyFile *config,
0e2628
+                         const gchar *section,
0e2628
+                         const gchar *key,
0e2628
+                         gint defValue);
0e2628
+
0e2628
+gchar *
0e2628
+VMTools_ConfigGetString(GKeyFile *config,
0e2628
+                        const gchar *section,
0e2628
+                        const gchar *key,
0e2628
+                        gchar *defValue);
0e2628
+
0e2628
 #if defined(G_PLATFORM_WIN32)
0e2628
 
0e2628
 gboolean
0e2628
--- open-vm-tools-10.0.5-3227872/libvmtools/vmtoolsConfig.c	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/libvmtools/vmtoolsConfig.c	2017-01-11 02:07:50.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2008-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2008-2016 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -329,7 +329,12 @@ 
0e2628
    gchar *backup = NULL;
0e2628
    gchar *defaultPath = NULL;
0e2628
    gchar *localPath = NULL;
0e2628
+   /* GStatBuf was added in 2.26. */
0e2628
+#if GLIB_CHECK_VERSION(2, 26, 0)
0e2628
+   GStatBuf confStat;
0e2628
+#else
0e2628
    struct stat confStat;
0e2628
+#endif
0e2628
    GHashTable *old = NULL;
0e2628
    GError *err = NULL;
0e2628
    GKeyFile *cfg = NULL;
0e2628
@@ -527,3 +532,122 @@ 
0e2628
    return ret;
0e2628
 }
0e2628
 
0e2628
+
0e2628
+/**
0e2628
+ * Loads boolean value for a key from the specified config section.
0e2628
+ *
0e2628
+ * @param[in]  config   Config file to read the key from.
0e2628
+ * @param[in]  section  Section to look for in the config file.
0e2628
+ * @param[in]  defValue Default value if the key is not found or error.
0e2628
+ *
0e2628
+ * @return value of the key if value was read successfully, else defValue.
0e2628
+ */
0e2628
+
0e2628
+gboolean
0e2628
+VMTools_ConfigGetBoolean(GKeyFile *config,
0e2628
+                         const gchar *section,
0e2628
+                         const gchar *key,
0e2628
+                         gboolean defValue)
0e2628
+{
0e2628
+   GError *err = NULL;
0e2628
+   gboolean value;
0e2628
+
0e2628
+   if (config == NULL || section == NULL || key == NULL) {
0e2628
+      g_debug("%s: Returning default value for '[%s] %s'=%s.\n",
0e2628
+              __FUNCTION__, section ? section : "(null)",
0e2628
+              key ? key : "(null)", defValue ? "TRUE" : "FALSE");
0e2628
+      return defValue;
0e2628
+   }
0e2628
+
0e2628
+   value = g_key_file_get_boolean(config, section, key, &err;;
0e2628
+   if (err != NULL) {
0e2628
+      if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND &&
0e2628
+          err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
0e2628
+         g_warning("%s: Failed to get value for '[%s] %s': %s (err=%d).\n",
0e2628
+                   __FUNCTION__, section, key, err->message, err->code);
0e2628
+      }
0e2628
+      g_debug("%s: Returning default value for '[%s] %s'=%s.\n",
0e2628
+              __FUNCTION__, section, key, defValue ? "TRUE" : "FALSE");
0e2628
+      value = defValue;
0e2628
+      g_clear_error(&err;;
0e2628
+   }
0e2628
+   return value;
0e2628
+}
0e2628
+
0e2628
+
0e2628
+/**
0e2628
+ * Loads integer value for a key from the specified config section.
0e2628
+ *
0e2628
+ * @param[in]  config   Config file to read the key from.
0e2628
+ * @param[in]  section  Section to look for in the config file.
0e2628
+ * @param[in]  defValue Default value if the key is not found or error.
0e2628
+ *
0e2628
+ * @return value of the key if value was read successfully, else defValue.
0e2628
+ */
0e2628
+
0e2628
+gint
0e2628
+VMTools_ConfigGetInteger(GKeyFile *config,
0e2628
+                         const gchar *section,
0e2628
+                         const gchar *key,
0e2628
+                         gint defValue)
0e2628
+{
0e2628
+   GError *err = NULL;
0e2628
+   gint value;
0e2628
+
0e2628
+   ASSERT(config);
0e2628
+   ASSERT(key);
0e2628
+   ASSERT(section);
0e2628
+
0e2628
+   value = g_key_file_get_integer(config, section, key, &err;;
0e2628
+   if (err != NULL) {
0e2628
+      if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND &&
0e2628
+          err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
0e2628
+         g_warning("%s: Failed to get value for '[%s] %s': %s (err=%d).\n",
0e2628
+                   __FUNCTION__, section, key, err->message, err->code);
0e2628
+      }
0e2628
+      g_debug("%s: Returning default value for '[%s] %s'=%d.\n",
0e2628
+              __FUNCTION__, section, key, defValue);
0e2628
+      value = defValue;
0e2628
+      g_clear_error(&err;;
0e2628
+   }
0e2628
+   return value;
0e2628
+}
0e2628
+
0e2628
+
0e2628
+/**
0e2628
+ * Loads string value for a key from the specified config section.
0e2628
+ *
0e2628
+ * @param[in]  config   Config file to read the key from.
0e2628
+ * @param[in]  section  Section to look for in the config file.
0e2628
+ * @param[in]  defValue Default value if the key is not found or error.
0e2628
+ *
0e2628
+ * @return value of the key if value was read successfully, else defValue.
0e2628
+ */
0e2628
+
0e2628
+gchar *
0e2628
+VMTools_ConfigGetString(GKeyFile *config,
0e2628
+                        const gchar *section,
0e2628
+                        const gchar *key,
0e2628
+                        gchar *defValue)
0e2628
+{
0e2628
+   GError *err = NULL;
0e2628
+   gchar *value;
0e2628
+
0e2628
+   ASSERT(config);
0e2628
+   ASSERT(key);
0e2628
+   ASSERT(section);
0e2628
+
0e2628
+   value = g_key_file_get_string(config, section, key, &err;;
0e2628
+   if (err != NULL) {
0e2628
+      if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND &&
0e2628
+          err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
0e2628
+         g_warning("%s: Failed to get value for '[%s] %s': %s (err=%d).\n",
0e2628
+                   __FUNCTION__, section, key, err->message, err->code);
0e2628
+      }
0e2628
+      g_debug("%s: Returning default value for '[%s] %s'=%s.\n",
0e2628
+              __FUNCTION__, section, key, defValue ? defValue : "(null)");
0e2628
+      value = defValue;
0e2628
+      g_clear_error(&err;;
0e2628
+   }
0e2628
+   return value;
0e2628
+}
0e2628
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/Makefile.am	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/Makefile.am	2017-01-11 02:07:53.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 ################################################################################
0e2628
-### Copyright (C) 2007-2015 VMware, Inc.  All rights reserved.
0e2628
+### Copyright (C) 2007-2016 VMware, Inc.  All rights reserved.
0e2628
 ###
0e2628
 ### This program is free software; you can redistribute it and/or modify
0e2628
 ### it under the terms of version 2 of the GNU General Public License as
0e2628
@@ -17,6 +17,9 @@ 
0e2628
 
0e2628
 noinst_LTLIBRARIES = libSyncDriver.la
0e2628
 
0e2628
+libSyncDriver_la_CPPFLAGS =
0e2628
+libSyncDriver_la_CPPFLAGS += @GLIB2_CPPFLAGS@
0e2628
+
0e2628
 libSyncDriver_la_SOURCES =
0e2628
 libSyncDriver_la_SOURCES += syncDriverPosix.c
0e2628
 
0e2628
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/nullDriver.c	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/nullDriver.c	2017-01-11 02:08:10.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2011-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2011-2016 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -63,7 +63,7 @@ 
0e2628
  */
0e2628
 
0e2628
 SyncDriverErr
0e2628
-NullDriver_Freeze(const char *paths,
0e2628
+NullDriver_Freeze(const GSList *paths,
0e2628
                   SyncDriverHandle *handle)
0e2628
 {
0e2628
    /*
0e2628
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverInt.h	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverInt.h	2017-01-11 02:08:10.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2011-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2011-2016 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -25,19 +25,22 @@ 
0e2628
  * Internal definitions for the sync driver library.
0e2628
  */
0e2628
 
0e2628
+#include <glib.h>
0e2628
 #include "syncDriver.h"
0e2628
 
0e2628
 #define LGPFX "SyncDriver: "
0e2628
 
0e2628
 #if !defined(Win32)
0e2628
 
0e2628
+#define SYNCDRIVER_PATH_SEPARATOR   ':'
0e2628
+
0e2628
 typedef enum {
0e2628
    SD_SUCCESS,
0e2628
    SD_ERROR,
0e2628
    SD_UNAVAILABLE,
0e2628
 } SyncDriverErr;
0e2628
 
0e2628
-typedef SyncDriverErr (*SyncFreezeFn)(const char *paths,
0e2628
+typedef SyncDriverErr (*SyncFreezeFn)(const GSList *paths,
0e2628
                                       SyncDriverHandle *handle);
0e2628
 
0e2628
 typedef struct SyncHandle {
0e2628
@@ -47,15 +50,15 @@ 
0e2628
 
0e2628
 #if defined(linux)
0e2628
 SyncDriverErr
0e2628
-LinuxDriver_Freeze(const char *userPaths,
0e2628
+LinuxDriver_Freeze(const GSList *userPaths,
0e2628
                    SyncDriverHandle *handle);
0e2628
 
0e2628
 SyncDriverErr
0e2628
-VmSync_Freeze(const char *userPaths,
0e2628
+VmSync_Freeze(const GSList *userPaths,
0e2628
               SyncDriverHandle *handle);
0e2628
 
0e2628
 SyncDriverErr
0e2628
-NullDriver_Freeze(const char *userPaths,
0e2628
+NullDriver_Freeze(const GSList *userPaths,
0e2628
                   SyncDriverHandle *handle);
0e2628
 #endif
0e2628
 
0e2628
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverLinux.c	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverLinux.c	2017-01-11 02:08:10.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2011-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2011-2017 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -32,7 +32,6 @@ 
0e2628
 #include <sys/ioctl.h>
0e2628
 #include "debug.h"
0e2628
 #include "dynbuf.h"
0e2628
-#include "strutil.h"
0e2628
 #include "syncDriverInt.h"
0e2628
 
0e2628
 /* Out toolchain headers are somewhat outdated and don't define these. */
0e2628
@@ -70,8 +69,13 @@ 
0e2628
    LinuxDriver *sync = (LinuxDriver *) handle;
0e2628
    SyncDriverErr err = SD_SUCCESS;
0e2628
 
0e2628
-   for (i = 0; i < sync->fdCnt; i++) {
0e2628
-      if (ioctl(sync->fds[i], FITHAW) == -1) {
0e2628
+   /*
0e2628
+    * Thaw in the reverse order of freeze
0e2628
+    */
0e2628
+   for (i = sync->fdCnt; i > 0; i--) {
0e2628
+      Debug(LGPFX "Thawing fd=%d.\n", sync->fds[i-1]);
0e2628
+      if (ioctl(sync->fds[i-1], FITHAW) == -1) {
0e2628
+         Debug(LGPFX "Thaw failed for fd=%d.\n", sync->fds[i-1]);
0e2628
          err = SD_ERROR;
0e2628
       }
0e2628
    }
0e2628
@@ -98,8 +102,12 @@ 
0e2628
    LinuxDriver *sync = (LinuxDriver *) handle;
0e2628
    size_t i;
0e2628
 
0e2628
-   for (i = 0; i < sync->fdCnt; i++) {
0e2628
-      close(sync->fds[i]);
0e2628
+   /*
0e2628
+    * Close in the reverse order of open
0e2628
+    */
0e2628
+   for (i = sync->fdCnt; i > 0; i--) {
0e2628
+      Debug(LGPFX "Closing fd=%d.\n", sync->fds[i-1]);
0e2628
+      close(sync->fds[i-1]);
0e2628
    }
0e2628
    free(sync->fds);
0e2628
    free(sync);
0e2628
@@ -120,7 +128,7 @@ 
0e2628
  * slow when guest is performing significant IO. Therefore, caller should
0e2628
  * consider running this function in a separate thread.
0e2628
  *
0e2628
- * @param[in]  paths    Paths to freeze (colon-separated).
0e2628
+ * @param[in]  paths    List of paths to freeze.
0e2628
  * @param[out] handle   Handle to use for thawing.
0e2628
  *
0e2628
  * @return A SyncDriverErr.
0e2628
@@ -129,13 +137,10 @@ 
0e2628
  */
0e2628
 
0e2628
 SyncDriverErr
0e2628
-LinuxDriver_Freeze(const char *paths,
0e2628
+LinuxDriver_Freeze(const GSList *paths,
0e2628
                    SyncDriverHandle *handle)
0e2628
 {
0e2628
-   char *path;
0e2628
-   int fd;
0e2628
-   size_t count = 0;
0e2628
-   unsigned int index = 0;
0e2628
+   ssize_t count = 0;
0e2628
    Bool first = TRUE;
0e2628
    DynBuf fds;
0e2628
    LinuxDriver *sync = NULL;
0e2628
@@ -143,7 +148,7 @@ 
0e2628
 
0e2628
    DynBuf_Init(&fds);
0e2628
 
0e2628
-   Debug(LGPFX "Freezing %s using Linux ioctls...\n", paths);
0e2628
+   Debug(LGPFX "Freezing using Linux ioctls...\n");
0e2628
 
0e2628
    sync = calloc(1, sizeof *sync);
0e2628
    if (sync == NULL) {
0e2628
@@ -154,12 +159,20 @@ 
0e2628
    sync->driver.close = LinuxFiClose;
0e2628
 
0e2628
    /*
0e2628
+    * Ensure we did not get an empty list
0e2628
+    */
0e2628
+   VERIFY(paths != NULL);
0e2628
+
0e2628
+   /*
0e2628
     * Iterate through the requested paths. If we get an error for the first
0e2628
     * path, and it's not EPERM, assume that the ioctls are not available in
0e2628
     * the current kernel.
0e2628
     */
0e2628
-   while ((path = StrUtil_GetNextToken(&index, paths, ":")) != NULL) {
0e2628
+   while (paths != NULL) {
0e2628
+      int fd;
0e2628
+      const char *path = paths->data;
0e2628
       Debug(LGPFX "opening path '%s'.\n", path);
0e2628
+      paths = g_slist_next(paths);
0e2628
       fd = open(path, O_RDONLY);
0e2628
       if (fd == -1) {
0e2628
          switch (errno) {
0e2628
@@ -169,7 +182,6 @@ 
0e2628
              * as users with permission 700, so just ignore these.
0e2628
              */
0e2628
             Debug(LGPFX "cannot access mounted directory '%s'.\n", path);
0e2628
-            free(path);
0e2628
             continue;
0e2628
 
0e2628
          case EIO:
0e2628
@@ -179,19 +191,17 @@ 
0e2628
              * this should be enough. Just skip.
0e2628
              */
0e2628
             Debug(LGPFX "I/O error reading directory '%s'.\n", path);
0e2628
-            free(path);
0e2628
             continue;
0e2628
 
0e2628
          default:
0e2628
             Debug(LGPFX "failed to open '%s': %d (%s)\n",
0e2628
                   path, errno, strerror(errno));
0e2628
             err = SD_ERROR;
0e2628
-            free(path);
0e2628
             goto exit;
0e2628
          }
0e2628
       }
0e2628
 
0e2628
-      Debug(LGPFX "freezing path '%s'.\n", path);
0e2628
+      Debug(LGPFX "freezing path '%s' (fd=%d).\n", path, fd);
0e2628
       if (ioctl(fd, FIFREEZE) == -1) {
0e2628
          int ioctlerr = errno;
0e2628
          /*
0e2628
@@ -211,17 +221,15 @@ 
0e2628
             Debug(LGPFX "failed to freeze '%s': %d (%s)\n",
0e2628
                   path, ioctlerr, strerror(ioctlerr));
0e2628
             err = first && ioctlerr == ENOTTY ? SD_UNAVAILABLE : SD_ERROR;
0e2628
-            free(path);
0e2628
             break;
0e2628
          }
0e2628
       } else {
0e2628
-         Debug(LGPFX "successfully froze '%s'.\n", path);
0e2628
+         Debug(LGPFX "successfully froze '%s' (fd=%d).\n", path, fd);
0e2628
          if (!DynBuf_Append(&fds, &fd, sizeof fd)) {
0e2628
             if (ioctl(fd, FITHAW) == -1) {
0e2628
                Warning(LGPFX "failed to thaw '%s': %d (%s)\n",
0e2628
                        path, errno, strerror(errno));
0e2628
             }
0e2628
-            free(path);
0e2628
             close(fd);
0e2628
             err = SD_ERROR;
0e2628
             break;
0e2628
@@ -229,7 +237,6 @@ 
0e2628
          count++;
0e2628
       }
0e2628
 
0e2628
-      free(path);
0e2628
       first = FALSE;
0e2628
    }
0e2628
 
0e2628
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverPosix.c	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverPosix.c	2017-01-11 02:08:10.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2005-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2005-2016 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -25,9 +25,9 @@ 
0e2628
 #include <stdio.h>
0e2628
 #include <sys/param.h>
0e2628
 #include <sys/mount.h>
0e2628
+#include <glib.h>
0e2628
 #include "vmware.h"
0e2628
 #include "debug.h"
0e2628
-#include "dynbuf.h"
0e2628
 #include "str.h"
0e2628
 #include "syncDriverInt.h"
0e2628
 #include "util.h"
0e2628
@@ -85,19 +85,21 @@ 
0e2628
 /*
0e2628
  *-----------------------------------------------------------------------------
0e2628
  *
0e2628
- * SyncDriverListMounts --
0e2628
+ * SyncDriverLocalMounts --
0e2628
  *
0e2628
- *    Returns a newly allocated string containing a list of colon-separated
0e2628
- *    mount paths in the system. No filtering is done, so all paths are added.
0e2628
- *    This assumes that the driver allows "unfreezable" paths to be provided
0e2628
- *    to the freeze command.
0e2628
+ *    Returns a singly-linked list of all local disk paths mounted in the
0e2628
+ *    system filtering out remote file systems. There is no filtering for
0e2628
+ *    other mount points because we assume that the underlying driver and
0e2628
+ *    IOCTL can deal with "unfreezable" paths. The returned list of paths
0e2628
+ *    is in the reverse order of the paths returned by GETNEXT_MNTINFO.
0e2628
+ *    Caller must free each path and the list itself.
0e2628
  *
0e2628
  *    XXX: mntinfo.h mentions Solaris and Linux, but not FreeBSD. If we ever
0e2628
  *    have a FreeBSD sync driver, we should make sure this function also
0e2628
  *    works there.
0e2628
  *
0e2628
  * Results:
0e2628
- *    The list of devices to freeze, or NULL on failure.
0e2628
+ *    GSList* on success, NULL on failure.
0e2628
  *
0e2628
  * Side effects:
0e2628
  *    None
0e2628
@@ -105,21 +107,20 @@ 
0e2628
  *-----------------------------------------------------------------------------
0e2628
  */
0e2628
 
0e2628
-static char *
0e2628
-SyncDriverListMounts(void)
0e2628
+static GSList *
0e2628
+SyncDriverLocalMounts(void)
0e2628
 {
0e2628
-   char *paths = NULL;
0e2628
-   DynBuf buf;
0e2628
+   GSList *paths = NULL;
0e2628
    MNTHANDLE mounts;
0e2628
    DECLARE_MNTINFO(mntinfo);
0e2628
 
0e2628
    if ((mounts = OPEN_MNTFILE("r")) == NULL) {
0e2628
+      Warning(LGPFX "Failed to open mount point table.\n");
0e2628
       return NULL;
0e2628
    }
0e2628
 
0e2628
-   DynBuf_Init(&buf;;
0e2628
-
0e2628
    while (GETNEXT_MNTINFO(mounts, mntinfo)) {
0e2628
+      char *path;
0e2628
       /*
0e2628
        * Skip remote mounts because they are not freezable and opening them
0e2628
        * could lead to hangs. See PR 1196785.
0e2628
@@ -130,29 +131,21 @@ 
0e2628
          continue;
0e2628
       }
0e2628
 
0e2628
+      path = Util_SafeStrdup(MNTINFO_MNTPT(mntinfo));
0e2628
+
0e2628
       /*
0e2628
-       * Add a separator if it's not the first path, and add the path to the
0e2628
-       * tail of the list.
0e2628
+       * A mount point could depend on existence of a previous mount
0e2628
+       * point like a loopback. In order to avoid deadlock/hang in
0e2628
+       * freeze operation, a mount point needs to be frozen before
0e2628
+       * its dependency is frozen.
0e2628
+       * Typically, mount points are listed in the order they are
0e2628
+       * mounted by the system i.e. dependent comes after the
0e2628
+       * dependency. So, we need to keep them in reverse order of
0e2628
+       * mount points to achieve the dependency order.
0e2628
        */
0e2628
-      if ((DynBuf_GetSize(&buf) != 0 && !DynBuf_Append(&buf, ":", 1))
0e2628
-          || !DynBuf_Append(&buf,
0e2628
-                            MNTINFO_MNTPT(mntinfo),
0e2628
-                            strlen(MNTINFO_MNTPT(mntinfo)))) {
0e2628
-         goto exit;
0e2628
-      }
0e2628
-   }
0e2628
-
0e2628
-   if (!DynBuf_Append(&buf, "\0", 1)) {
0e2628
-      goto exit;
0e2628
+      paths = g_slist_prepend(paths, path);
0e2628
    }
0e2628
 
0e2628
-   paths = DynBuf_AllocGet(&buf;;
0e2628
-   if (paths == NULL) {
0e2628
-      Debug(LGPFX "Failed to allocate path list.\n");
0e2628
-   }
0e2628
-
0e2628
-exit:
0e2628
-   DynBuf_Destroy(&buf;;
0e2628
    (void) CLOSE_MNTFILE(mounts);
0e2628
    return paths;
0e2628
 }
0e2628
@@ -185,6 +178,29 @@ 
0e2628
 /*
0e2628
  *-----------------------------------------------------------------------------
0e2628
  *
0e2628
+ * SyncDriverFreePath --
0e2628
+ *
0e2628
+ *    A GFunc for freeing path strings. It is intended for g_slist_foreach.
0e2628
+ *
0e2628
+ * Results:
0e2628
+ *    None
0e2628
+ *
0e2628
+ * Side effects:
0e2628
+ *    None
0e2628
+ *
0e2628
+ *-----------------------------------------------------------------------------
0e2628
+ */
0e2628
+
0e2628
+static void
0e2628
+SyncDriverFreePath(gpointer data, gpointer userData)
0e2628
+{
0e2628
+   free(data);
0e2628
+}
0e2628
+
0e2628
+
0e2628
+/*
0e2628
+ *-----------------------------------------------------------------------------
0e2628
+ *
0e2628
  * SyncDriver_Freeze --
0e2628
  *
0e2628
  *    Freeze I/O on the indicated drives. "all" means all drives.
0e2628
@@ -214,14 +230,11 @@ 
0e2628
                   Bool enableNullDriver,     // IN
0e2628
                   SyncDriverHandle *handle)  // OUT
0e2628
 {
0e2628
-   char *paths = NULL;
0e2628
+   GSList *paths = NULL;
0e2628
    SyncDriverErr err = SD_UNAVAILABLE;
0e2628
    size_t i = 0;
0e2628
 
0e2628
    /*
0e2628
-    * First, convert the given path list to something the backends will
0e2628
-    * understand: a colon-separated list of paths.
0e2628
-    *
0e2628
     * NOTE: Ignore disk UUIDs. We ignore the userPaths if it does
0e2628
     * not start with '/' because all paths are absolute and it is
0e2628
     * possible only when we get diskUUID as userPaths. So, all
0e2628
@@ -229,26 +242,42 @@ 
0e2628
     */
0e2628
    if (userPaths == NULL ||
0e2628
        Str_Strncmp(userPaths, "all", sizeof "all") == 0 ||
0e2628
-       *userPaths != '/') {
0e2628
-      paths = SyncDriverListMounts();
0e2628
-      if (paths == NULL) {
0e2628
-         Debug(LGPFX "Failed to list mount points.\n");
0e2628
-         return SD_ERROR;
0e2628
-      }
0e2628
+       userPaths[0] != '/') {
0e2628
+      paths = SyncDriverLocalMounts();
0e2628
    } else {
0e2628
       /*
0e2628
-       * The sync driver API specifies spaces as separators, but the driver
0e2628
-       * uses colons as the path separator on Unix.
0e2628
+       * The sync driver API specifies spaces as separators.
0e2628
        */
0e2628
-      char *c;
0e2628
-      paths = Util_SafeStrdup(userPaths);
0e2628
-      for (c = paths; *c != '\0'; c++) {
0e2628
-         if (*c == ' ') {
0e2628
-            *c = ':';
0e2628
+      while (*userPaths != '\0') {
0e2628
+         const char *c;
0e2628
+         char *path;
0e2628
+
0e2628
+         if (*userPaths == ' ') {
0e2628
+            /*
0e2628
+             * Trim spaces from beginning
0e2628
+             */
0e2628
+            userPaths++;
0e2628
+            continue;
0e2628
+         }
0e2628
+
0e2628
+         c = strchr(userPaths, ' ');
0e2628
+         if (c == NULL) {
0e2628
+            path = Util_SafeStrdup(userPaths);
0e2628
+            paths = g_slist_append(paths, path);
0e2628
+            break;
0e2628
+         } else {
0e2628
+            path = Util_SafeStrndup(userPaths, c - userPaths);
0e2628
+            paths = g_slist_append(paths, path);
0e2628
+            userPaths = c;
0e2628
          }
0e2628
       }
0e2628
    }
0e2628
 
0e2628
+   if (paths == NULL) {
0e2628
+      Warning(LGPFX "No paths to freeze.\n");
0e2628
+      return SD_ERROR;
0e2628
+   }
0e2628
+
0e2628
    while (err == SD_UNAVAILABLE && i < ARRAYSIZE(gBackends)) {
0e2628
       SyncFreezeFn freezeFn = gBackends[i];
0e2628
       Debug(LGPFX "Calling backend %d.\n", (int) i);
0e2628
@@ -262,7 +291,12 @@ 
0e2628
       err = freezeFn(paths, handle);
0e2628
    }
0e2628
 
0e2628
-   free(paths);
0e2628
+   /*
0e2628
+    * g_slist_free_full requires glib >= v2.28
0e2628
+    */
0e2628
+   g_slist_foreach(paths, SyncDriverFreePath, NULL);
0e2628
+   g_slist_free(paths);
0e2628
+
0e2628
    return err == SD_SUCCESS;
0e2628
 }
0e2628
 
0e2628
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/vmSyncDriver.c	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/vmSyncDriver.c	2017-01-11 02:08:10.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2011-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2011-2016 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -24,9 +24,11 @@ 
0e2628
 
0e2628
 #include <fcntl.h>
0e2628
 #include <sys/ioctl.h>
0e2628
+#include <glib.h>
0e2628
 #include "debug.h"
0e2628
 #include "syncDriverInt.h"
0e2628
 #include "syncDriverIoc.h"
0e2628
+#include "strutil.h"
0e2628
 #include "util.h"
0e2628
 
0e2628
 #define SYNC_PROC_PATH "/proc/driver/vmware-sync"
0e2628
@@ -89,7 +91,7 @@ 
0e2628
  * Opens a description to the driver's proc node, and if successful, send an
0e2628
  * ioctl to freeze the requested filesystems.
0e2628
  *
0e2628
- * @param[in]  paths    Paths to freeze (colon-delimited).
0e2628
+ * @param[in]  paths    List of paths to freeze.
0e2628
  * @param[out] handle   Where to store the handle to use for thawing.
0e2628
  *
0e2628
  * @return A SyncDriverErr.
0e2628
@@ -98,19 +100,41 @@ 
0e2628
  */
0e2628
 
0e2628
 SyncDriverErr
0e2628
-VmSync_Freeze(const char *paths,
0e2628
+VmSync_Freeze(const GSList *paths,
0e2628
               SyncDriverHandle *handle)
0e2628
 {
0e2628
    int file;
0e2628
+   Bool first = TRUE;
0e2628
+   char *allPaths = NULL;
0e2628
    VmSyncDriver *sync = NULL;
0e2628
 
0e2628
-   Debug(LGPFX "Freezing %s using vmsync driver...\n", paths);
0e2628
+   Debug(LGPFX "Freezing using vmsync driver...\n");
0e2628
 
0e2628
    file = open(SYNC_PROC_PATH, O_RDONLY);
0e2628
    if (file == -1) {
0e2628
       return SD_UNAVAILABLE;
0e2628
    }
0e2628
 
0e2628
+   /*
0e2628
+    * Ensure we did not get an empty list
0e2628
+    */
0e2628
+   VERIFY(paths != NULL);
0e2628
+
0e2628
+   /*
0e2628
+    * Concatenate all paths in the list into one string
0e2628
+    */
0e2628
+   while (paths != NULL) {
0e2628
+      if (!first) {
0e2628
+         /*
0e2628
+          * Append the separator (':')
0e2628
+          */
0e2628
+         StrUtil_SafeStrcat(&allPaths, ":");
0e2628
+      }
0e2628
+      StrUtil_SafeStrcat(&allPaths, paths->data);
0e2628
+      first = FALSE;
0e2628
+      paths = g_slist_next(paths);
0e2628
+   }
0e2628
+
0e2628
    sync = calloc(1, sizeof *sync);
0e2628
    if (sync == NULL) {
0e2628
       goto exit;
0e2628
@@ -120,7 +144,9 @@ 
0e2628
    sync->driver.close = VmSyncClose;
0e2628
    sync->fd = file;
0e2628
 
0e2628
-   if (ioctl(file, SYNC_IOC_FREEZE, paths) == -1) {
0e2628
+   Debug(LGPFX "Freezing %s using vmsync driver...\n", allPaths);
0e2628
+
0e2628
+   if (ioctl(file, SYNC_IOC_FREEZE, allPaths) == -1) {
0e2628
       free(sync);
0e2628
       sync = NULL;
0e2628
    }
0e2628
@@ -133,6 +159,7 @@ 
0e2628
    } else {
0e2628
       *handle = &sync->driver;
0e2628
    }
0e2628
+   free(allPaths);
0e2628
    return sync != NULL ? SD_SUCCESS : SD_ERROR;
0e2628
 }
0e2628
 
0e2628
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/README	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/README	2017-01-11 02:08:10.000000000 -0800
0e2628
@@ -24,6 +24,10 @@ 
0e2628
                                 | d            |
0e2628
                                \/              |
0e2628
                             SCRIPT_THAW --------
0e2628
+                                |              |
0e2628
+                                | f            | g
0e2628
+                               \/              |
0e2628
+                            COMPLETE_WAIT-------
0e2628
 
0e2628
 The transitions mean the following events / conditions:
0e2628
 
0e2628
@@ -33,6 +37,8 @@ 
0e2628
 c. vmbackup.snapshotDone RPC
0e2628
 d. sync provider operation is finished
0e2628
 e. error condition: runtime error, or vmbackup.abort RPC
0e2628
+f. thaw scripts run finished
0e2628
+g. get notification that snapshot succeeds
0e2628
 
0e2628
 Sending a vmbackup.start RPC while the state machine is not IDLE causes an
0e2628
 error to be returned to the client, but the state machine is not changed.
0e2628
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/nullProvider.c	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/nullProvider.c	2017-01-11 02:08:10.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2010-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2010-2016 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -32,6 +32,7 @@ 
0e2628
 
0e2628
 
0e2628
 #if defined(_WIN32)
0e2628
+
0e2628
 /*
0e2628
  ******************************************************************************
0e2628
  * VmBackupNullStart --                                                 */ /**
0e2628
@@ -54,14 +55,128 @@ 
0e2628
    return VmBackup_SendEvent(VMBACKUP_EVENT_SNAPSHOT_COMMIT, 0, "");
0e2628
 }
0e2628
 
0e2628
+
0e2628
+/*
0e2628
+ ******************************************************************************
0e2628
+ * VmBackupNullSnapshotDone --                                          */ /**
0e2628
+ *
0e2628
+ * Does nothing, just keep the backup state machine alive.
0e2628
+ *
0e2628
+ * @param[in] state         Backup state.
0e2628
+ * @param[in] clientData    Unused.
0e2628
+ *
0e2628
+ * @return TRUE.
0e2628
+ *
0e2628
+ ******************************************************************************
0e2628
+ */
0e2628
+
0e2628
+static Bool
0e2628
+VmBackupNullSnapshotDone(VmBackupState *state,
0e2628
+                         void *clientData)
0e2628
+{
0e2628
+   VmBackup_SetCurrentOp(state, NULL, NULL, __FUNCTION__);
0e2628
+   return TRUE;
0e2628
+}
0e2628
+
0e2628
 #else
0e2628
 
0e2628
 /*
0e2628
  ******************************************************************************
0e2628
+ * VmBackupNullReadyForSnapshot --                                      */ /**
0e2628
+ *
0e2628
+ * Sends an event to the VMX indicating that the guest is ready for a
0e2628
+ * snapshot to be taken (i.e., scripts have run and Nulldriver is
0e2628
+ * enabled).
0e2628
+ *
0e2628
+ * @param[in] state         Backup state.
0e2628
+ *
0e2628
+ * @return TRUE, unless sending the message fails.
0e2628
+ *
0e2628
+ ******************************************************************************
0e2628
+ */
0e2628
+
0e2628
+static Bool
0e2628
+VmBackupNullReadyForSnapshot(VmBackupState *state)
0e2628
+{
0e2628
+   Bool success;
0e2628
+
0e2628
+   g_debug("*** %s\n", __FUNCTION__);
0e2628
+   success = VmBackup_SendEvent(VMBACKUP_EVENT_SNAPSHOT_COMMIT, 0, "");
0e2628
+   if (success) {
0e2628
+      state->freezeStatus = VMBACKUP_FREEZE_FINISHED;
0e2628
+   } else {
0e2628
+      g_warning("Failed to send commit event to host");
0e2628
+      state->freezeStatus = VMBACKUP_FREEZE_ERROR;
0e2628
+   }
0e2628
+   return success;
0e2628
+}
0e2628
+
0e2628
+
0e2628
+/*
0e2628
+ ******************************************************************************
0e2628
+ * VmBackupNullOpQuery --                                               */ /**
0e2628
+ *
0e2628
+ * Checks the status of the operation that is enabling or disabling the
0e2628
+ * Null driver. Nulldriver is enabled immediately and there is nothing
0e2628
+ * to disable.
0e2628
+ *
0e2628
+ * @param[in] op        VmBackupOp.
0e2628
+ *
0e2628
+ * @return VMBACKUP_STATUS_FINISHED always.
0e2628
+ *
0e2628
+ ******************************************************************************
0e2628
+ */
0e2628
+
0e2628
+static VmBackupOpStatus
0e2628
+VmBackupNullOpQuery(VmBackupOp *op) // IN
0e2628
+{
0e2628
+   return VMBACKUP_STATUS_FINISHED;
0e2628
+}
0e2628
+
0e2628
+
0e2628
+/*
0e2628
+ ******************************************************************************
0e2628
+ * VmBackupNullOpRelease --                                             */ /**
0e2628
+ *
0e2628
+ * Cleans up data held by the op object.
0e2628
+ *
0e2628
+ * @param[in] op        VmBackupOp.
0e2628
+ *
0e2628
+ ******************************************************************************
0e2628
+ */
0e2628
+
0e2628
+static void
0e2628
+VmBackupNullOpRelease(VmBackupOp *op)  // IN
0e2628
+{
0e2628
+   g_free(op);
0e2628
+}
0e2628
+
0e2628
+
0e2628
+/*
0e2628
+ ******************************************************************************
0e2628
+ * VmBackupNullOpCancel --                                              */ /**
0e2628
+ *
0e2628
+ * Cancel an ongoing Nulldriver operation. This doesn't actually
0e2628
+ * do anything because there is no operation to cancel as such.
0e2628
+ *
0e2628
+ * @param[in] op        VmBackupOp.
0e2628
+ *
0e2628
+ ******************************************************************************
0e2628
+ */
0e2628
+
0e2628
+static void
0e2628
+VmBackupNullOpCancel(VmBackupOp *op)   // IN
0e2628
+{
0e2628
+   /* Nothing to do */
0e2628
+}
0e2628
+
0e2628
+
0e2628
+/*
0e2628
+ ******************************************************************************
0e2628
  * VmBackupNullStart --                                                 */ /**
0e2628
  *
0e2628
- * Calls sync(2) on POSIX systems. Sends the "commit snapshot" event to the
0e2628
- * host.
0e2628
+ * Calls sync(2) on POSIX systems. Sets up an asynchronous operation
0e2628
+ * for tracking.
0e2628
  *
0e2628
  * @param[in] ctx           Plugin context.
0e2628
  * @param[in] state         Backup state.
0e2628
@@ -73,28 +188,35 @@ 
0e2628
 VmBackupNullStart(ToolsAppCtx *ctx,
0e2628
                   void *clientData)
0e2628
 {
0e2628
+   VmBackupOp *op;
0e2628
    VmBackupState *state = (VmBackupState*) clientData;
0e2628
+
0e2628
+   g_debug("*** %s\n", __FUNCTION__);
0e2628
+
0e2628
+   op = g_new0(VmBackupOp, 1);
0e2628
+   op->queryFn = VmBackupNullOpQuery;
0e2628
+   op->cancelFn = VmBackupNullOpCancel;
0e2628
+   op->releaseFn = VmBackupNullOpRelease;
0e2628
+
0e2628
    /*
0e2628
     * This is more of a "let's at least do something" than something that
0e2628
     * will actually ensure data integrity...
0e2628
     */
0e2628
    sync();
0e2628
-   VmBackup_SetCurrentOp(state, NULL, NULL, __FUNCTION__);
0e2628
-   if (!VmBackup_SendEvent(VMBACKUP_EVENT_SNAPSHOT_COMMIT, 0, "")) {
0e2628
-      g_warning("Failed to send commit event to host");
0e2628
-      state->freezeStatus = VMBACKUP_FREEZE_ERROR;
0e2628
-   } else {
0e2628
-      state->freezeStatus = VMBACKUP_FREEZE_FINISHED;
0e2628
-   }
0e2628
+
0e2628
+   VmBackup_SetCurrentOp(state,
0e2628
+                         op,
0e2628
+                         VmBackupNullReadyForSnapshot,
0e2628
+                         __FUNCTION__);
0e2628
 }
0e2628
-#endif
0e2628
 
0e2628
 
0e2628
 /*
0e2628
  ******************************************************************************
0e2628
  * VmBackupNullSnapshotDone --                                          */ /**
0e2628
  *
0e2628
- * Does nothing, just keep the backup state machine alive.
0e2628
+ * Does nothing except setting up an asynchronous operation to keep the
0e2628
+ * backup state machine alive.
0e2628
  *
0e2628
  * @param[in] state         Backup state.
0e2628
  * @param[in] clientData    Unused.
0e2628
@@ -108,10 +230,20 @@ 
0e2628
 VmBackupNullSnapshotDone(VmBackupState *state,
0e2628
                          void *clientData)
0e2628
 {
0e2628
-   VmBackup_SetCurrentOp(state, NULL, NULL, __FUNCTION__);
0e2628
+   VmBackupOp *op;
0e2628
+
0e2628
+   g_debug("*** %s\n", __FUNCTION__);
0e2628
+
0e2628
+   op = g_new0(VmBackupOp, 1);
0e2628
+   op->queryFn = VmBackupNullOpQuery;
0e2628
+   op->cancelFn = VmBackupNullOpCancel;
0e2628
+   op->releaseFn = VmBackupNullOpRelease;
0e2628
+
0e2628
+   VmBackup_SetCurrentOp(state, op, NULL, __FUNCTION__);
0e2628
    return TRUE;
0e2628
 }
0e2628
 
0e2628
+#endif
0e2628
 
0e2628
 /*
0e2628
  ******************************************************************************
0e2628
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/stateMachine.c	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/stateMachine.c	2017-01-11 02:08:10.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2007-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2007-2017 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -74,6 +74,18 @@ 
0e2628
                             NULL);                                            \
0e2628
 } while (0)
0e2628
 
0e2628
+/*
0e2628
+ * Macros to read values from config file.
0e2628
+ */
0e2628
+#define VMBACKUP_CONFIG_GET_BOOL(config, key, defVal)       \
0e2628
+   VMTools_ConfigGetBoolean(config, "vmbackup", key, defVal)
0e2628
+
0e2628
+#define VMBACKUP_CONFIG_GET_STR(config, key, defVal)        \
0e2628
+   VMTools_ConfigGetString(config, "vmbackup", key, defVal)
0e2628
+
0e2628
+#define VMBACKUP_CONFIG_GET_INT(config, key, defVal)        \
0e2628
+   VMTools_ConfigGetInteger(config, "vmbackup", key, defVal)
0e2628
+
0e2628
 static VmBackupState *gBackupState = NULL;
0e2628
 
0e2628
 static Bool
0e2628
@@ -82,6 +94,9 @@ 
0e2628
 static Bool
0e2628
 VmBackupEnableSyncWait(void);
0e2628
 
0e2628
+static Bool
0e2628
+VmBackupEnableCompleteWait(void);
0e2628
+
0e2628
 
0e2628
 /**
0e2628
  * Returns a string representation of the given state machine state.
0e2628
@@ -113,6 +128,9 @@ 
0e2628
    case VMBACKUP_MSTATE_SCRIPT_THAW:
0e2628
       return "SCRIPT_THAW";
0e2628
 
0e2628
+   case VMBACKUP_MSTATE_COMPLETE_WAIT:
0e2628
+      return "COMPLETE_WAIT";
0e2628
+
0e2628
    case VMBACKUP_MSTATE_SCRIPT_ERROR:
0e2628
       return "SCRIPT_ERROR";
0e2628
 
0e2628
@@ -249,7 +267,8 @@ 
0e2628
 #endif
0e2628
 
0e2628
    if (!success) {
0e2628
-      g_warning("Failed to send vmbackup event: %s.\n", result);
0e2628
+      g_warning("Failed to send vmbackup event: %s, result: %s.\n",
0e2628
+                msg, result);
0e2628
    }
0e2628
    vm_free(result);
0e2628
    g_free(msg);
0e2628
@@ -299,6 +318,9 @@ 
0e2628
    }
0e2628
 
0e2628
    gBackupState->provider->release(gBackupState->provider);
0e2628
+   if (gBackupState->completer != NULL) {
0e2628
+      gBackupState->completer->release(gBackupState->completer);
0e2628
+   }
0e2628
    g_static_mutex_free(&gBackupState->opLock);
0e2628
    g_free(gBackupState->scriptArg);
0e2628
    g_free(gBackupState->volumes);
0e2628
@@ -393,6 +415,7 @@ 
0e2628
       break;
0e2628
 
0e2628
    case VMBACKUP_MSTATE_SCRIPT_THAW:
0e2628
+   case VMBACKUP_MSTATE_COMPLETE_WAIT:
0e2628
       /* Next state is "idle". */
0e2628
       gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
0e2628
       break;
0e2628
@@ -417,6 +440,7 @@ 
0e2628
    ASSERT(gBackupState != NULL);
0e2628
    if (gBackupState->machineState != VMBACKUP_MSTATE_SCRIPT_ERROR &&
0e2628
        gBackupState->machineState != VMBACKUP_MSTATE_SYNC_ERROR) {
0e2628
+      const char *eventMsg = "Quiesce aborted.";
0e2628
       /* Mark the current operation as cancelled. */
0e2628
       g_static_mutex_lock(&gBackupState->opLock);
0e2628
       if (gBackupState->currentOp != NULL) {
0e2628
@@ -426,9 +450,21 @@ 
0e2628
       }
0e2628
       g_static_mutex_unlock(&gBackupState->opLock);
0e2628
 
0e2628
+#ifdef __linux__
0e2628
+      /* Thaw the guest if already quiesced */
0e2628
+      if (gBackupState->machineState == VMBACKUP_MSTATE_SYNC_FREEZE) {
0e2628
+         g_debug("Guest already quiesced, thawing for abort\n");
0e2628
+         if (!gBackupState->provider->snapshotDone(gBackupState,
0e2628
+                                      gBackupState->provider->clientData)) {
0e2628
+            g_debug("Thaw during abort failed\n");
0e2628
+            eventMsg = "Quiesce could not be aborted.";
0e2628
+         }
0e2628
+      }
0e2628
+#endif
0e2628
+
0e2628
       VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ABORT,
0e2628
                          VMBACKUP_REMOTE_ABORT,
0e2628
-                         "Quiesce aborted.");
0e2628
+                         eventMsg);
0e2628
 
0e2628
       /* Transition to the error state. */
0e2628
       if (VmBackupOnError()) {
0e2628
@@ -459,51 +495,49 @@ 
0e2628
 
0e2628
 
0e2628
 /**
0e2628
- * Callback that checks for the status of the current operation. Calls the
0e2628
- * queued operations as needed.
0e2628
+ * Post-process the current operation. Calls the queued
0e2628
+ * operations as needed.
0e2628
  *
0e2628
- * @param[in]  clientData     Unused.
0e2628
+ * @param[out]    pending     Tells if currentOp is pending.
0e2628
  *
0e2628
- * @return FALSE
0e2628
+ * @return TRUE if currentOp finished or pending, FALSE on error.
0e2628
  */
0e2628
 
0e2628
 static gboolean
0e2628
-VmBackupAsyncCallback(void *clientData)
0e2628
+VmBackupPostProcessCurrentOp(gboolean *pending)
0e2628
 {
0e2628
+   gboolean retVal = TRUE;
0e2628
    VmBackupOpStatus status = VMBACKUP_STATUS_FINISHED;
0e2628
 
0e2628
    g_debug("*** %s\n", __FUNCTION__);
0e2628
    ASSERT(gBackupState != NULL);
0e2628
 
0e2628
-   g_source_unref(gBackupState->timerEvent);
0e2628
-   gBackupState->timerEvent = NULL;
0e2628
+   *pending = FALSE;
0e2628
 
0e2628
    g_static_mutex_lock(&gBackupState->opLock);
0e2628
+
0e2628
    if (gBackupState->currentOp != NULL) {
0e2628
-      g_debug("VmBackupAsyncCallback: checking %s\n", gBackupState->currentOpName);
0e2628
+      g_debug("%s: checking %s\n", __FUNCTION__, gBackupState->currentOpName);
0e2628
       status = VmBackup_QueryStatus(gBackupState->currentOp);
0e2628
    }
0e2628
-   g_static_mutex_unlock(&gBackupState->opLock);
0e2628
 
0e2628
    switch (status) {
0e2628
    case VMBACKUP_STATUS_PENDING:
0e2628
+      *pending = TRUE;
0e2628
       goto exit;
0e2628
 
0e2628
    case VMBACKUP_STATUS_FINISHED:
0e2628
-      g_static_mutex_lock(&gBackupState->opLock);
0e2628
       if (gBackupState->currentOpName != NULL) {
0e2628
          g_debug("Async request '%s' completed\n", gBackupState->currentOpName);
0e2628
          VmBackup_Release(gBackupState->currentOp);
0e2628
          gBackupState->currentOpName = NULL;
0e2628
       }
0e2628
       gBackupState->currentOp = NULL;
0e2628
-      g_static_mutex_unlock(&gBackupState->opLock);
0e2628
       break;
0e2628
 
0e2628
    default:
0e2628
       {
0e2628
          gchar *msg;
0e2628
-         g_static_mutex_lock(&gBackupState->opLock);
0e2628
          if (gBackupState->errorMsg != NULL) {
0e2628
             msg = g_strdup_printf("'%s' operation failed: %s",
0e2628
                                   gBackupState->currentOpName,
0e2628
@@ -519,8 +553,7 @@ 
0e2628
 
0e2628
          VmBackup_Release(gBackupState->currentOp);
0e2628
          gBackupState->currentOp = NULL;
0e2628
-         g_static_mutex_unlock(&gBackupState->opLock);
0e2628
-         VmBackupOnError();
0e2628
+         retVal = FALSE;
0e2628
          goto exit;
0e2628
       }
0e2628
    }
0e2628
@@ -533,23 +566,62 @@ 
0e2628
       VmBackupCallback cb = gBackupState->callback;
0e2628
       gBackupState->callback = NULL;
0e2628
 
0e2628
+      /*
0e2628
+       * Callback should not acquire opLock, but instead assume that
0e2628
+       * it holds the lock already.
0e2628
+       */
0e2628
       if (cb(gBackupState)) {
0e2628
-         g_static_mutex_lock(&gBackupState->opLock);
0e2628
          if (gBackupState->currentOp != NULL || gBackupState->forceRequeue) {
0e2628
-            g_static_mutex_unlock(&gBackupState->opLock);
0e2628
             goto exit;
0e2628
          }
0e2628
-         g_static_mutex_unlock(&gBackupState->opLock);
0e2628
       } else {
0e2628
-         VmBackupOnError();
0e2628
+         retVal = FALSE;
0e2628
          goto exit;
0e2628
       }
0e2628
    }
0e2628
 
0e2628
+exit:
0e2628
+   g_static_mutex_unlock(&gBackupState->opLock);
0e2628
+   return retVal;
0e2628
+}
0e2628
+
0e2628
+
0e2628
+/**
0e2628
+ * Callback to advance the state machine to next state once
0e2628
+ * current operation finishes.
0e2628
+ *
0e2628
+ * @param[in]  clientData     Unused.
0e2628
+ *
0e2628
+ * @return FALSE
0e2628
+ */
0e2628
+
0e2628
+static gboolean
0e2628
+VmBackupAsyncCallback(void *clientData)
0e2628
+{
0e2628
+   gboolean opPending;
0e2628
+   g_debug("*** %s\n", __FUNCTION__);
0e2628
+   ASSERT(gBackupState != NULL);
0e2628
+
0e2628
+   g_source_unref(gBackupState->timerEvent);
0e2628
+   gBackupState->timerEvent = NULL;
0e2628
+
0e2628
    /*
0e2628
-    * At this point, the current operation can be declared finished, and the
0e2628
-    * state machine can move to the next state.
0e2628
+    * Move the state machine to the next state, if the
0e2628
+    * currentOp has finished.
0e2628
     */
0e2628
+   if (!VmBackupPostProcessCurrentOp(&opPending)) {
0e2628
+      VmBackupOnError();
0e2628
+      goto exit;
0e2628
+   } else {
0e2628
+      /*
0e2628
+       * State transition can't be done if currentOp
0e2628
+       * has not finished yet.
0e2628
+       */
0e2628
+      if (opPending) {
0e2628
+         goto exit;
0e2628
+      }
0e2628
+   }
0e2628
+
0e2628
    switch (gBackupState->machineState) {
0e2628
    case VMBACKUP_MSTATE_SCRIPT_FREEZE:
0e2628
       /* Next state is "sync freeze wait". */
0e2628
@@ -583,8 +655,15 @@ 
0e2628
       }
0e2628
       break;
0e2628
 
0e2628
-   case VMBACKUP_MSTATE_SCRIPT_ERROR:
0e2628
    case VMBACKUP_MSTATE_SCRIPT_THAW:
0e2628
+      /* Next state is "complete wait" or "idle". */
0e2628
+      if (!VmBackupEnableCompleteWait()) {
0e2628
+         VmBackupOnError();
0e2628
+      }
0e2628
+      break;
0e2628
+
0e2628
+   case VMBACKUP_MSTATE_SCRIPT_ERROR:
0e2628
+   case VMBACKUP_MSTATE_COMPLETE_WAIT:
0e2628
       /* Next state is "idle". */
0e2628
       gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
0e2628
       break;
0e2628
@@ -676,6 +755,62 @@ 
0e2628
 
0e2628
 
0e2628
 /**
0e2628
+ * Calls the completer's start function and moves the state
0e2628
+ * machine to next state.
0e2628
+ *
0e2628
+ * @return Whether the completer's start callback was successful.
0e2628
+ */
0e2628
+
0e2628
+static Bool
0e2628
+VmBackupEnableCompleteWait(void)
0e2628
+{
0e2628
+   Bool ret = TRUE;
0e2628
+
0e2628
+   g_debug("*** %s\n", __FUNCTION__);
0e2628
+
0e2628
+   if (gBackupState->completer == NULL) {
0e2628
+      gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
0e2628
+      goto exit;
0e2628
+   }
0e2628
+
0e2628
+   if (gBackupState->abortTimer != NULL) {
0e2628
+      g_source_destroy(gBackupState->abortTimer);
0e2628
+      g_source_unref(gBackupState->abortTimer);
0e2628
+
0e2628
+      /* Host make timeout maximum as 15 minutes for complete process. */
0e2628
+      if (gBackupState->timeout > GUEST_QUIESCE_DEFAULT_TIMEOUT_IN_SEC) {
0e2628
+         gBackupState->timeout = GUEST_QUIESCE_DEFAULT_TIMEOUT_IN_SEC;
0e2628
+      }
0e2628
+
0e2628
+      if (gBackupState->timeout != 0) {
0e2628
+         g_debug("Using completer timeout: %u\n", gBackupState->timeout);
0e2628
+         gBackupState->abortTimer =
0e2628
+            g_timeout_source_new_seconds(gBackupState->timeout);
0e2628
+         VMTOOLSAPP_ATTACH_SOURCE(gBackupState->ctx,
0e2628
+            gBackupState->abortTimer,
0e2628
+            VmBackupAbortTimer,
0e2628
+            NULL,
0e2628
+            NULL);
0e2628
+      }
0e2628
+   }
0e2628
+
0e2628
+   if (gBackupState->completer->start(gBackupState,
0e2628
+                                      gBackupState->completer->clientData)) {
0e2628
+      /* Move to next state */
0e2628
+      gBackupState->machineState = VMBACKUP_MSTATE_COMPLETE_WAIT;
0e2628
+   } else {
0e2628
+      VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ERROR,
0e2628
+                         VMBACKUP_SYNC_ERROR,
0e2628
+                         "Error when enabling the sync provider.");
0e2628
+      ret = FALSE;
0e2628
+   }
0e2628
+
0e2628
+exit:
0e2628
+   return ret;
0e2628
+}
0e2628
+
0e2628
+
0e2628
+/**
0e2628
  * After sync provider's start function returns and moves the state
0e2628
  * machine to VMBACKUP_MSTATE_SYNC_FREEZE state.
0e2628
  *
0e2628
@@ -709,36 +844,6 @@ 
0e2628
 
0e2628
 
0e2628
 /**
0e2628
- * Get boolean entry for the key from the config file.
0e2628
- *
0e2628
- * @param[in]  config        Config file to read the key from.
0e2628
- * @param[in]  key           Key to look for in the config file.
0e2628
- * @param[in]  defaultValue  Default value if the key is not found.
0e2628
- */
0e2628
-
0e2628
-static gboolean
0e2628
-VmBackupConfigGetBoolean(GKeyFile *config,
0e2628
-                         const char *key,
0e2628
-                         gboolean defValue)
0e2628
-{
0e2628
-   GError *err = NULL;
0e2628
-   gboolean value = defValue;
0e2628
-
0e2628
-   if (key != NULL) {
0e2628
-      value = g_key_file_get_boolean(config,
0e2628
-                                     "vmbackup",
0e2628
-                                     key,
0e2628
-                                     &err;;
0e2628
-      if (err != NULL) {
0e2628
-         g_clear_error(&err;;
0e2628
-         value = defValue;
0e2628
-      }
0e2628
-   }
0e2628
-   return value;
0e2628
-}
0e2628
-
0e2628
-
0e2628
-/**
0e2628
  * Starts the quiesce operation according to the supplied specification unless
0e2628
  * some unexpected error occurs.
0e2628
  *
0e2628
@@ -754,9 +859,9 @@ 
0e2628
 VmBackupStartCommon(RpcInData *data,
0e2628
                     gboolean forceQuiesce)
0e2628
 {
0e2628
-   GError *err = NULL;
0e2628
    ToolsAppCtx *ctx = data->appCtx;
0e2628
    VmBackupSyncProvider *provider = NULL;
0e2628
+   VmBackupSyncCompleter *completer = NULL;
0e2628
 
0e2628
    size_t i;
0e2628
 
0e2628
@@ -779,7 +884,7 @@ 
0e2628
           * only allow VSS provider
0e2628
           */
0e2628
 #if defined(_WIN32)
0e2628
-         if (VmBackupConfigGetBoolean(ctx->config, "enableVSS", TRUE)) {
0e2628
+         if (VMBACKUP_CONFIG_GET_BOOL(ctx->config, "enableVSS", TRUE)) {
0e2628
             provider = VmBackup_NewVssProvider();
0e2628
          }
0e2628
 #elif defined(_LINUX) || defined(__linux__)
0e2628
@@ -788,9 +893,9 @@ 
0e2628
           * only allow SyncDriver provider
0e2628
           */
0e2628
          if (gBackupState->quiesceFS &&
0e2628
-             VmBackupConfigGetBoolean(ctx->config, "enableSyncDriver", TRUE)) {
0e2628
+             VMBACKUP_CONFIG_GET_BOOL(ctx->config, "enableSyncDriver", TRUE)) {
0e2628
             provider = VmBackup_NewSyncDriverOnlyProvider();
0e2628
-          }
0e2628
+         }
0e2628
 #endif
0e2628
       } else {
0e2628
          /* If no quiescing is requested only allow null provider */
0e2628
@@ -805,7 +910,7 @@ 
0e2628
       for (i = 0; i < ARRAYSIZE(providers); i++) {
0e2628
          struct SyncProvider *sp = &providers[i];
0e2628
 
0e2628
-         if (VmBackupConfigGetBoolean(ctx->config, sp->cfgEntry, TRUE)) {
0e2628
+         if (VMBACKUP_CONFIG_GET_BOOL(ctx->config, sp->cfgEntry, TRUE)) {
0e2628
             provider = sp->ctor();
0e2628
             if (provider != NULL) {
0e2628
                break;
0e2628
@@ -816,15 +921,27 @@ 
0e2628
 
0e2628
    ASSERT(provider != NULL);
0e2628
 
0e2628
+#if defined(_WIN32)
0e2628
+   if (VMBACKUP_CONFIG_GET_BOOL(ctx->config, "enableVSS", TRUE)) {
0e2628
+      completer = VmBackup_NewVssCompleter(provider);
0e2628
+      if (completer == NULL) {
0e2628
+         provider->release(provider);
0e2628
+         g_warning("Requested quiescing cannot be initialized.");
0e2628
+         goto error;
0e2628
+      }
0e2628
+   }
0e2628
+#endif
0e2628
+
0e2628
    /* Instantiate the backup state and start the operation. */
0e2628
    gBackupState->ctx = data->appCtx;
0e2628
    gBackupState->pollPeriod = 1000;
0e2628
    gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
0e2628
    gBackupState->freezeStatus = VMBACKUP_FREEZE_FINISHED;
0e2628
    gBackupState->provider = provider;
0e2628
+   gBackupState->completer = completer;
0e2628
    gBackupState->needsPriv = FALSE;
0e2628
    g_static_mutex_init(&gBackupState->opLock);
0e2628
-   gBackupState->enableNullDriver = VmBackupConfigGetBoolean(ctx->config,
0e2628
+   gBackupState->enableNullDriver = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
0e2628
                                                              "enableNullDriver",
0e2628
                                                              TRUE);
0e2628
 
0e2628
@@ -864,15 +981,8 @@ 
0e2628
     * See bug 506106.
0e2628
     */
0e2628
    if (gBackupState->timeout == 0) {
0e2628
-      gBackupState->timeout = (guint) g_key_file_get_integer(
0e2628
-                                               gBackupState->ctx->config,
0e2628
-                                               "vmbackup",
0e2628
-                                               "timeout",
0e2628
-                                               &err;;
0e2628
-      if (err != NULL) {
0e2628
-         g_clear_error(&err;;
0e2628
-         gBackupState->timeout = 15 * 60;
0e2628
-      }
0e2628
+      gBackupState->timeout = VMBACKUP_CONFIG_GET_INT(ctx->config, "timeout",
0e2628
+                                       GUEST_QUIESCE_DEFAULT_TIMEOUT_IN_SEC);
0e2628
    }
0e2628
 
0e2628
    /* Treat "0" as no timeout. */
0e2628
@@ -898,6 +1008,9 @@ 
0e2628
    if (gBackupState->provider) {
0e2628
       gBackupState->provider->release(gBackupState->provider);
0e2628
    }
0e2628
+   if (gBackupState->completer) {
0e2628
+      gBackupState->completer->release(gBackupState->completer);
0e2628
+   }
0e2628
    g_free(gBackupState->scriptArg);
0e2628
    g_free(gBackupState->volumes);
0e2628
    g_free(gBackupState);
0e2628
@@ -923,6 +1036,8 @@ 
0e2628
 static gboolean
0e2628
 VmBackupStart(RpcInData *data)
0e2628
 {
0e2628
+   ToolsAppCtx *ctx = data->appCtx;
0e2628
+
0e2628
    g_debug("*** %s\n", __FUNCTION__);
0e2628
    if (gBackupState != NULL) {
0e2628
       return RPCIN_SETRETVALS(data, "Quiesce operation already in progress.",
0e2628
@@ -936,12 +1051,26 @@ 
0e2628
       if (StrUtil_GetNextIntToken(&generateManifests, &index, data->args, " ")) {
0e2628
          gBackupState->generateManifests = generateManifests;
0e2628
       }
0e2628
-      gBackupState->quiesceApps = TRUE;
0e2628
-      gBackupState->quiesceFS = TRUE;
0e2628
-      gBackupState->allowHWProvider = TRUE;
0e2628
-      gBackupState->execScripts = TRUE;
0e2628
-      gBackupState->scriptArg = NULL;
0e2628
-      gBackupState->timeout = 0;
0e2628
+      gBackupState->quiesceApps = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
0e2628
+                                                           "quiesceApps",
0e2628
+                                                           TRUE);
0e2628
+      gBackupState->quiesceFS = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
0e2628
+                                                         "quiesceFS",
0e2628
+                                                         TRUE);
0e2628
+      gBackupState->allowHWProvider = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
0e2628
+                                                             "allowHWProvider",
0e2628
+                                                             TRUE);
0e2628
+      gBackupState->execScripts = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
0e2628
+                                                           "execScripts",
0e2628
+                                                           TRUE);
0e2628
+      gBackupState->scriptArg = VMBACKUP_CONFIG_GET_STR(ctx->config,
0e2628
+                                                        "scriptArg",
0e2628
+                                                        NULL);
0e2628
+      gBackupState->timeout = VMBACKUP_CONFIG_GET_INT(ctx->config,
0e2628
+                                                      "timeout", 0);
0e2628
+      gBackupState->vssUseDefault = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
0e2628
+                                                             "vssUseDefault",
0e2628
+                                                             TRUE);
0e2628
 
0e2628
       /* get volume uuids if provided */
0e2628
       if (data->args[index] != '\0') {
0e2628
@@ -949,7 +1078,9 @@ 
0e2628
                                            data->argsSize - index);
0e2628
       }
0e2628
    }
0e2628
-   return VmBackupStartCommon(data, FALSE);
0e2628
+   return VmBackupStartCommon(data, VMBACKUP_CONFIG_GET_BOOL(ctx->config,
0e2628
+                                                             "forceQuiesce",
0e2628
+                                                             FALSE));
0e2628
 }
0e2628
 
0e2628
 
0e2628
@@ -987,8 +1118,10 @@ 
0e2628
 static gboolean
0e2628
 VmBackupStartWithOpts(RpcInData *data)
0e2628
 {
0e2628
+   ToolsAppCtx *ctx = data->appCtx;
0e2628
    GuestQuiesceParams *params;
0e2628
-   GuestQuiesceParamsV1 *paramsV1;
0e2628
+   GuestQuiesceParamsV1 *paramsV1 = NULL;
0e2628
+   GuestQuiesceParamsV2 *paramsV2;
0e2628
    gboolean retval;
0e2628
 
0e2628
    g_debug("*** %s\n", __FUNCTION__);
0e2628
@@ -997,24 +1130,57 @@ 
0e2628
                               FALSE);
0e2628
    }
0e2628
    params = (GuestQuiesceParams *)data->args;
0e2628
+
0e2628
+#if defined(_WIN32)
0e2628
+   if (params->ver != GUESTQUIESCEPARAMS_V1 &&
0e2628
+       params->ver != GUESTQUIESCEPARAMS_V2) {
0e2628
+      g_warning("%s: Incompatible quiesce parameter version. \n", __FUNCTION__);
0e2628
+      return RPCIN_SETRETVALS(data, "Incompatible quiesce parameter version",
0e2628
+                              FALSE);
0e2628
+   }
0e2628
+#else
0e2628
    if (params->ver != GUESTQUIESCEPARAMS_V1) {
0e2628
       g_warning("%s: Incompatible quiesce parameter version. \n", __FUNCTION__);
0e2628
       return RPCIN_SETRETVALS(data, "Incompatible quiesce parameter version",
0e2628
                               FALSE);
0e2628
    }
0e2628
+#endif
0e2628
+
0e2628
    gBackupState = g_new0(VmBackupState, 1);
0e2628
-   paramsV1 = params->GuestQuiesceParams_u.guestQuiesceParamsV1;
0e2628
-   gBackupState->generateManifests = paramsV1->createManifest;
0e2628
-   gBackupState->quiesceApps = paramsV1->quiesceApps;
0e2628
-   gBackupState->quiesceFS = paramsV1->quiesceFS;
0e2628
-   gBackupState->allowHWProvider = paramsV1->writableSnapshot;
0e2628
-   gBackupState->execScripts = paramsV1->execScripts;
0e2628
-   gBackupState->scriptArg = g_strndup(paramsV1->scriptArg,
0e2628
-                                       strlen(paramsV1->scriptArg));
0e2628
-   gBackupState->timeout = paramsV1->timeout;
0e2628
-   gBackupState->volumes = g_strndup(paramsV1->diskUuids,
0e2628
-                                     strlen(paramsV1->diskUuids));
0e2628
-   retval = VmBackupStartCommon(data, TRUE);
0e2628
+
0e2628
+   if (params->ver == GUESTQUIESCEPARAMS_V1) {
0e2628
+      paramsV1 = params->GuestQuiesceParams_u.guestQuiesceParamsV1;
0e2628
+      gBackupState->vssUseDefault = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
0e2628
+                                                             "vssUseDefault",
0e2628
+                                                             TRUE);
0e2628
+   } else if (params->ver == GUESTQUIESCEPARAMS_V2) {
0e2628
+      paramsV2 = params->GuestQuiesceParams_u.guestQuiesceParamsV2;
0e2628
+      paramsV1 = &paramsV2->paramsV1;
0e2628
+      gBackupState->vssBackupContext = paramsV2->vssBackupContext;
0e2628
+      gBackupState->vssBackupType = paramsV2->vssBackupType;
0e2628
+      gBackupState->vssBootableSystemState = paramsV2->vssBootableSystemState;
0e2628
+      gBackupState->vssPartialFileSupport = paramsV2->vssPartialFileSupport;
0e2628
+      gBackupState->vssUseDefault = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
0e2628
+                                                             "vssUseDefault",
0e2628
+                                                             FALSE);
0e2628
+   }
0e2628
+
0e2628
+   if (paramsV1 != NULL) {
0e2628
+      gBackupState->generateManifests = paramsV1->createManifest;
0e2628
+      gBackupState->quiesceApps = paramsV1->quiesceApps;
0e2628
+      gBackupState->quiesceFS = paramsV1->quiesceFS;
0e2628
+      gBackupState->allowHWProvider = paramsV1->writableSnapshot;
0e2628
+      gBackupState->execScripts = paramsV1->execScripts;
0e2628
+      gBackupState->scriptArg = g_strndup(paramsV1->scriptArg,
0e2628
+                                          strlen(paramsV1->scriptArg));
0e2628
+      gBackupState->timeout = paramsV1->timeout;
0e2628
+      gBackupState->volumes = g_strndup(paramsV1->diskUuids,
0e2628
+                                        strlen(paramsV1->diskUuids));
0e2628
+   }
0e2628
+
0e2628
+   retval = VmBackupStartCommon(data, VMBACKUP_CONFIG_GET_BOOL(ctx->config,
0e2628
+                                                               "forceQuiesce",
0e2628
+                                                               TRUE));
0e2628
    return retval;
0e2628
 }
0e2628
 
0e2628
@@ -1085,6 +1251,45 @@ 
0e2628
 
0e2628
 
0e2628
 /**
0e2628
+ * Notifies the completer to complete the provider process
0e2628
+ * machine in the COMPLETE_WAIT state.
0e2628
+ *
0e2628
+ * @param[in]  data     RPC data.
0e2628
+ *
0e2628
+ * @return TRUE
0e2628
+ */
0e2628
+
0e2628
+static gboolean
0e2628
+VmBackupSnapshotCompleted(RpcInData *data)
0e2628
+{
0e2628
+   g_debug("*** %s\n", __FUNCTION__);
0e2628
+
0e2628
+   if (gBackupState == NULL ||
0e2628
+       gBackupState->completer == NULL) {
0e2628
+      return RPCIN_SETRETVALS(data, "Error: no quiesce complete in progress",
0e2628
+                              FALSE);
0e2628
+   } else if (gBackupState->machineState != VMBACKUP_MSTATE_COMPLETE_WAIT) {
0e2628
+      g_warning("Error: unexpected state for snapshot complete message: %s",
0e2628
+                VmBackupGetStateName(gBackupState->machineState));
0e2628
+      return RPCIN_SETRETVALS(data,
0e2628
+                              "Error: unexpected state for complete message.",
0e2628
+                              FALSE);
0e2628
+   } else {
0e2628
+      if (!gBackupState->completer->snapshotCompleted(gBackupState,
0e2628
+             gBackupState->completer->clientData)) {
0e2628
+         VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ERROR,
0e2628
+                            VMBACKUP_SYNC_ERROR,
0e2628
+                            "Error when notifying the sync completer.");
0e2628
+         if (VmBackupOnError()) {
0e2628
+            VmBackupFinalize();
0e2628
+         }
0e2628
+      }
0e2628
+      return RPCIN_SETRETVALS(data, "", TRUE);
0e2628
+   }
0e2628
+}
0e2628
+
0e2628
+
0e2628
+/**
0e2628
  * Prints some information about the plugin's state to the log.
0e2628
  *
0e2628
  * @param[in]  src      The source object.
0e2628
@@ -1167,6 +1372,8 @@ 
0e2628
       { VMBACKUP_PROTOCOL_START_WITH_OPTS, VmBackupStartWithOpts, NULL,
0e2628
                     xdr_GuestQuiesceParams, NULL, sizeof (GuestQuiesceParams) },
0e2628
       { VMBACKUP_PROTOCOL_ABORT, VmBackupAbort, NULL, NULL, NULL, 0 },
0e2628
+      { VMBACKUP_PROTOCOL_SNAPSHOT_COMPLETED, VmBackupSnapshotCompleted, NULL,
0e2628
+                    NULL, NULL, 0 },
0e2628
       { VMBACKUP_PROTOCOL_SNAPSHOT_DONE, VmBackupSnapshotDone, NULL, NULL, NULL, 0 }
0e2628
    };
0e2628
    ToolsPluginSignalCb sigs[] = {
0e2628
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/syncDriverOps.c	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/syncDriverOps.c	2017-01-11 02:08:10.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2007-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2007-2017 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -61,10 +61,10 @@ 
0e2628
  */
0e2628
 
0e2628
 static Bool
0e2628
-VmBackupDriverThaw(VmBackupDriverOp *op)
0e2628
+VmBackupDriverThaw(SyncDriverHandle *handle)
0e2628
 {
0e2628
-   Bool success = SyncDriver_Thaw(*op->syncHandle);
0e2628
-   SyncDriver_CloseHandle(op->syncHandle);
0e2628
+   Bool success = SyncDriver_Thaw(*handle);
0e2628
+   SyncDriver_CloseHandle(handle);
0e2628
    return success;
0e2628
 }
0e2628
 
0e2628
@@ -106,7 +106,7 @@ 
0e2628
 
0e2628
       case SYNCDRIVER_IDLE:
0e2628
          if (op->canceled) {
0e2628
-            VmBackupDriverThaw(op);
0e2628
+            VmBackupDriverThaw(op->syncHandle);
0e2628
          }
0e2628
          /*
0e2628
           * This prevents the release callback from freeing the handle, which
0e2628
@@ -117,7 +117,7 @@ 
0e2628
          break;
0e2628
 
0e2628
       default:
0e2628
-         VmBackupDriverThaw(op);
0e2628
+         VmBackupDriverThaw(op->syncHandle);
0e2628
          ret = VMBACKUP_STATUS_ERROR;
0e2628
          break;
0e2628
       }
0e2628
@@ -231,7 +231,7 @@ 
0e2628
                                   state->enableNullDriver : FALSE,
0e2628
                                   op->syncHandle);
0e2628
    } else {
0e2628
-      success = VmBackupDriverThaw(op);
0e2628
+      success = VmBackupDriverThaw(op->syncHandle);
0e2628
    }
0e2628
    if (!success) {
0e2628
       g_warning("Error %s filesystems.", freeze ? "freezing" : "thawing");
0e2628
@@ -264,15 +264,24 @@ 
0e2628
 static Bool
0e2628
 VmBackupSyncDriverReadyForSnapshot(VmBackupState *state)
0e2628
 {
0e2628
-   Bool success;
0e2628
    SyncDriverHandle *handle = state->clientData;
0e2628
 
0e2628
    g_debug("*** %s\n", __FUNCTION__);
0e2628
    if (handle != NULL && *handle != SYNCDRIVER_INVALID_HANDLE) {
0e2628
+      Bool success;
0e2628
       success = VmBackup_SendEvent(VMBACKUP_EVENT_SNAPSHOT_COMMIT, 0, "");
0e2628
       if (success) {
0e2628
          state->freezeStatus = VMBACKUP_FREEZE_FINISHED;
0e2628
       } else {
0e2628
+         /*
0e2628
+          * If the vmx does not know this event (e.g. due to an RPC timeout),
0e2628
+          * then filesystems need to be thawed here because snapshotDone
0e2628
+          * will not be sent by the vmx.
0e2628
+          */
0e2628
+         g_debug("VMX state changed; thawing filesystems.\n");
0e2628
+         if (!VmBackupDriverThaw(handle)) {
0e2628
+            g_warning("Error thawing filesystems.\n");
0e2628
+         }
0e2628
          state->freezeStatus = VMBACKUP_FREEZE_ERROR;
0e2628
       }
0e2628
       return success;
0e2628
@@ -488,7 +497,7 @@ 
0e2628
 
0e2628
 static Bool
0e2628
 VmBackupSyncDriverOnlySnapshotDone(VmBackupState *state,
0e2628
-                               void *clientData)
0e2628
+                                   void *clientData)
0e2628
 {
0e2628
    VmBackupDriverOp *op;
0e2628
 
0e2628
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/vmBackupInt.h	2015-11-23 23:07:44.000000000 -0800
0e2628
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/vmBackupInt.h	2017-01-11 02:08:10.000000000 -0800
0e2628
@@ -1,5 +1,5 @@ 
0e2628
 /*********************************************************
0e2628
- * Copyright (C) 2008-2015 VMware, Inc. All rights reserved.
0e2628
+ * Copyright (C) 2008-2016 VMware, Inc. All rights reserved.
0e2628
  *
0e2628
  * This program is free software; you can redistribute it and/or modify it
0e2628
  * under the terms of the GNU Lesser General Public License as published
0e2628
@@ -35,6 +35,11 @@ 
0e2628
 #include "vmware/tools/threadPool.h"
0e2628
 #endif
0e2628
 
0e2628
+/*
0e2628
+ * The default timeout in seconds for guest OS quiescing process
0e2628
+ */
0e2628
+#define GUEST_QUIESCE_DEFAULT_TIMEOUT_IN_SEC     (15 * 60)
0e2628
+
0e2628
 typedef enum {
0e2628
    VMBACKUP_STATUS_PENDING,
0e2628
    VMBACKUP_STATUS_FINISHED,
0e2628
@@ -62,6 +67,7 @@ 
0e2628
    VMBACKUP_MSTATE_SYNC_FREEZE,
0e2628
    VMBACKUP_MSTATE_SYNC_THAW,
0e2628
    VMBACKUP_MSTATE_SCRIPT_THAW,
0e2628
+   VMBACKUP_MSTATE_COMPLETE_WAIT,
0e2628
    VMBACKUP_MSTATE_SCRIPT_ERROR,
0e2628
    VMBACKUP_MSTATE_SYNC_ERROR
0e2628
 } VmBackupMState;
0e2628
@@ -81,6 +87,7 @@ 
0e2628
 
0e2628
 
0e2628
 struct VmBackupSyncProvider;
0e2628
+struct VmBackupSyncCompleter;
0e2628
 
0e2628
 /**
0e2628
  * Holds information about the current state of the backup operation.
0e2628
@@ -114,7 +121,7 @@ 
0e2628
    Bool           execScripts;
0e2628
    Bool           enableNullDriver;
0e2628
    Bool           needsPriv;
0e2628
-   char          *scriptArg;
0e2628
+   gchar         *scriptArg;
0e2628
    guint          timeout;
0e2628
    gpointer       clientData;
0e2628
    void          *scripts;
0e2628
@@ -124,10 +131,17 @@ 
0e2628
    VmBackupMState machineState;
0e2628
    VmBackupFreezeStatus freezeStatus;
0e2628
    struct VmBackupSyncProvider *provider;
0e2628
+   struct VmBackupSyncCompleter *completer;
0e2628
+   gint           vssBackupContext;
0e2628
+   gint           vssBackupType;
0e2628
+   Bool           vssBootableSystemState;
0e2628
+   Bool           vssPartialFileSupport;
0e2628
+   Bool           vssUseDefault;
0e2628
 } VmBackupState;
0e2628
 
0e2628
 typedef Bool (*VmBackupCallback)(VmBackupState *);
0e2628
 typedef Bool (*VmBackupProviderCallback)(VmBackupState *, void *clientData);
0e2628
+typedef Bool (*VmBackupCompleterCallback)(VmBackupState *, void *clientData);
0e2628
 
0e2628
 
0e2628
 /**
0e2628
@@ -147,6 +161,19 @@ 
0e2628
    void *clientData;
0e2628
 } VmBackupSyncProvider;
0e2628
 
0e2628
+/**
0e2628
+ * Defines the interface between the state machine and the implementation
0e2628
+ * of the "sync completer": either the VSS completer or the sync driver
0e2628
+ * completer, currently.
0e2628
+ */
0e2628
+
0e2628
+typedef struct VmBackupSyncCompleter {
0e2628
+   VmBackupCompleterCallback start;
0e2628
+   VmBackupCompleterCallback snapshotCompleted;
0e2628
+   void (*release)(struct VmBackupSyncCompleter *);
0e2628
+   void *clientData;
0e2628
+} VmBackupSyncCompleter;
0e2628
+
0e2628
 
0e2628
 /**
0e2628
  * Sets the current asynchronous operation being monitored, and an
0e2628
@@ -251,6 +278,9 @@ 
0e2628
 VmBackupSyncProvider *
0e2628
 VmBackup_NewVssProvider(void);
0e2628
 
0e2628
+VmBackupSyncCompleter *
0e2628
+VmBackup_NewVssCompleter(VmBackupSyncProvider *provider);
0e2628
+
0e2628
 void
0e2628
 VmBackup_UnregisterSnapshotProvider(void);
0e2628
 #endif