. 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>
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),
+
};
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:
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);
#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
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.
*
* 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,
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 */
#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
#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)
/* 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"
#include "vixOpenSource.h"
#include "vixTools.h"
+#include "vixToolsInt.h"
#ifdef _WIN32
#include "registryWin32.h"
size_t maxBufferSize,
char **result);
+static VixError VixToolsInitiateFileTransferToGuest(VixCommandRequestHeader *requestMsg);
+
static VixError VixToolsKillProcess(VixCommandRequestHeader *requestMsg);
static VixError VixToolsCreateDirectory(VixCommandRequestHeader *requestMsg);
} // 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
+
+
/*
*-----------------------------------------------------------------------------
*
*
* 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
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;
}
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();
*/
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,
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,
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.
break;
////////////////////////////////////
+ case VIX_COMMAND_INITIATE_FILE_TRANSFER_FROM_GUEST:
case VIX_COMMAND_LIST_FILES:
err = VixToolsListFiles(requestMsg,
maxResultBufferSize,
// resultValue is static. Do not free it.
break;
+ ////////////////////////////////////
+ case VIX_COMMAND_INITIATE_FILE_TRANSFER_TO_GUEST:
+ err = VixToolsInitiateFileTransferToGuest(requestMsg);
+ break;
+
////////////////////////////////////
default:
break;
void VixToolsLogoutUser(void *userToken);
-#ifdef _WIN32
-VixError VixToolsGetUserTmpDir(void *userToken,
- char **tmpDirPath);
-
-Bool VixToolsUserIsMemberOfAdministratorGroup(VixCommandRequestHeader *requestMsg);
-#endif // _WIN32
-
#endif /* __VIX_TOOLS_H__ */
--- /dev/null
+/*********************************************************
+ * 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__
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;
#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"
}
gBackupState->provider->release(gBackupState->provider);
+ g_free(gBackupState->scriptArg);
g_free(gBackupState->volumes);
g_free(gBackupState->snapshots);
g_free(gBackupState);
NOT_REACHED();
}
- if (!VmBackup_SetCurrentOp(gBackupState,
+ if (gBackupState->execScripts &&
+ !VmBackup_SetCurrentOp(gBackupState,
VmBackup_NewScriptOp(type, gBackupState),
NULL,
opName)) {
}
-/* 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);
{ 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;
+ }
}
}
}
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) {
* 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,
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
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 }
};
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;