4f1758d
diff --git a/libDeployPkg/linuxDeployment.c b/libDeployPkg/linuxDeployment.c
c16e623
index 996f184c..34c8b956 100644
4f1758d
--- a/libDeployPkg/linuxDeployment.c
4f1758d
+++ b/libDeployPkg/linuxDeployment.c
c16e623
@@ -139,7 +139,7 @@ static bool CopyFileToDirectory(const char* srcPath, const char* destPath,
0c5cdad
                                 const char* fileName);
c16e623
 static DeployPkgStatus Deploy(const char* pkgName);
0c5cdad
 static char** GetFormattedCommandLine(const char* command);
0c5cdad
-int ForkExecAndWaitCommand(const char* command);
0c5cdad
+int ForkExecAndWaitCommand(const char* command, bool ignoreStdErr);
0c5cdad
 static void SetDeployError(const char* format, ...);
0c5cdad
 static const char* GetDeployError(void);
0c5cdad
 static void NoLogging(int level, const char* fmtstr, ...);
0c5cdad
@@ -920,7 +920,7 @@ CloudInitSetup(const char *tmpDirPath)
0c5cdad
             "/bin/mkdir -p %s", cloudInitTmpDirPath);
0c5cdad
    command[sizeof(command) - 1] = '\0';
0c5cdad
 
0c5cdad
-   forkExecResult = ForkExecAndWaitCommand(command);
0c5cdad
+   forkExecResult = ForkExecAndWaitCommand(command, false);
0c5cdad
    if (forkExecResult != 0) {
0c5cdad
       SetDeployError("Error creating %s dir: %s",
0c5cdad
                      cloudInitTmpDirPath,
0c5cdad
@@ -937,7 +937,7 @@ CloudInitSetup(const char *tmpDirPath)
0c5cdad
             "/usr/bin/test -f %s/nics.txt", tmpDirPath);
0c5cdad
    command[sizeof(command) - 1] = '\0';
0c5cdad
 
0c5cdad
-   forkExecResult = ForkExecAndWaitCommand(command);
0c5cdad
+   forkExecResult = ForkExecAndWaitCommand(command, false);
0c5cdad
 
0c5cdad
    /*
0c5cdad
     * /usr/bin/test -f returns 0 if the file exists
0c5cdad
@@ -946,7 +946,7 @@ CloudInitSetup(const char *tmpDirPath)
0c5cdad
     */
0c5cdad
    if (forkExecResult == 0) {
0c5cdad
       sLog(log_info, "nics.txt file exists. Copying..");
0c5cdad
-      if(!CopyFileToDirectory(tmpDirPath, cloudInitTmpDirPath, "nics.txt")) {
0c5cdad
+      if (!CopyFileToDirectory(tmpDirPath, cloudInitTmpDirPath, "nics.txt")) {
0c5cdad
          goto done;
0c5cdad
        }
0c5cdad
    }
0c5cdad
@@ -973,7 +973,7 @@ CloudInitSetup(const char *tmpDirPath)
0c5cdad
    }
0c5cdad
 
0c5cdad
    sLog(log_info, "Copying main configuration file cust.cfg");
0c5cdad
-   if(!CopyFileToDirectory(tmpDirPath, cloudInitTmpDirPath, "cust.cfg")) {
0c5cdad
+   if (!CopyFileToDirectory(tmpDirPath, cloudInitTmpDirPath, "cust.cfg")) {
0c5cdad
       goto done;
0c5cdad
    }
0c5cdad
 
0c5cdad
@@ -992,7 +992,7 @@ CloudInitSetup(const char *tmpDirPath)
0c5cdad
                   "/bin/rm -rf %s",
0c5cdad
                   cloudInitTmpDirPath);
0c5cdad
          command[sizeof(command) - 1] = '\0';
0c5cdad
-         ForkExecAndWaitCommand(command);
0c5cdad
+         ForkExecAndWaitCommand(command, false);
0c5cdad
       }
0c5cdad
       sLog(log_error, "Setting generic error status in vmx. \n");
