MXUserExclLock * MXUser_CreateExclLock(const char *userName, // IN: MX_Rank rank) // IN: { Bool doStats; char *properName; MXUserExclLock *lock; lock = Util_SafeCalloc(1, sizeof(*lock)); if (userName == NULL) { properName = Str_SafeAsprintf(NULL, "X-%p", GetReturnAddress()); } else { properName = Util_SafeStrdup(userName); } if (!MXRecLockInit(&lock->recursiveLock)) { free(properName); free(lock); return NULL; } lock->header.signature = MXUserGetSignature(MXUSER_TYPE_EXCL); lock->header.name = properName; lock->header.rank = rank; lock->header.serialNumber = MXUserAllocSerialNumber(); lock->header.dumpFunc = MXUserDumpExclLock; if (vmx86_stats) { doStats = MXUserStatsEnabled(); } else { doStats = FALSE; } if (doStats) { MXUser_ControlExclLock(lock, MXUSER_CONTROL_ENABLE_STATS); } else { lock->header.statsFunc = NULL; Atomic_WritePtr(&lock->statsMem, NULL); } MXUserAddToList(&lock->header); return lock; }
MXUserSemaphore * MXUser_CreateSemaphore(const char *userName, // IN: MX_Rank rank) // IN: { char *properName; MXUserSemaphore *sema; sema = Util_SafeCalloc(1, sizeof(*sema)); if (userName == NULL) { properName = Str_SafeAsprintf(NULL, "Sema-%p", GetReturnAddress()); } else { properName = Util_SafeStrdup(userName); } if (LIKELY(MXUserInit(&sema->nativeSemaphore) == 0)) { sema->header.signature = MXUserGetSignature(MXUSER_TYPE_SEMA); sema->header.name = properName; sema->header.rank = rank; sema->header.serialNumber = MXUserAllocSerialNumber(); sema->header.dumpFunc = MXUserDumpSemaphore; if (MXUserStatsMode() == 0) { sema->header.statsFunc = NULL; Atomic_WritePtr(&sema->acquireStatsMem, NULL); } else { MXUserAcquireStats *acquireStats; acquireStats = Util_SafeCalloc(1, sizeof(*acquireStats)); MXUserAcquisitionStatsSetUp(&acquireStats->data); sema->header.statsFunc = MXUserStatsActionSema; Atomic_WritePtr(&sema->acquireStatsMem, acquireStats); } MXUserAddToList(&sema->header); } else { free(properName); free(sema); sema = NULL; } return sema; }
static char * ToolsDaemonTcloGetQuotedString(const char *args, // IN const char **endOfArg) // OUT { char *resultStr = NULL; char *endStr; Debug(">ToolsDaemonTcloGetQuotedString\n"); while ((*args) && ('\"' != *args)) { args++; } if ('\"' == *args) { args++; } resultStr = Util_SafeStrdup(args); endStr = resultStr; while (*endStr) { if (('\\' == *endStr) && (*(endStr + 1))) { endStr += 2; } else if ('\"' == *endStr) { *endStr = 0; endStr++; break; } else { endStr++; } } if (NULL != endOfArg) { args += (endStr - resultStr); while (' ' == *args) { args++; } *endOfArg = args; } Debug("<ToolsDaemonTcloGetQuotedString\n"); return resultStr; } // ToolsDaemonTcloGetQuotedString
Bool SyncDriver_Freeze(const char *userPaths, // IN SyncDriverHandle *handle) // OUT { char *paths = NULL; SyncDriverErr err = SD_UNAVAILABLE; size_t i = 0; /* * First, convert the given path list to something the backends will * understand: a colon-separated list of paths. */ if (userPaths == NULL || Str_Strncmp(userPaths, "all", sizeof "all") == 0) { paths = SyncDriverListMounts(); if (paths == NULL) { Debug(LGPFX "Failed to list mount points.\n"); return SD_ERROR; } } else { /* * The sync driver API specifies spaces as separators, but the driver * uses colons as the path separator on Unix. */ char *c; paths = Util_SafeStrdup(userPaths); for (c = paths; *c != '\0'; c++) { if (*c == ' ') { *c = ':'; } } } while (err == SD_UNAVAILABLE && i < ARRAYSIZE(gBackends)) { err = gBackends[i++](paths, handle); } free(paths); return err == SD_SUCCESS; }
Unicode Unicode_Duplicate(ConstUnicode str) // IN { return (Unicode)Util_SafeStrdup((const char *)str); }
static int DnD_TryInitVmblock(const char *vmbFsName, // IN const char *vmbMntPoint, // IN const char *vmbDevice, // IN mode_t vmbDeviceMode, // IN Bool (*verifyBlock)(int fd)) // IN { #if defined NO_SETMNTENT || defined NO_ENDMNTENT NOT_IMPLEMENTED(); errno = ENOSYS; return -1; #else Bool found = FALSE; int blockFd = -1; char *realMntPoint; MNTHANDLE fp; DECLARE_MNTINFO(mnt); ASSERT(vmbFsName); ASSERT(vmbMntPoint); ASSERT(vmbDevice); /* Resolve desired mount point in case it is symlinked somewhere */ realMntPoint = Posix_RealPath(vmbMntPoint); if (!realMntPoint) { /* * If resolve failed for some reason try to fall back to * original mount point specification. */ realMntPoint = Util_SafeStrdup(vmbMntPoint); } /* Make sure the vmblock file system is mounted. */ fp = OPEN_MNTFILE("r"); if (fp == NULL) { LOG(1, ("%s: could not open mount file\n", __func__)); goto out; } while (GETNEXT_MNTINFO(fp, mnt)) { /* * In the future we can publish the mount point in VMDB so that the UI * can use it rather than enforcing the VMBLOCK_MOUNT_POINT check here. */ if (strcmp(MNTINFO_FSTYPE(mnt), vmbFsName) == 0 && strcmp(MNTINFO_MNTPT(mnt), realMntPoint) == 0) { found = TRUE; break; } } (void) CLOSE_MNTFILE(fp); if (found) { /* Open device node for communication with vmblock. */ blockFd = Posix_Open(vmbDevice, vmbDeviceMode); if (blockFd < 0) { LOG(1, ("%s: Can not open blocker device (%s)\n", __func__, strerror(errno))); } else { LOG(4, ("%s: Opened blocker device at %s\n", __func__, VMBLOCK_DEVICE)); if (verifyBlock && !verifyBlock(blockFd)) { LOG(4, ("%s: Blocker device at %s did not pass checks, closing.\n", __func__, VMBLOCK_DEVICE)); close(blockFd); blockFd = -1; } } } out: free(realMntPoint); return blockFd; #endif }
static Bool RecordResolverInfo(NicInfoV3 *nicInfo) // OUT { DnsConfigInfo *dnsConfigInfo = NULL; char namebuf[DNSINFO_MAX_ADDRLEN + 1]; char **s; if (res_init() == -1) { return FALSE; } dnsConfigInfo = Util_SafeCalloc(1, sizeof *dnsConfigInfo); /* * Copy in the host name. not this */ if (!GuestInfoGetFqdn(sizeof namebuf, namebuf)) { goto fail; } dnsConfigInfo->hostName = Util_SafeCalloc(1, sizeof *dnsConfigInfo->hostName); *dnsConfigInfo->hostName = Util_SafeStrdup(namebuf); /* * Repeat with the domain name. not this */ dnsConfigInfo->domainName = Util_SafeCalloc(1, sizeof *dnsConfigInfo->domainName); *dnsConfigInfo->domainName = Util_SafeStrdup(_res.defdname); /* * Name servers. */ RecordResolverNS(dnsConfigInfo); /* * Search suffixes. */ for (s = _res.dnsrch; *s; s++) { DnsHostname *suffix; /* Check to see if we're going above our limit. See bug 605821. */ if (dnsConfigInfo->searchSuffixes.searchSuffixes_len == DNSINFO_MAX_SUFFIXES) { g_message("%s: dns search suffix limit (%d) reached, skipping overflow.", __FUNCTION__, DNSINFO_MAX_SUFFIXES); break; } suffix = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, searchSuffixes, 1); ASSERT_MEM_ALLOC(suffix); *suffix = Util_SafeStrdup("test suffix"); } /* * "Commit" dnsConfigInfo to nicInfo. */ nicInfo->dnsConfigInfo = dnsConfigInfo; return TRUE; fail: VMX_XDR_FREE(xdr_DnsConfigInfo, dnsConfigInfo); free(dnsConfigInfo); return FALSE; }
MXUserRWLock * MXUser_CreateRWLock(const char *userName, // IN: MX_Rank rank) // IN: { Bool lockInited; char *properName; MXUserRWLock *lock; Bool useNative = MXUserNativeRWSupported(); lock = Util_SafeCalloc(1, sizeof(*lock)); if (userName == NULL) { if (LIKELY(useNative)) { properName = Str_SafeAsprintf(NULL, "RW-%p", GetReturnAddress()); } else { /* emulated */ properName = Str_SafeAsprintf(NULL, "RWemul-%p", GetReturnAddress()); } } else { properName = Util_SafeStrdup(userName); } lock->header.signature = MXUserGetSignature(MXUSER_TYPE_RW); lock->header.name = properName; lock->header.rank = rank; lock->header.serialNumber = MXUserAllocSerialNumber(); lock->header.dumpFunc = MXUserDumpRWLock; /* * Always attempt to use native locks when they are available. If, for some * reason, a native lock should be available but isn't, fall back to using * an internal recursive lock - something is better than nothing. */ lock->useNative = useNative && MXUserNativeRWInit(&lock->nativeLock); lockInited = MXRecLockInit(&lock->recursiveLock); if (LIKELY(lockInited)) { Bool doStats; lock->holderTable = HashTable_Alloc(256, HASH_INT_KEY | HASH_FLAG_ATOMIC, MXUserFreeHashEntry); if (vmx86_stats) { doStats = MXUserStatsEnabled(); } else { doStats = FALSE; } if (doStats) { MXUser_ControlRWLock(lock, MXUSER_CONTROL_ENABLE_STATS); } else { lock->header.statsFunc = NULL; Atomic_WritePtr(&lock->statsMem, NULL); } MXUserAddToList(&lock->header); } else { if (lock->useNative) { MXUserNativeRWDestroy(&lock->nativeLock); } free(properName); free(lock); lock = NULL; } return lock; }
char * File_GetSafeTmpDir(Bool useConf) // IN: { char *tmpDir; #if defined(__FreeBSD__) || defined(sun) tmpDir = FileGetTmpDir(useConf); #else static Atomic_Ptr lckStorage; static char *safeDir; char *baseTmpDir = NULL; char *userName = NULL; uid_t userId; MXUserExclLock *lck; userId = geteuid(); /* Get and take lock for our safe dir. */ lck = MXUser_CreateSingletonExclLock(&lckStorage, "getSafeTmpDirLock", RANK_getSafeTmpDirLock); VERIFY(lck != NULL); MXUser_AcquireExclLock(lck); /* * Check if we've created a temporary dir already and if it is still usable. */ tmpDir = NULL; if (safeDir && FileAcceptableSafeTmpDir(safeDir, userId)) { tmpDir = Util_SafeStrdup(safeDir); goto exit; } /* We don't have a useable temporary dir, create one. */ baseTmpDir = FileGetTmpDir(useConf); if (!baseTmpDir) { Warning("%s: FileGetTmpDir failed.\n", __FUNCTION__); goto exit; } userName = FileGetUserName(userId); if (!userName) { Warning("%s: FileGetUserName failed, using numeric ID " "as username instead.\n", __FUNCTION__); /* Fallback on just using the userId as the username. */ userName = Str_Asprintf(NULL, "uid-%d", userId); if (!userName) { Warning("%s: Str_Asprintf error.\n", __FUNCTION__); goto exit; } } tmpDir = Str_Asprintf(NULL, "%s%s%s-%s", baseTmpDir, DIRSEPS, PRODUCT_GENERIC_NAME_LOWER, userName); if (!tmpDir) { Warning("%s: Out of memory error.\n", __FUNCTION__); goto exit; } if (!FileAcceptableSafeTmpDir(tmpDir, userId)) { /* * We didn't get our first choice for the safe temp directory. * Search through the unsafe tmp directory to see if there is * an acceptable one to use. */ free(tmpDir); tmpDir = FileFindExistingSafeTmpDir(userId, userName, baseTmpDir); if (!tmpDir) { /* * We didn't find any usable directories, so try to create one now. */ tmpDir = FileCreateSafeTmpDir(userId, userName, baseTmpDir); } } if (tmpDir) { /* * We have successfully created a temporary directory, remember it for * future calls. */ free(safeDir); safeDir = Util_SafeStrdup(tmpDir); } exit: MXUser_ReleaseExclLock(lck); free(baseTmpDir); free(userName); #endif return tmpDir; }
const char * Err_Errno2String(Err_Number errorNumber) // IN { HashTable *numTable; HashTable *ptrTable; ErrInfo *info; ErrInfo *oldInfo; Err_Number oldErrno = Err_Errno(); ASSERT(errorNumber != ERR_INVALID); /* * Look up the error in numTable. * Or insert it if it's not there. */ numTable = NUMTABLE(); if (!HashTable_Lookup(numTable, (void *) (uintptr_t) errorNumber, (void **) &info)) { char buf[2048]; const char *p; size_t n; /* * Convert number to string and build the info structure. */ p = ErrErrno2String(errorNumber, buf, sizeof buf); info = Util_SafeMalloc(sizeof *info); info->number = errorNumber; info->string = Util_SafeStrdup(p); /* * To be safe, make sure the end of the string is at * a UTF-8 boundary, but we can only do this when the * string is in our buffer (it may not be). */ n = strlen(info->string); n = CodeSet_Utf8FindCodePointBoundary(info->string, n); info->string[n] = '\0'; /* * Try to insert new info into numTable. * If that fails, then we must have lost out to someone else. * Use theirs in that case. */ oldInfo = HashTable_LookupOrInsert(numTable, (void *) (uintptr_t) errorNumber, info); if (oldInfo != info) { ASSERT(oldInfo->number == info->number); ASSERT(Str_Strcmp(oldInfo->string, info->string) == 0); free(info->string); free(info); info = oldInfo; } } /* * Try to insert info into ptrTable. * We need to do it even if we didn't create this entry, * because we may get here before the other guy (who created * the entry and inserted it into numTable). */ ptrTable = PTRTABLE(); oldInfo = HashTable_LookupOrInsert(ptrTable, info->string, info); ASSERT(oldInfo == info); #if defined VMX86_DEBUG && defined __linux__ { HashTable *strTable = STRTABLE(); ErrInfo *i = HashTable_LookupOrInsert(strTable, info->string, info); ASSERT(i == info); } #endif Err_SetErrno(oldErrno); return info->string; }
MXUserRWLock * MXUser_CreateRWLock(const char *userName, // IN: MX_Rank rank) // IN: { Bool lockInited; char *properName; Bool useNative = MXUserNativeRWSupported(); MXUserRWLock *lock = Util_SafeCalloc(1, sizeof *lock); if (userName == NULL) { if (LIKELY(useNative)) { properName = Str_SafeAsprintf(NULL, "RW-%p", GetReturnAddress()); } else { /* emulated */ properName = Str_SafeAsprintf(NULL, "RWemul-%p", GetReturnAddress()); } } else { properName = Util_SafeStrdup(userName); } lock->header.signature = MXUserGetSignature(MXUSER_TYPE_RW); lock->header.name = properName; lock->header.rank = rank; lock->header.bits.serialNumber = MXUserAllocSerialNumber(); lock->header.dumpFunc = MXUserDumpRWLock; /* * Always attempt to use native locks when they are available. If, for some * reason, a native lock should be available but isn't, fall back to using * an internal recursive lock - something is better than nothing. */ lock->useNative = useNative && MXUserNativeRWInit(&lock->nativeLock); lockInited = MXRecLockInit(&lock->recursiveLock); if (LIKELY(lockInited)) { uint32 statsMode; lock->holderTable = HashTable_Alloc(256, HASH_INT_KEY | HASH_FLAG_ATOMIC, MXUserFreeHashEntry); statsMode = MXUserStatsMode(); switch (MXUserStatsMode()) { case 0: MXUserDisableStats(&lock->acquireStatsMem, &lock->heldStatsMem); lock->header.statsFunc = NULL; break; case 1: MXUserEnableStats(&lock->acquireStatsMem, NULL); lock->header.statsFunc = MXUserStatsActionRW; break; case 2: MXUserEnableStats(&lock->acquireStatsMem, &lock->heldStatsMem); lock->header.statsFunc = MXUserStatsActionRW; break; default: Panic("%s: unknown stats mode: %d!\n", __FUNCTION__, statsMode); } MXUserAddToList(&lock->header); } else { Panic("%s: native lock initialization routine failed\n", __FUNCTION__); } return lock; }
static HashTable * SNEBuildHash(const char **compatEnviron) // IN: original "compatibility" environment { HashTable *environTable; const char **p; /* * Number of buckets picked arbitrarily. We're more interested in having an * associative array than raw table performance. */ environTable = HashTable_Alloc(64, HASH_STRING_KEY | HASH_FLAG_COPYKEY, free); for (p = compatEnviron; p && *p; p++) { const size_t prefixLength = sizeof "VMWARE_" - 1; char *key; char *value; unsigned int index; index = 0; key = StrUtil_GetNextToken(&index, *p, "="); if (!key) { /* XXX Must empty environment variables still contain a '=' delimiter? */ Debug("%s: Encountered environment entry without '='.\n", __func__); continue; } /* * Copy the value beginning after the '=' delimiter (even if it's empty). */ ++index; value = Util_SafeStrdup(&(*p)[index]); if (StrUtil_StartsWith(key, "VMWARE_") && key[prefixLength] != '\0' && (value[0] == '0' || value[0] == '1')) { /* * Okay, this appears to be one of the wrapper's variables, so let's * figure out the original environment variable name (by just indexing * past the prefix) and value (by indexing past the "was this variable * in the native environment?" marker). * * XXX Should we move this marker to a separate header? */ char *realKey = &key[prefixLength]; char *realValue = (value[0] == '0') ? NULL : Util_SafeStrdup(&value[1]); HashTable_ReplaceOrInsert(environTable, realKey, realValue); } else { HashTable_LookupOrInsert(environTable, key, value); } /* * The hash table makes a copy of our key, and it takes ownership of inserted * values (via our passed freeing function). So that means we're responsible * for freeing 'key', but -not- 'value'. */ free(key); } return environTable; }
Bool FileIO_AtomicUpdate(FileIODescriptor *newFD, // IN/OUT: file IO descriptor FileIODescriptor *currFD) // IN/OUT: file IO descriptor { char *currPath = NULL; char *newPath = NULL; #if defined(_WIN32) uint32 currAccess; uint32 newAccess; FileIOResult status; FileIODescriptor tmpFD; #else int fd; #endif int savedErrno = 0; Bool ret = FALSE; ASSERT(FileIO_IsValid(newFD)); ASSERT(FileIO_IsValid(currFD)); if (HostType_OSIsVMK()) { #if defined(VMX86_SERVER) FS_SwapFilesArgs *args = NULL; char *dirName = NULL; char *fileName = NULL; char *dstDirName = NULL; char *dstFileName = NULL; currPath = File_FullPath(FileIO_Filename(currFD)); if (!currPath) { savedErrno = errno; Log("%s: File_FullPath of '%s' failed.\n", __FUNCTION__, FileIO_Filename(currFD)); goto swapdone; } newPath = File_FullPath(FileIO_Filename(newFD)); if (!newPath) { savedErrno = errno; Log("%s: File_FullPath of '%s' failed.\n", __FUNCTION__, FileIO_Filename(newFD)); goto swapdone; } File_GetPathName(newPath, &dirName, &fileName); File_GetPathName(currPath, &dstDirName, &dstFileName); ASSERT(dirName); ASSERT(fileName && *fileName); ASSERT(dstDirName); ASSERT(dstFileName && *dstFileName); ASSERT(File_IsSameFile(dirName, dstDirName)); args = Util_SafeCalloc(1, sizeof *args); if (Str_Snprintf(args->srcFile, sizeof args->srcFile, "%s", fileName) < 0) { Log("%s: Path too long \"%s\".\n", __FUNCTION__, fileName); savedErrno = ENAMETOOLONG; goto swapdone; } if (Str_Snprintf(args->dstFilePath, sizeof args->dstFilePath, "%s/%s", dstDirName, dstFileName) < 0) { Log("%s: Path too long \"%s\".\n", __FUNCTION__, dstFileName); savedErrno = ENAMETOOLONG; goto swapdone; } /* * Issue the ioctl on the directory rather than on the file, * because the file could be open. */ if (!*dirName) { /* need a proper root directory string for Posix_Open() */ free(dirName); dirName = Util_SafeStrdup("/"); } fd = Posix_Open(dirName, O_RDONLY); if (fd < 0) { Log("%s: Open failed \"%s\" %d.\n", __FUNCTION__, dirName, errno); ASSERT(errno != EBUSY); /* #615124. */ savedErrno = errno; goto swapdone; } if (ioctl(fd, IOCTLCMD_VMFS_SWAP_FILES, args) != 0) { savedErrno = errno; if (errno != ENOSYS && errno != ENOTTY) { Log("%s: ioctl failed %d.\n", __FUNCTION__, errno); ASSERT(errno != EBUSY); /* #615124. */ } } else { ret = TRUE; } close(fd); /* * Did we fail because we are on a file system that does not * support the IOCTLCMD_VMFS_SWAP_FILES ioctl? If so fallback to * using rename. * * Check for both ENOSYS and ENOTTY. PR 957695 */ if (savedErrno == ENOSYS || savedErrno == ENOTTY) { /* * NFS allows renames of locked files, even if both files * are locked. The file lock follows the file handle, not * the name, so after the rename we can swap the underlying * file descriptors instead of closing and reopening the * target file. * * This is different than the hosted path below because * ESX uses native file locks and hosted does not. * * We assume that all ESX file systems that support rename * have the same file lock semantics as NFS. */ if (File_Rename(newPath, currPath)) { Log("%s: rename of '%s' to '%s' failed %d.\n", __FUNCTION__, newPath, currPath, errno); savedErrno = errno; goto swapdone; } ret = TRUE; fd = newFD->posix; newFD->posix = currFD->posix; currFD->posix = fd; FileIO_Close(newFD); } swapdone: free(args); free(dirName); free(fileName); free(dstDirName); free(dstFileName); free(currPath); free(newPath); errno = savedErrno; return ret; #else NOT_REACHED(); #endif } #if defined(_WIN32) currPath = Unicode_Duplicate(FileIO_Filename(currFD)); newPath = Unicode_Duplicate(FileIO_Filename(newFD)); newAccess = newFD->flags; currAccess = currFD->flags; FileIO_Close(newFD); /* * The current file needs to be closed and reopened, * but we don't want to drop the file lock by calling * FileIO_Close() on it. Instead, use native close primitives. * We'll reopen it later with FileIO_Open. Set the * descriptor/handle to an invalid value while we're in the * middle of transferring ownership. */ CloseHandle(currFD->win32); currFD->win32 = INVALID_HANDLE_VALUE; if (File_RenameRetry(newPath, currPath, 10) == 0) { ret = TRUE; } else { savedErrno = errno; ASSERT(!ret); } FileIO_Invalidate(&tmpFD); /* * Clear the locking bits from the requested access so that reopening * the file ignores the advisory lock. */ ASSERT((currAccess & FILEIO_OPEN_LOCK_MANDATORY) == 0); currAccess &= ~(FILEIO_OPEN_LOCK_MANDATORY | FILEIO_OPEN_LOCK_ADVISORY | FILEIO_OPEN_LOCK_BEST | FILEIO_OPEN_LOCKED); status = FileIO_Open(&tmpFD, currPath, currAccess, FILEIO_OPEN); if (!FileIO_IsSuccess(status)) { Panic("Failed to reopen dictionary after renaming " "\"%s\" to \"%s\": %s (%d)\n", newPath, currPath, FileIO_ErrorEnglish(status), status); } ASSERT(tmpFD.lockToken == NULL); currFD->win32 = tmpFD.win32; FileIO_Cleanup(&tmpFD); free(currPath); free(newPath); errno = savedErrno; return ret; #else currPath = (char *)FileIO_Filename(currFD); newPath = (char *)FileIO_Filename(newFD); if (File_Rename(newPath, currPath)) { Log("%s: rename of '%s' to '%s' failed %d.\n", __FUNCTION__, newPath, currPath, errno); savedErrno = errno; } else { ret = TRUE; fd = newFD->posix; newFD->posix = currFD->posix; currFD->posix = fd; FileIO_Close(newFD); } errno = savedErrno; return ret; #endif }
char * Unicode_Duplicate(const char *str) // IN { return Util_SafeStrdup(str); }
void VMTools_BindTextDomain(const char *domain, const char *lang, const char *catdir) { char *dfltdir = NULL; gchar *file; gchar *usrlang = NULL; MsgState *state = MsgGetState(); MsgCatalog *catalog; ASSERT(domain); /* * If the caller has asked for the default user language, detect it and * translate to our internal language string representation. */ if (lang == NULL || *lang == '\0') { usrlang = MsgGetUserLanguage(); lang = usrlang; } g_debug("%s: user locale=%s\n", __FUNCTION__, lang); /* * Use the default install directory if none is provided. */ if (catdir == NULL) { #if defined(OPEN_VM_TOOLS) dfltdir = Util_SafeStrdup(VMTOOLS_DATA_DIR); #else dfltdir = GuestApp_GetInstallPath(); #endif catdir = (dfltdir) ? dfltdir : "."; } file = g_strdup_printf("%s%smessages%s%s%s%s.vmsg", catdir, DIRSEPS, DIRSEPS, lang, DIRSEPS, domain); if (!File_IsFile(file)) { /* * If we couldn't find the catalog file for the user's language, see if * we can find a more generic language (e.g., for "en_US", also try "en"). */ char *sep = Str_Strrchr(lang, '_'); if (sep != NULL) { if (usrlang == NULL) { usrlang = Util_SafeStrdup(lang); } usrlang[sep - lang] = '\0'; g_free(file); file = g_strdup_printf("%s%smessages%s%s%s%s.vmsg", catdir, DIRSEPS, DIRSEPS, usrlang, DIRSEPS, domain); } } catalog = MsgLoadCatalog(file); if (catalog == NULL) { if (Str_Strncmp(lang, "en", 2)) { /* * Don't warn about english dictionary, which may not exist (it is the * default translation). */ g_message("Cannot load message catalog for domain '%s', language '%s', " "catalog dir '%s'.\n", domain, lang, catdir); } } else { g_static_mutex_lock(&state->lock); MsgSetCatalog(domain, catalog); g_static_mutex_unlock(&state->lock); } g_free(file); free(dfltdir); g_free(usrlang); }
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; }