421 lines
14 KiB
Diff
421 lines
14 KiB
Diff
|
From 180dcbd06dd3990a8de3f881ad29cdb29d9ed4a4 Mon Sep 17 00:00:00 2001
|
||
|
From: Oliver Kurth <okurth@vmware.com>
|
||
|
Date: Thu, 6 Jul 2017 17:00:55 -0700
|
||
|
Subject: [PATCH] randomly generate tmp directory name
|
||
|
|
||
|
(cherry picked from commit 22e58289f71232310d30cf162b83b5151a937bac)
|
||
|
---
|
||
|
open-vm-tools/libDeployPkg/linuxDeployment.c | 232 +++++++++++++--------------
|
||
|
1 file changed, 114 insertions(+), 118 deletions(-)
|
||
|
|
||
|
diff --git a/open-vm-tools/libDeployPkg/linuxDeployment.c b/open-vm-tools/libDeployPkg/linuxDeployment.c
|
||
|
index 1c8f7855..8e536a97 100644
|
||
|
--- a/open-vm-tools/libDeployPkg/linuxDeployment.c
|
||
|
+++ b/open-vm-tools/libDeployPkg/linuxDeployment.c
|
||
|
@@ -43,6 +43,8 @@
|
||
|
#include "mspackWrapper.h"
|
||
|
#include "rpcout.h"
|
||
|
#include "toolsDeployPkg.h"
|
||
|
+#include <strutil.h>
|
||
|
+#include <util.h>
|
||
|
|
||
|
/*
|
||
|
* These are covered by #ifndef to give the ability to change these
|
||
|
@@ -52,12 +54,17 @@
|
||
|
|
||
|
#define CLEANUPCMD "/bin/rm -r -f "
|
||
|
|
||
|
-#ifndef EXTRACTPATH
|
||
|
-#define EXTRACTPATH "/tmp/.vmware/linux/deploy"
|
||
|
+#ifndef TMP_PATH_VAR
|
||
|
+#define TMP_PATH_VAR "/tmp/.vmware/linux/deploy"
|
||
|
#endif
|
||
|
|
||
|
-#ifndef CLEANUPPATH
|
||
|
-#define CLEANUPPATH "/tmp/.vmware"
|
||
|
+#ifndef IMC_TMP_PATH_VAR
|
||
|
+#define IMC_TMP_PATH_VAR "@@IMC_TMP_PATH_VAR@@"
|
||
|
+#endif
|
||
|
+
|
||
|
+// '/tmp' below will be addressed by PR 1601405.
|
||
|
+#ifndef TMP_DIR_PATH_PATTERN
|
||
|
+#define TMP_DIR_PATH_PATTERN "/tmp/.vmware-imgcust-dXXXXXX"
|
||
|
#endif
|
||
|
|
||
|
#ifndef BASEFILENAME
|
||
|
@@ -115,13 +122,14 @@ struct List {
|
||
|
// Private functions
|
||
|
static Bool GetPackageInfo(const char* pkgName, char** cmd, uint8* type, uint8* flags);
|
||
|
static Bool ExtractZipPackage(const char* pkg, const char* dest);
|
||
|
-static Bool CreateDir(const char *path);
|
||
|
static void Init(void);
|
||
|
static struct List* AddToList(struct List* head, const char* token);
|
||
|
static int ListSize(struct List* head);
|
||
|
static int Touch(const char* state);
|
||
|
static int UnTouch(const char* state);
|
||
|
static int TransitionState(const char* stateFrom, const char* stateTo);
|
||
|
+static bool CopyFileToDirectory(const char* srcPath, const char* destPath,
|
||
|
+ const char* fileName);
|
||
|
static int Deploy(const char* pkgName);
|
||
|
static char** GetFormattedCommandLine(const char* command);
|
||
|
static int ForkExecAndWaitCommand(const char* command);
|
||
|
@@ -151,8 +159,17 @@ static LogFunction sLog = NoLogging;
|
||
|
NORETURN void
|
||
|
Panic(const char *fmtstr, ...)
|
||
|
{
|
||
|
- /* Ignored */
|
||
|
- sLog(log_warning, "Panic callback invoked. \n");
|
||
|
+ va_list args;
|
||
|
+
|
||
|
+ char *tmp = Util_SafeMalloc(MAXSTRING);
|
||
|
+
|
||
|
+ va_start(args, fmtstr);
|
||
|
+ vsprintf(tmp, fmtstr, args);
|
||
|
+
|
||
|
+ sLog(log_error, "Panic callback invoked: %s\n", tmp);
|
||
|
+
|
||
|
+ free(tmp);
|
||
|
+
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
@@ -169,12 +186,19 @@ Panic(const char *fmtstr, ...)
|
||
|
*
|
||
|
**/
|
||
|
void
|
||
|
-Debug(const char *fmtstr,
|
||
|
- va_list args)
|
||
|
+Debug(const char *fmtstr, ...)
|
||
|
{
|
||
|
- /* Ignored */
|
||
|
#ifdef VMX86_DEBUG
|
||
|
- sLog(log_warning, "Debug callback invoked. \n");
|
||
|
+ va_list args;
|
||
|
+
|
||
|
+ char *tmp = Util_SafeMalloc(MAXSTRING);
|
||
|
+
|
||
|
+ va_start(args, fmtstr);
|
||
|
+ vsprintf(tmp, fmtstr, args);
|
||
|
+
|
||
|
+ sLog(log_debug, "Debug callback invoked: %s\n", tmp);
|
||
|
+
|
||
|
+ free(tmp);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
@@ -874,11 +898,13 @@ static int
|
||
|
CloudInitSetup(const char *tmpDirPath)
|
||
|
{
|
||
|
int deployStatus = DEPLOY_ERROR;
|
||
|
- const char *cloudInitTmpDirPath = "/var/run/vmware-imc";
|
||
|
+ static const char *cloudInitTmpDirPath = "/var/run/vmware-imc";
|
||
|
int forkExecResult;
|
||
|
char command[1024];
|
||
|
Bool cloudInitTmpDirCreated = FALSE;
|
||
|
|
||
|
+ sLog(log_info, "Creating temp directory %s to copy customization files",
|
||
|
+ cloudInitTmpDirPath);
|
||
|
snprintf(command, sizeof(command),
|
||
|
"/bin/mkdir -p %s", cloudInitTmpDirPath);
|
||
|
command[sizeof(command) - 1] = '\0';
|
||
|
@@ -893,26 +919,9 @@ CloudInitSetup(const char *tmpDirPath)
|
||
|
|
||
|
cloudInitTmpDirCreated = TRUE;
|
||
|
|
||
|
- snprintf(command, sizeof(command),
|
||
|
- "/bin/rm -f %s/cust.cfg %s/nics.txt",
|
||
|
- cloudInitTmpDirPath, cloudInitTmpDirPath);
|
||
|
- command[sizeof(command) - 1] = '\0';
|
||
|
-
|
||
|
- forkExecResult = ForkExecAndWaitCommand(command);
|
||
|
-
|
||
|
- snprintf(command, sizeof(command),
|
||
|
- "/bin/cp %s/cust.cfg %s/cust.cfg",
|
||
|
- tmpDirPath, cloudInitTmpDirPath);
|
||
|
- command[sizeof(command) - 1] = '\0';
|
||
|
-
|
||
|
- forkExecResult = ForkExecAndWaitCommand(command);
|
||
|
-
|
||
|
- if (forkExecResult != 0) {
|
||
|
- SetDeployError("Error copying cust.cfg file: %s",
|
||
|
- strerror(errno));
|
||
|
- goto done;
|
||
|
- }
|
||
|
-
|
||
|
+ // Copy required files for cloud-init to a temp name initially and then
|
||
|
+ // rename in order to avoid race conditions with partial writes.
|
||
|
+ sLog(log_info, "Check if nics.txt exists. Copy if exists, skip otherwise");
|
||
|
snprintf(command, sizeof(command),
|
||
|
"/usr/bin/test -f %s/nics.txt", tmpDirPath);
|
||
|
command[sizeof(command) - 1] = '\0';
|
||
|
@@ -925,26 +934,27 @@ CloudInitSetup(const char *tmpDirPath)
|
||
|
* We need to copy the nics.txt only if it exists.
|
||
|
*/
|
||
|
if (forkExecResult == 0) {
|
||
|
- snprintf(command, sizeof(command),
|
||
|
- "/bin/cp %s/nics.txt %s/nics.txt",
|
||
|
- tmpDirPath, cloudInitTmpDirPath);
|
||
|
- command[sizeof(command) - 1] = '\0';
|
||
|
-
|
||
|
- forkExecResult = ForkExecAndWaitCommand(command);
|
||
|
- if (forkExecResult != 0) {
|
||
|
- SetDeployError("Error copying nics.txt file: %s",
|
||
|
- strerror(errno));
|
||
|
+ sLog(log_info, "nics.txt file exists. Copying..");
|
||
|
+ if(!CopyFileToDirectory(tmpDirPath, cloudInitTmpDirPath, "nics.txt")) {
|
||
|
goto done;
|
||
|
- }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ sLog(log_info, "Copying main configuration file cust.cfg");
|
||
|
+ if(!CopyFileToDirectory(tmpDirPath, cloudInitTmpDirPath, "cust.cfg")) {
|
||
|
+ goto done;
|
||
|
}
|
||
|
|
||
|
deployStatus = DEPLOY_SUCCESS;
|
||
|
|
||
|
done:
|
||
|
if (DEPLOY_SUCCESS == deployStatus) {
|
||
|
+ sLog(log_info, "Deployment for cloud-init succeeded.");
|
||
|
TransitionState(INPROGRESS, DONE);
|
||
|
} else {
|
||
|
+ sLog(log_error, "Deployment for cloud-init failed.");
|
||
|
if (cloudInitTmpDirCreated) {
|
||
|
+ sLog(log_info, "Removing temporary folder %s", cloudInitTmpDirPath);
|
||
|
snprintf(command, sizeof(command),
|
||
|
"/bin/rm -rf %s",
|
||
|
cloudInitTmpDirPath);
|
||
|
@@ -964,6 +974,34 @@ done:
|
||
|
|
||
|
//......................................................................................
|
||
|
|
||
|
+static bool
|
||
|
+CopyFileToDirectory(const char* srcPath, const char* destPath,
|
||
|
+ const char* fileName)
|
||
|
+{
|
||
|
+ char command[1024];
|
||
|
+ int forkExecResult;
|
||
|
+ snprintf(command, sizeof(command), "/bin/cp %s/%s %s/%s.tmp", srcPath,
|
||
|
+ fileName, destPath, fileName);
|
||
|
+ command[sizeof(command) - 1] = '\0';
|
||
|
+ forkExecResult = ForkExecAndWaitCommand(command);
|
||
|
+ if (forkExecResult != 0) {
|
||
|
+ SetDeployError("Error while copying file %s: %s", fileName,
|
||
|
+ strerror(errno));
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+ snprintf(command, sizeof(command), "/bin/mv -f %s/%s.tmp %s/%s", destPath,
|
||
|
+ fileName, destPath, fileName);
|
||
|
+ command[sizeof(command) - 1] = '\0';
|
||
|
+
|
||
|
+ forkExecResult = ForkExecAndWaitCommand(command);
|
||
|
+ if (forkExecResult != 0) {
|
||
|
+ SetDeployError("Error while renaming temp file %s: %s", fileName,
|
||
|
+ strerror(errno));
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
/**
|
||
|
*
|
||
|
* Core function which takes care of deployment in Linux.
|
||
|
@@ -979,6 +1017,7 @@ static int
|
||
|
Deploy(const char* packageName)
|
||
|
{
|
||
|
int deployStatus = DEPLOY_SUCCESS;
|
||
|
+ char* pkgCommand = NULL;
|
||
|
char* command = NULL;
|
||
|
int deploymentResult = 0;
|
||
|
char *nics;
|
||
|
@@ -986,6 +1025,7 @@ Deploy(const char* packageName)
|
||
|
uint8 archiveType;
|
||
|
uint8 flags;
|
||
|
bool forceSkipReboot = false;
|
||
|
+ char *tmpDirPath;
|
||
|
Bool cloudInitEnabled = FALSE;
|
||
|
const char *cloudInitConfigFilePath = "/etc/cloud/cloud.cfg";
|
||
|
char cloudCommand[1024];
|
||
|
@@ -998,52 +1038,62 @@ Deploy(const char* packageName)
|
||
|
TOOLSDEPLOYPKG_ERROR_SUCCESS,
|
||
|
NULL);
|
||
|
|
||
|
+ tmpDirPath = mkdtemp((char *)Util_SafeStrdup(TMP_DIR_PATH_PATTERN));
|
||
|
+ if (tmpDirPath == NULL) {
|
||
|
+ SetDeployError("Error creating tmp dir: %s", strerror(errno));
|
||
|
+ return DEPLOY_ERROR;
|
||
|
+ }
|
||
|
+
|
||
|
sLog(log_info, "Reading cabinet file %s. \n", packageName);
|
||
|
|
||
|
// Get the command to execute
|
||
|
- if (!GetPackageInfo(packageName, &command, &archiveType, &flags)) {
|
||
|
+ if (!GetPackageInfo(packageName, &pkgCommand, &archiveType, &flags)) {
|
||
|
SetDeployError("Error extracting package header information. (%s)",
|
||
|
GetDeployError());
|
||
|
+ free(tmpDirPath);
|
||
|
return DEPLOY_ERROR;
|
||
|
}
|
||
|
|
||
|
- // Print the header command
|
||
|
-#ifdef VMX86_DEBUG
|
||
|
- sLog(log_debug, "Header command: %s \n ", command);
|
||
|
-#endif
|
||
|
-
|
||
|
- // create the destination directory
|
||
|
- if (!CreateDir(EXTRACTPATH "/")) {
|
||
|
- free(command);
|
||
|
- return DEPLOY_ERROR;
|
||
|
+ sLog(log_info, "Original deployment command: %s\n", pkgCommand);
|
||
|
+ if (strstr(pkgCommand, IMC_TMP_PATH_VAR) != NULL) {
|
||
|
+ command = StrUtil_ReplaceAll(pkgCommand, IMC_TMP_PATH_VAR, tmpDirPath);
|
||
|
+ } else {
|
||
|
+ command = StrUtil_ReplaceAll(pkgCommand, TMP_PATH_VAR, tmpDirPath);
|
||
|
}
|
||
|
+ free(pkgCommand);
|
||
|
+
|
||
|
+ sLog(log_info, "Actual deployment command: %s\n", command);
|
||
|
|
||
|
if (archiveType == VMWAREDEPLOYPKG_PAYLOAD_TYPE_CAB) {
|
||
|
- if (!ExtractCabPackage(packageName, EXTRACTPATH)) {
|
||
|
+ if (!ExtractCabPackage(packageName, tmpDirPath)) {
|
||
|
+ free(tmpDirPath);
|
||
|
free(command);
|
||
|
return DEPLOY_ERROR;
|
||
|
}
|
||
|
} else if (archiveType == VMWAREDEPLOYPKG_PAYLOAD_TYPE_ZIP) {
|
||
|
- if (!ExtractZipPackage(packageName, EXTRACTPATH)) {
|
||
|
+ if (!ExtractZipPackage(packageName, tmpDirPath)) {
|
||
|
+ free(tmpDirPath);
|
||
|
free(command);
|
||
|
return DEPLOY_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check if cloud-init installed
|
||
|
+ sLog(log_info, "Checking if cloud-init is installed");
|
||
|
snprintf(cloudCommand, sizeof(cloudCommand),
|
||
|
"/usr/bin/cloud-init -h");
|
||
|
cloudCommand[sizeof(cloudCommand) - 1] = '\0';
|
||
|
forkExecResult = ForkExecAndWaitCommand(cloudCommand);
|
||
|
// if cloud-init is installed, check if it is enabled
|
||
|
if (forkExecResult == 0 && IsCloudInitEnabled(cloudInitConfigFilePath)) {
|
||
|
+ sLog(log_info, "cloud-init is installed and enabled");
|
||
|
cloudInitEnabled = TRUE;
|
||
|
sSkipReboot = TRUE;
|
||
|
free(command);
|
||
|
- deployStatus = CloudInitSetup(EXTRACTPATH);
|
||
|
+ deployStatus = CloudInitSetup(tmpDirPath);
|
||
|
} else {
|
||
|
- // Run the deployment command
|
||
|
- sLog(log_info, "Launching deployment %s. \n", command);
|
||
|
+ sLog(log_info, "cloud-init is either not installed or the flag to enable \
|
||
|
+ cloud-init is not set.\n Executing traditional GOSC workflow");
|
||
|
deploymentResult = ForkExecAndWaitCommand(command);
|
||
|
free(command);
|
||
|
|
||
|
@@ -1089,7 +1139,7 @@ Deploy(const char* packageName)
|
||
|
* of the sucess/failure of the customization so that at the end of it we
|
||
|
* always have nics enabled.
|
||
|
*/
|
||
|
- nics = GetNicsToEnable(EXTRACTPATH);
|
||
|
+ nics = GetNicsToEnable(tmpDirPath);
|
||
|
if (nics) {
|
||
|
// XXX: Sleep before the last SetCustomizationStatusInVmx
|
||
|
// This is a temporary-hack for PR 422790
|
||
|
@@ -1104,22 +1154,23 @@ Deploy(const char* packageName)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- cleanupCommand = malloc(strlen(CLEANUPCMD) + strlen(CLEANUPPATH) + 1);
|
||
|
+ cleanupCommand = malloc(strlen(CLEANUPCMD) + strlen(tmpDirPath) + 1);
|
||
|
if (!cleanupCommand) {
|
||
|
SetDeployError("Error allocating memory.");
|
||
|
+ free(tmpDirPath);
|
||
|
return DEPLOY_ERROR;
|
||
|
}
|
||
|
|
||
|
strcpy(cleanupCommand, CLEANUPCMD);
|
||
|
- strcat(cleanupCommand, CLEANUPPATH);
|
||
|
+ strcat(cleanupCommand, tmpDirPath);
|
||
|
|
||
|
sLog(log_info, "Launching cleanup. \n");
|
||
|
if (ForkExecAndWaitCommand(cleanupCommand) != 0) {
|
||
|
- sLog(log_warning, "Error while clean up. Error removing directory %s. (%s)",
|
||
|
- EXTRACTPATH, strerror (errno));
|
||
|
- //TODO: What should be done if cleanup fails ??
|
||
|
+ sLog(log_warning, "Error while clean up tmp directory %s: (%s)",
|
||
|
+ tmpDirPath, strerror (errno));
|
||
|
}
|
||
|
free (cleanupCommand);
|
||
|
+ free(tmpDirPath);
|
||
|
|
||
|
if (flags & VMWAREDEPLOYPKG_HEADER_FLAGS_SKIP_REBOOT) {
|
||
|
forceSkipReboot = true;
|
||
|
@@ -1388,61 +1439,6 @@ ForkExecAndWaitCommand(const char* command)
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
-/**
|
||
|
- * Sets up the path for exracting file. For e.g. if the file is /a/b/c/d.abc
|
||
|
- * then it creates /a/b/c (skips if any of the directories along the path
|
||
|
- * exists). If the the path ends in '/', then the the entire input is assumed
|
||
|
- * to be a directory and is created as such.
|
||
|
- *
|
||
|
- * @param path IN: Complete path of the file
|
||
|
- * @return TRUE on success
|
||
|
- */
|
||
|
-
|
||
|
-Bool
|
||
|
-CreateDir(const char* path)
|
||
|
-{
|
||
|
- struct stat stats;
|
||
|
- char* token;
|
||
|
- char* copy;
|
||
|
-
|
||
|
- // make a copy we can modify
|
||
|
- copy = strdup(path);
|
||
|
-
|
||
|
- // walk through the path (it employs in string replacement)
|
||
|
- for (token = copy + 1; *token; ++token) {
|
||
|
-
|
||
|
- // find
|
||
|
- if (*token != '/') {
|
||
|
- continue;
|
||
|
- }
|
||
|
-
|
||
|
- /*
|
||
|
- * cut it off here for e.g. on first iteration /a/b/c/d.abc will have
|
||
|
- * token /a, on second /a/b etc
|
||
|
- */
|
||
|
- *token = 0;
|
||
|
-
|
||
|
- sLog(log_debug, "Creating directory %s", copy);
|
||
|
-
|
||
|
- // ignore if the directory exists
|
||
|
- if (!((stat(copy, &stats) == 0) && S_ISDIR(stats.st_mode))) {
|
||
|
- // make directory and check error (accessible only by owner)
|
||
|
- if (mkdir(copy, 0700) == -1) {
|
||
|
- sLog(log_error, "Unable to create directory %s (%s)", copy,
|
||
|
- strerror(errno));
|
||
|
- free(copy);
|
||
|
- return FALSE;
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- // restore the token
|
||
|
- *token = '/';
|
||
|
- }
|
||
|
-
|
||
|
- free(copy);
|
||
|
- return TRUE;
|
||
|
-}
|
||
|
-
|
||
|
//......................................................................................
|
||
|
|
||
|
/**
|
||
|
--
|
||
|
2.13.2
|
||
|
|