0c5cdad
       SetCustomizationStatusInVmx(TOOLSDEPLOYPKG_RUNNING,
0c5cdad
@@ -1016,7 +1016,7 @@ CopyFileToDirectory(const char* srcPath, const char* destPath,
0c5cdad
    snprintf(command, sizeof(command), "/bin/cp %s/%s %s/%s.tmp", srcPath,
0c5cdad
             fileName, destPath, fileName);
0c5cdad
    command[sizeof(command) - 1] = '\0';
0c5cdad
-   forkExecResult = ForkExecAndWaitCommand(command);
0c5cdad
+   forkExecResult = ForkExecAndWaitCommand(command, false);
0c5cdad
    if (forkExecResult != 0) {
0c5cdad
       SetDeployError("Error while copying file %s: %s", fileName,
0c5cdad
                      strerror(errno));
0c5cdad
@@ -1026,7 +1026,7 @@ CopyFileToDirectory(const char* srcPath, const char* destPath,
0c5cdad
             fileName, destPath, fileName);
0c5cdad
    command[sizeof(command) - 1] = '\0';
0c5cdad
 
0c5cdad
-   forkExecResult = ForkExecAndWaitCommand(command);
0c5cdad
+   forkExecResult = ForkExecAndWaitCommand(command, false);
0c5cdad
    if (forkExecResult != 0) {
0c5cdad
       SetDeployError("Error while renaming temp file %s: %s", fileName,
0c5cdad
                      strerror(errno));
0c5cdad
@@ -1090,7 +1090,7 @@ UseCloudInitWorkflow(const char* dirPath)
0c5cdad
       sLog(log_info, "cust.cfg is found in '%s' directory.", dirPath);
0c5cdad
    }
0c5cdad
 
0c5cdad
-   forkExecResult = ForkExecAndWaitCommand(cloudInitCommand);
0c5cdad
+   forkExecResult = ForkExecAndWaitCommand(cloudInitCommand, true);
0c5cdad
    if (forkExecResult != 0) {
0c5cdad
       sLog(log_info, "cloud-init is not installed");
0c5cdad
       free(cfgFullPath);
c16e623
@@ -1194,7 +1194,7 @@ Deploy(const char* packageName)
c16e623
       deployPkgStatus = CloudInitSetup(tmpDirPath);
0c5cdad
    } else {
0c5cdad
       sLog(log_info, "Executing traditional GOSC workflow");
0c5cdad
-      deploymentResult = ForkExecAndWaitCommand(command);
0c5cdad
+      deploymentResult = ForkExecAndWaitCommand(command, false);
0c5cdad
       free(command);
0c5cdad
 
0c5cdad
       if (deploymentResult != CUST_SUCCESS) {
c16e623
@@ -1260,7 +1260,7 @@ Deploy(const char* packageName)
0c5cdad
    strcat(cleanupCommand, tmpDirPath);
0c5cdad
 
0c5cdad
    sLog(log_info, "Launching cleanup. \n");
0c5cdad
-   if (ForkExecAndWaitCommand(cleanupCommand) != 0) {
0c5cdad
+   if (ForkExecAndWaitCommand(cleanupCommand, false) != 0) {
0c5cdad
       sLog(log_warning, "Error while clean up tmp directory %s: (%s)",
0c5cdad
            tmpDirPath, strerror (errno));
0c5cdad
    }
c16e623
@@ -1289,7 +1289,7 @@ Deploy(const char* packageName)
0c5cdad
          int rebootComandResult = 0;
0c5cdad
          do {
0c5cdad
             sLog(log_info, "Rebooting\n");
0c5cdad
-            rebootComandResult = ForkExecAndWaitCommand("/sbin/telinit 6");
0c5cdad
+            rebootComandResult = ForkExecAndWaitCommand("/sbin/telinit 6", false);
0c5cdad
             sleep(1);
0c5cdad
          } while (rebootComandResult == 0);
0c5cdad
          sLog(log_error, "telinit returned error %d\n", rebootComandResult);
c16e623
@@ -1499,12 +1499,13 @@ GetFormattedCommandLine(const char* command)
c16e623
  * Fork off the command and wait for it to finish. Classical Linux/Unix
0c5cdad
  * fork-and-exec.
0c5cdad
  *
c16e623
- * @param   [IN]  command  Command to execute
c16e623
+ * @param   [IN]  command       Command to execute
0c5cdad
+ * @param   [IN]  ignoreStdErr  If we ignore stderr when cmd's return code is 0
c16e623
  * @return  Return code from the process (or -1)
0c5cdad
  *
0c5cdad
  **/
0c5cdad
 int
0c5cdad
-ForkExecAndWaitCommand(const char* command)
0c5cdad
+ForkExecAndWaitCommand(const char* command, bool ignoreStdErr)
0c5cdad
 {
0c5cdad
    ProcessHandle hp;
0c5cdad
    int retval;
c16e623
@@ -1522,14 +1523,30 @@ ForkExecAndWaitCommand(const char* command)
0c5cdad
 
0c5cdad
    Process_RunToComplete(hp, 100);
0c5cdad
    sLog(log_info, "Customization command output: %s\n", Process_GetStdout(hp));
0c5cdad
-
0c5cdad
-   if(Process_GetExitCode(hp) == 0 && strlen(Process_GetStderr(hp)) > 0) {
0c5cdad
-      // Assume command failed if it wrote to stderr, even if exitCode is 0
0c5cdad
-      sLog(log_error, "Customization command failed: %s\n", Process_GetStderr(hp));
0c5cdad
-      retval = -1;
0c5cdad
+   retval = Process_GetExitCode(hp);
0c5cdad
+
0c5cdad
+   if (retval == 0) {
0c5cdad
+      if (strlen(Process_GetStderr(hp)) > 0) {
0c5cdad
+         if (!ignoreStdErr) {
0c5cdad
+            // Assume command failed if it wrote to stderr, even if exitCode is 0
0c5cdad
+            sLog(log_error,
0c5cdad
+                 "Customization command failed with stderr: %s\n",
0c5cdad
+                 Process_GetStderr(hp));
0c5cdad
+            retval = -1;
0c5cdad
+         } else {
0c5cdad
+            // If we choose to ignore stderr, we do not return -1 when return
0c5cdad
+            // code is 0. e.g, PR2148977, "cloud-init -v" will return 0
0c5cdad
+            // even there is output in stderr
0c5cdad
+            sLog(log_info, "Ignoring stderr output: %s\n", Process_GetStderr(hp));
0c5cdad
+         }
0c5cdad
+      }
0c5cdad
    } else {
0c5cdad
-      retval = Process_GetExitCode(hp);
0c5cdad
+      sLog(log_error,
0c5cdad
+           "Customization command failed with exitcode: %d, stderr: %s\n",
0c5cdad
+           retval,
0c5cdad
+           Process_GetStderr(hp));
0c5cdad
    }
0c5cdad
+
0c5cdad
    Process_Destroy(hp);
0c5cdad
    return retval;
0c5cdad
 }
4f1758d
diff --git a/libDeployPkg/linuxDeploymentUtilities.c b/libDeployPkg/linuxDeploymentUtilities.c
0c5cdad
index 83f942da..93e1b0aa 100644
4f1758d
--- a/libDeployPkg/linuxDeploymentUtilities.c
4f1758d
    +++ b/libDeployPkg/linuxDeploymentUtilities.c
0c5cdad
@@ -1,5 +1,5 @@
0c5cdad
 /*********************************************************
0c5cdad
- * Copyright (C) 2016-2017 VMware, Inc. All rights reserved.
0c5cdad
+ * Copyright (C) 2016-2018 VMware, Inc. All rights reserved.
0c5cdad
  *
0c5cdad
  * This program is free software; you can redistribute it and/or modify it
0c5cdad
  * under the terms of the GNU Lesser General Public License as published
0c5cdad
@@ -24,7 +24,6 @@
0c5cdad
 #include <regex.h>
0c5cdad
 #include "linuxDeploymentUtilities.h"
0c5cdad
 
0c5cdad
-extern int ForkExecAndWaitCommand(const char* command);
0c5cdad
 extern LogFunction sLog;
0c5cdad
 
0c5cdad
 /**