Exemple #1
0
Bool
DnD_DeleteStagingFiles(const char *stagingDir,  // IN:
                       Bool onReboot)           // IN:
{
   Bool ret = TRUE;

   ASSERT(stagingDir);

   if (!File_Exists(stagingDir)) {
      /* The stagingDir is already gone. */
      return TRUE;
   }

   if (!File_IsDirectory(stagingDir)) {
      return FALSE;
   }

   if (onReboot) {
      if (File_UnlinkDelayed(stagingDir)) {
         ret = FALSE;
      }
   } else {
      int i;
      int numFiles;
      char *base;
      char **fileList = NULL;

      /* get list of files in current directory */
      numFiles = File_ListDirectory(stagingDir, &fileList);

      if (numFiles == -1) {
         return FALSE;
      }

      /* delete everything in the directory */
      base = Unicode_Append(stagingDir, DIRSEPS);

      for (i = 0; i < numFiles; i++) {
         char *curPath;

         curPath = Unicode_Append(base, fileList[i]);

         if (File_IsDirectory(curPath)) {
            if (!File_DeleteDirectoryTree(curPath)) {
               ret = FALSE;
            }
         } else {
            if (File_Unlink(curPath) == -1) {
               ret = FALSE;
            }
         }

         free(curPath);
      }

      free(base);
   }

   return ret;
}
Exemple #2
0
static const char *
CreateRealRootDirectory(void)
{
   const char *realRoot = DetermineRealRootDirectory();

   if (   realRoot != NULL
       && (   File_IsDirectory(realRoot)
           || File_CreateDirectoryHierarchyEx(realRoot, 0700, NULL))) {
      return realRoot;
   }

   return NULL;
}
static char *
FileFindExistingSafeTmpDir(uid_t userId,            // IN:
                           const char *userName,    // IN:
                           const char *baseTmpDir)  // IN:
{
   int i;
   int numFiles;
   char *pattern;
   char *tmpDir = NULL;
   char **fileList = NULL;

   /*
    * We always use the pattern PRODUCT-USER-xxxx when creating
    * alternative safe temp directories, so check for ones with
    * those names and the appropriate permissions.
    */

   pattern = Unicode_Format("%s-%s-", PRODUCT_GENERIC_NAME_LOWER, userName);
   if (pattern == NULL) {
      return NULL;
   }

   numFiles = File_ListDirectory(baseTmpDir, &fileList);

   if (numFiles == -1) {
      free(pattern);

      return NULL;
   }

   for (i = 0; i < numFiles; i++) {
       if (Unicode_StartsWith(fileList[i], pattern)) {
          char *path = Unicode_Join(baseTmpDir, DIRSEPS, fileList[i], NULL);

          if (File_IsDirectory(path) &&
              FileAcceptableSafeTmpDir(path, userId)) {
             tmpDir = path;
             break;
          }

          free(path);
       }
   }

   Util_FreeStringList(fileList, numFiles);
   free(pattern);

   return tmpDir;
}
/**
 *
 * Core function which takes care of deployment in Linux.
 * Essentially it does
 * - uncabing of the cabinet
 * - execution of the command embedded in the cabinet header
 *
 * @param   [IN[  packageName  Package file to be used for deployment
 * @returns DEPLOYPKG_STATUS_SUCCESS on success
 *          DEPLOYPKG_STATUS_CLOUD_INIT_DELEGATED if customization task is
 *          delegated to cloud-init.
 *          DEPLOYPKG_STATUS_ERROR on error
 *
 **/
static DeployPkgStatus
Deploy(const char* packageName)
{
   DeployPkgStatus deployPkgStatus = DEPLOYPKG_STATUS_SUCCESS;
   char* pkgCommand = NULL;
   char* command = NULL;
   int deploymentResult = 0;
   char *nics;
   char* cleanupCommand;
   uint8 archiveType;
   uint8 flags;
   bool forceSkipReboot = false;
   const char *baseDirPath = NULL;
   char *imcDirPath = NULL;
   bool useCloudInitWorkflow = false;

   TransitionState(NULL, INPROGRESS);

   // Notify the vpx of customization in-progress state
   SetCustomizationStatusInVmx(TOOLSDEPLOYPKG_RUNNING,
                               TOOLSDEPLOYPKG_ERROR_SUCCESS,
                               NULL);

   // PR 2127543, Use /var/run or /run but /tmp firstly
   if (File_IsDirectory(VARRUNDIR)) {
      baseDirPath = VARRUNDIR;
   } else if (File_IsDirectory(RUNDIR)) {
      baseDirPath = RUNDIR;
   } else {
      baseDirPath = TMPDIR;
   }

   // Create a random name dir under base dir path
   imcDirPath = malloc(strlen(baseDirPath) + strlen(IMC_DIR_PATH_PATTERN) + 1);
   if (imcDirPath == NULL) {
      SetDeployError("Error allocating memory to create imc dir.");
      return DEPLOYPKG_STATUS_ERROR;
   }
   strcpy(imcDirPath, baseDirPath);
   strcat(imcDirPath, IMC_DIR_PATH_PATTERN);
   if (mkdtemp(imcDirPath) == NULL) {
      free(imcDirPath);
      SetDeployError("Error creating imc dir: %s", strerror(errno));
      return DEPLOYPKG_STATUS_ERROR;
   }

   sLog(log_info,
        "Reading cabinet file %s and will extract it to %s. \n",
         packageName,
         imcDirPath);

   // Get the command to execute
   if (!GetPackageInfo(packageName, &pkgCommand, &archiveType, &flags)) {
      SetDeployError("Error extracting package header information. (%s)",
                     GetDeployError());
      free(imcDirPath);
      return DEPLOYPKG_STATUS_CAB_ERROR;
   }

   sLog(log_info, "Flags in the header: %d\n", (int) flags);

   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, imcDirPath);
   } else {
      command = StrUtil_ReplaceAll(pkgCommand, TMP_PATH_VAR, imcDirPath);
   }
   free(pkgCommand);

   sLog(log_info, "Actual deployment command: %s\n", command);

   if (archiveType == VMWAREDEPLOYPKG_PAYLOAD_TYPE_CAB) {
      if (!ExtractCabPackage(packageName, imcDirPath)) {
         free(imcDirPath);
         free(command);
         return DEPLOYPKG_STATUS_CAB_ERROR;
      }
   } else if (archiveType == VMWAREDEPLOYPKG_PAYLOAD_TYPE_ZIP) {
      if (!ExtractZipPackage(packageName, imcDirPath)) {
         free(imcDirPath);
         free(command);
         return DEPLOYPKG_STATUS_CAB_ERROR;
      }
   }

   if (!(flags & VMWAREDEPLOYPKG_HEADER_FLAGS_IGNORE_CLOUD_INIT)) {
      useCloudInitWorkflow = UseCloudInitWorkflow(imcDirPath);
   } else {
      sLog(log_info, "Ignoring cloud-init.");
   }

   if (useCloudInitWorkflow) {
      sLog(log_info, "Executing cloud-init workflow");
      sSkipReboot = TRUE;
      free(command);
      deployPkgStatus = CloudInitSetup(imcDirPath);
   } else {
      sLog(log_info, "Executing traditional GOSC workflow");
      deploymentResult = ForkExecAndWaitCommand(command, false);
      free(command);

      if (deploymentResult != CUST_SUCCESS) {
         sLog(log_error, "Customization process returned with error. \n");
         sLog(log_debug, "Deployment result = %d \n", deploymentResult);

         if (deploymentResult == CUST_NETWORK_ERROR ||
             deploymentResult == CUST_NIC_ERROR ||
             deploymentResult == CUST_DNS_ERROR) {
            sLog(log_info, "Setting network error status in vmx. \n");
            SetCustomizationStatusInVmx(TOOLSDEPLOYPKG_RUNNING,
                                        GUESTCUST_EVENT_NETWORK_SETUP_FAILED,
                                        NULL);
         } else {
            sLog(log_info, "Setting %s error status in vmx. \n",
                 deploymentResult == CUST_GENERIC_ERROR ? "generic" : "unknown");
            SetCustomizationStatusInVmx(TOOLSDEPLOYPKG_RUNNING,
                                        GUESTCUST_EVENT_CUSTOMIZE_FAILED,
                                        NULL);
         }

         TransitionState(INPROGRESS, ERRORED);

         deployPkgStatus = DEPLOYPKG_STATUS_ERROR;
         SetDeployError("Deployment failed. "
                        "The forked off process returned error code.");
         sLog(log_error, "Deployment failed. "
                         "The forked off process returned error code. \n");
      } else {
         nics = GetNicsToEnable(imcDirPath);
         if (nics) {
            // XXX: Sleep before the last SetCustomizationStatusInVmx
            //      This is a temporary-hack for PR 422790
            sleep(5);
            sLog(log_info, "Wait before set enable-nics stats in vmx.\n");

            TryToEnableNics(nics);

            free(nics);
         } else {
            sLog(log_info, "No nics to enable.\n");
         }

         SetCustomizationStatusInVmx(TOOLSDEPLOYPKG_DONE,
                                     TOOLSDEPLOYPKG_ERROR_SUCCESS,
                                     NULL);

         TransitionState(INPROGRESS, DONE);

         deployPkgStatus = DEPLOYPKG_STATUS_SUCCESS;
         sLog(log_info, "Deployment succeeded. \n");
      }
   }

   cleanupCommand = malloc(strlen(CLEANUPCMD) + strlen(imcDirPath) + 1);
   if (!cleanupCommand) {
      SetDeployError("Error allocating memory.");
      free(imcDirPath);
      return DEPLOYPKG_STATUS_ERROR;
   }

   strcpy(cleanupCommand, CLEANUPCMD);
   strcat(cleanupCommand, imcDirPath);

   sLog(log_info, "Launching cleanup. \n");
   if (ForkExecAndWaitCommand(cleanupCommand, false) != 0) {
      sLog(log_warning, "Error while cleaning up imc directory %s: (%s)",
           imcDirPath, strerror (errno));
   }
   free (cleanupCommand);
   free(imcDirPath);

   if (flags & VMWAREDEPLOYPKG_HEADER_FLAGS_SKIP_REBOOT) {
      forceSkipReboot = true;
   }
   sLog(log_info,
        "sSkipReboot: %s, forceSkipReboot %s\n",
        sSkipReboot ? "true" : "false",
        forceSkipReboot ? "true" : "false");
   sSkipReboot |= forceSkipReboot;

   //Reset the guest OS
   if (!sSkipReboot && !deploymentResult) {
      pid_t pid = fork();
      if (pid == -1) {
         sLog(log_error, "Failed to fork: %s", strerror(errno));
      } else if (pid == 0) {
         // We're in the child

         // Repeatedly try to reboot to workaround PR 530641 where
         // telinit 6 is overwritten by a telinit 2
         int rebootComandResult = 0;
         do {
            sLog(log_info, "Rebooting\n");
            rebootComandResult = ForkExecAndWaitCommand("/sbin/telinit 6", false);
            sleep(1);
         } while (rebootComandResult == 0);
         sLog(log_error, "telinit returned error %d\n", rebootComandResult);

         exit (127);
      }
   }

   return deployPkgStatus;
}
VmBackupOp *
VmBackup_NewScriptOp(VmBackupScriptType type, // IN
                     VmBackupState *state)    // IN
{
   Bool fail = FALSE;
   char **fileList = NULL;
   char *scriptDir = NULL;
   int numFiles = 0;
   size_t i;
   VmBackupScriptOp *op = NULL;

   scriptDir = VmBackupGetScriptPath();
   if (scriptDir == NULL) {
      goto exit;
   }

   op = calloc(1, sizeof *op);
   if (op == NULL) {
      goto exit;
   }

   op->state = state;
   op->type = type;
   op->callbacks.queryFn = VmBackupScriptOpQuery;
   op->callbacks.cancelFn = VmBackupScriptOpCancel;
   op->callbacks.releaseFn = VmBackupScriptOpRelease;

   g_debug("Trying to run scripts from %s\n", scriptDir);

   /*
    * Load the list of scripts to run when freezing. The same list will be
    * used later in case of failure, or when thawing, in reverse order.
    *
    * This logic won't recurse into directories, so only files directly under
    * the script dir will be considered.
    *
    * Legacy scripts will be the first ones to run (or last ones in the
    * case of thawing). If either the legacy freeze or thaw script
    * exist, the first entry in the script list will be reserved for
    * them, and their path might not exist (in case, for example, the
    * freeze script exists but the thaw script doesn't).
    */
   if (type == VMBACKUP_SCRIPT_FREEZE) {
      VmBackupScript *scripts = NULL;
      int legacy = 0;
      size_t idx = 0;

      state->scripts = NULL;
      state->currentScript = 0;

      if (File_IsFile(LEGACY_FREEZE_SCRIPT) ||
          File_IsFile(LEGACY_THAW_SCRIPT)) {
         legacy = 1;
      }

      if (File_IsDirectory(scriptDir)) {
         numFiles = File_ListDirectory(scriptDir, &fileList);
      }

      if (numFiles + legacy > 0) {
         scripts = calloc(numFiles + legacy + 1, sizeof *scripts);
         if (scripts == NULL) {
            fail = TRUE;
            goto exit;
         }

         /*
          * VmBackupRunNextScript increments the index, so need to make it point
          * to "before the first script".
          */
         state->currentScript = -1;
         state->scripts = scripts;
      }

      if (legacy > 0) {
         scripts[idx++].path = Util_SafeStrdup(LEGACY_FREEZE_SCRIPT);
      }

      if (numFiles > 0) {
         size_t i;

         if (numFiles > 1) {
            qsort(fileList, (size_t) numFiles, sizeof *fileList, VmBackupStringCompare);
         }

         for (i = 0; i < numFiles; i++) {
            char *script;

            script = Str_Asprintf(NULL, "%s%c%s", scriptDir, DIRSEPC, fileList[i]);
            if (script == NULL) {
               fail = TRUE;
               goto exit;
            } else if (File_IsFile(script)) {
               scripts[idx++].path = script;
            } else {
               free(script);
            }
         }
      }
   } else if (state->scripts != NULL) {
      VmBackupScript *scripts = state->scripts;
      if (strcmp(scripts[0].path, LEGACY_FREEZE_SCRIPT) == 0) {
         vm_free(scripts[0].path);
         scripts[0].path = Util_SafeStrdup(LEGACY_THAW_SCRIPT);
      }
   }

   /*
    * If there are any scripts to be executed, start the first one. If we get to
    * this point, we won't free the scripts array until VmBackupScriptOpRelease
    * is called after thawing (or after the sync provider failed and the "fail"
    * scripts are run).
    */
   fail = (state->scripts != NULL && VmBackupRunNextScript(op) == -1);

exit:
   /* Free the file list. */
   for (i = 0; i < numFiles; i++) {
      free(fileList[i]);
   }
   free(fileList);

   if (fail && op != NULL) {
      VmBackup_Release((VmBackupOp *) op);
      op = NULL;
   }
   free(scriptDir);
   return (VmBackupOp *) op;
}