RTDECL(const char *) RTEnvGetBad(const char *pszVar) { AssertReturn(strchr(pszVar, '=') == NULL, NULL); IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc causes trouble */ const char *pszValue = getenv(pszVar); IPRT_ALIGNMENT_CHECKS_ENABLE(); return pszValue; }
/** * Converts a string from one charset to another without using the handle cache. * * @returns IPRT status code. * * @param pvInput Pointer to intput string. * @param cbInput Size (in bytes) of input string. Excludes any terminators. * @param pszInputCS Codeset of the input string. * @param ppvOutput Pointer to pointer to output buffer if cbOutput > 0. * If cbOutput is 0 this is where the pointer to the allocated * buffer is stored. * @param cbOutput Size of the passed in buffer. * @param pszOutputCS Codeset of the input string. * @param cFactor Input vs. output size factor. */ static int rtStrConvertUncached(const void *pvInput, size_t cbInput, const char *pszInputCS, void **ppvOutput, size_t cbOutput, const char *pszOutputCS, unsigned cFactor) { /* * Allocate buffer */ bool fUcs2Term; void *pvOutput; size_t cbOutput2; if (!cbOutput) { cbOutput2 = cbInput * cFactor; pvOutput = RTMemTmpAlloc(cbOutput2 + sizeof(RTUTF16)); if (!pvOutput) return VERR_NO_TMP_MEMORY; fUcs2Term = true; } else { pvOutput = *ppvOutput; fUcs2Term = !strcmp(pszOutputCS, "UCS-2"); cbOutput2 = cbOutput - (fUcs2Term ? sizeof(RTUTF16) : 1); if (cbOutput2 > cbOutput) return VERR_BUFFER_OVERFLOW; } /* * Use a loop here to retry with bigger buffers. */ for (unsigned cTries = 10; cTries > 0; cTries--) { /* * Create conversion object. */ #if defined(RT_OS_SOLARIS) || defined(RT_OS_NETBSD) /* Some systems don't grok empty codeset strings, so help them find the current codeset. */ if (!*pszInputCS) pszInputCS = rtStrGetLocaleCodeset(); if (!*pszOutputCS) pszOutputCS = rtStrGetLocaleCodeset(); #endif IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc causes trouble */ iconv_t icHandle = iconv_open(pszOutputCS, pszInputCS); IPRT_ALIGNMENT_CHECKS_ENABLE(); if (icHandle != (iconv_t)-1) { /* * Do the conversion. */ size_t cbInLeft = cbInput; size_t cbOutLeft = cbOutput2; const void *pvInputLeft = pvInput; void *pvOutputLeft = pvOutput; size_t cchNonRev; #if defined(RT_OS_LINUX) || defined(RT_OS_HAIKU) || defined(RT_OS_SOLARIS) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */ cchNonRev = iconv(icHandle, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft); #else cchNonRev = iconv(icHandle, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft); #endif if (cchNonRev != (size_t)-1) { if (!cbInLeft) { /* * We're done, just add the terminator and return. * (Two terminators to support UCS-2 output, too.) */ iconv_close(icHandle); ((char *)pvOutputLeft)[0] = '\0'; if (fUcs2Term) ((char *)pvOutputLeft)[1] = '\0'; *ppvOutput = pvOutput; if (cchNonRev == 0) return VINF_SUCCESS; return VWRN_NO_TRANSLATION; } errno = E2BIG; } iconv_close(icHandle); /* * If we failed because of output buffer space we'll * increase the output buffer size and retry. */ if (errno == E2BIG) { if (!cbOutput) { RTMemTmpFree(pvOutput); cbOutput2 *= 2; pvOutput = RTMemTmpAlloc(cbOutput2 + sizeof(RTUTF16)); if (!pvOutput) return VERR_NO_TMP_MEMORY; continue; } return VERR_BUFFER_OVERFLOW; } } break; } /* failure */ if (!cbOutput) RTMemTmpFree(pvOutput); return VERR_NO_TRANSLATION; }
/** * Converts a string from one charset to another. * * @returns iprt status code. * @param pvInput Pointer to intput string. * @param cbInput Size (in bytes) of input string. Excludes any terminators. * @param pszInputCS Codeset of the input string. * @param ppvOutput Pointer to pointer to output buffer if cbOutput > 0. * If cbOutput is 0 this is where the pointer to the allocated * buffer is stored. * @param cbOutput Size of the passed in buffer. * @param pszOutputCS Codeset of the input string. * @param cFactor Input vs. output size factor. * @param phIconv Pointer to the cache entry. */ static int rtstrConvertCached(const void *pvInput, size_t cbInput, const char *pszInputCS, void **ppvOutput, size_t cbOutput, const char *pszOutputCS, unsigned cFactor, iconv_t *phIconv) { /* * Allocate buffer */ bool fUcs2Term; void *pvOutput; size_t cbOutput2; if (!cbOutput) { cbOutput2 = cbInput * cFactor; pvOutput = RTMemTmpAlloc(cbOutput2 + sizeof(RTUTF16)); if (!pvOutput) return VERR_NO_TMP_MEMORY; fUcs2Term = true; } else { pvOutput = *ppvOutput; fUcs2Term = !strcmp(pszOutputCS, "UCS-2") || !strcmp(pszOutputCS, "UTF-16") || !strcmp(pszOutputCS, "ucs-2") || !strcmp(pszOutputCS, "utf-16"); cbOutput2 = cbOutput - (fUcs2Term ? sizeof(RTUTF16) : 1); if (cbOutput2 > cbOutput) return VERR_BUFFER_OVERFLOW; } /* * Use a loop here to retry with bigger buffers. */ for (unsigned cTries = 10; cTries > 0; cTries--) { /* * Create conversion object if necessary. */ iconv_t hIconv = (iconv_t)*phIconv; if (hIconv == (iconv_t)-1) { #ifdef RT_OS_SOLARIS /* Solaris doesn't grok empty codeset strings, so help it find the current codeset. */ if (!*pszInputCS) pszInputCS = rtStrGetLocaleCodeset(); if (!*pszOutputCS) pszOutputCS = rtStrGetLocaleCodeset(); #endif IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc causes trouble */ *phIconv = hIconv = iconv_open(pszOutputCS, pszInputCS); IPRT_ALIGNMENT_CHECKS_ENABLE(); } if (hIconv != (iconv_t)-1) { /* * Do the conversion. */ size_t cbInLeft = cbInput; size_t cbOutLeft = cbOutput2; const void *pvInputLeft = pvInput; void *pvOutputLeft = pvOutput; #if defined(RT_OS_LINUX) || defined(RT_OS_HAIKU) || defined(RT_OS_SOLARIS) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */ if (iconv(hIconv, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1) #else if (iconv(hIconv, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1) #endif { if (!cbInLeft) { /* * We're done, just add the terminator and return. * (Two terminators to support UCS-2 output, too.) */ ((char *)pvOutputLeft)[0] = '\0'; if (fUcs2Term) ((char *)pvOutputLeft)[1] = '\0'; *ppvOutput = pvOutput; return VINF_SUCCESS; } errno = E2BIG; } /* * If we failed because of output buffer space we'll * increase the output buffer size and retry. */ if (errno == E2BIG) { if (!cbOutput) { RTMemTmpFree(pvOutput); cbOutput2 *= 2; pvOutput = RTMemTmpAlloc(cbOutput2 + sizeof(RTUTF16)); if (!pvOutput) return VERR_NO_TMP_MEMORY; continue; } return VERR_BUFFER_OVERFLOW; } /* * Close the handle on all other errors to make sure we won't carry * any bad state with us. */ *phIconv = (iconv_t)-1; iconv_close(hIconv); } break; } /* failure */ if (!cbOutput) RTMemTmpFree(pvOutput); return VERR_NO_TRANSLATION; }
/** * Internal write API, stream lock already held. * * @returns IPRT status code. * @param pStream The stream. * @param pvBuf What to write. * @param cbWrite How much to write. * @param pcbWritten Where to optionally return the number of bytes * written. * @param fSureIsText Set if we're sure this is UTF-8 text already. */ static int rtStrmWriteLocked(PRTSTREAM pStream, const void *pvBuf, size_t cbWrite, size_t *pcbWritten, bool fSureIsText) { int rc = pStream->i32Error; if (RT_FAILURE(rc)) return rc; if (pStream->fRecheckMode) rtStreamRecheckMode(pStream); #ifdef RT_OS_WINDOWS /* * Use the unicode console API when possible in order to avoid stuff * getting lost in unnecessary code page translations. */ HANDLE hCon; if (rtStrmIsConsoleUnlocked(pStream, &hCon)) { # ifdef HAVE_FWRITE_UNLOCKED if (!fflush_unlocked(pStream->pFile)) # else if (!fflush(pStream->pFile)) # endif { /** @todo Consider buffering later. For now, we'd rather correct output than * fast output. */ DWORD cwcWritten = 0; PRTUTF16 pwszSrc = NULL; size_t cwcSrc = 0; rc = RTStrToUtf16Ex((const char *)pvBuf, cbWrite, &pwszSrc, 0, &cwcSrc); if (RT_SUCCESS(rc)) { if (!WriteConsoleW(hCon, pwszSrc, (DWORD)cwcSrc, &cwcWritten, NULL)) { /* try write char-by-char to avoid heap problem. */ cwcWritten = 0; while (cwcWritten != cwcSrc) { DWORD cwcThis; if (!WriteConsoleW(hCon, &pwszSrc[cwcWritten], 1, &cwcThis, NULL)) { if (!pcbWritten || cwcWritten == 0) rc = RTErrConvertFromErrno(GetLastError()); break; } if (cwcThis != 1) /* Unable to write current char (amount)? */ break; cwcWritten++; } } if (RT_SUCCESS(rc)) { if (cwcWritten == cwcSrc) { if (pcbWritten) *pcbWritten = cbWrite; } else if (pcbWritten) { PCRTUTF16 pwszCur = pwszSrc; const char *pszCur = (const char *)pvBuf; while ((uintptr_t)(pwszCur - pwszSrc) < cwcWritten) { RTUNICP CpIgnored; RTUtf16GetCpEx(&pwszCur, &CpIgnored); RTStrGetCpEx(&pszCur, &CpIgnored); } *pcbWritten = pszCur - (const char *)pvBuf; } else rc = VERR_WRITE_ERROR; } RTUtf16Free(pwszSrc); } } else rc = RTErrConvertFromErrno(errno); if (RT_FAILURE(rc)) ASMAtomicWriteS32(&pStream->i32Error, rc); return rc; } #endif /* RT_OS_WINDOWS */ /* * If we're sure it's text output, convert it from UTF-8 to the current * code page before printing it. * * Note! Partial writes are not supported in this scenario because we * cannot easily report back a written length matching the input. */ /** @todo Skip this if the current code set is UTF-8. */ if ( pStream->fCurrentCodeSet && !pStream->fBinary && ( fSureIsText || rtStrmIsUtf8Text(pvBuf, cbWrite)) ) { char *pszSrcFree = NULL; const char *pszSrc = (const char *)pvBuf; if (pszSrc[cbWrite]) { pszSrc = pszSrcFree = RTStrDupN(pszSrc, cbWrite); if (pszSrc == NULL) rc = VERR_NO_STR_MEMORY; } if (RT_SUCCESS(rc)) { char *pszSrcCurCP; rc = RTStrUtf8ToCurrentCP(&pszSrcCurCP, pszSrc); if (RT_SUCCESS(rc)) { size_t cchSrcCurCP = strlen(pszSrcCurCP); IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */ #ifdef HAVE_FWRITE_UNLOCKED ssize_t cbWritten = fwrite_unlocked(pszSrcCurCP, cchSrcCurCP, 1, pStream->pFile); #else ssize_t cbWritten = fwrite(pszSrcCurCP, cchSrcCurCP, 1, pStream->pFile); #endif IPRT_ALIGNMENT_CHECKS_ENABLE(); if (cbWritten == 1) { if (pcbWritten) *pcbWritten = cbWrite; } #ifdef HAVE_FWRITE_UNLOCKED else if (!ferror_unlocked(pStream->pFile)) #else else if (!ferror(pStream->pFile)) #endif { if (pcbWritten) *pcbWritten = 0; } else rc = VERR_WRITE_ERROR; RTStrFree(pszSrcCurCP); } RTStrFree(pszSrcFree); } if (RT_FAILURE(rc)) ASMAtomicWriteS32(&pStream->i32Error, rc); return rc; }
/** * rtR3Init worker. */ static int rtR3InitBody(uint32_t fFlags, int cArgs, char ***papszArgs, const char *pszProgramPath) { /* * Early native initialization. */ int rc = rtR3InitNativeFirst(fFlags); AssertMsgRCReturn(rc, ("rtR3InitNativeFirst failed with %Rrc\n", rc), rc); /* * Disable error popups. */ #if defined(RT_OS_OS2) /** @todo move to private code. */ DosError(FERR_DISABLEHARDERR); #endif /* * Init C runtime locale before we do anything that may end up converting * paths or we'll end up using the "C" locale for path conversion. */ setlocale(LC_CTYPE, ""); /* * The Process ID. */ #ifdef _MSC_VER g_ProcessSelf = _getpid(); /* crappy ansi compiler */ #else g_ProcessSelf = getpid(); #endif /* * Save the init flags. */ g_fInitFlags |= fFlags; #if !defined(IN_GUEST) && !defined(RT_NO_GIP) # ifdef VBOX /* * This MUST be done as the very first thing, before any file is opened. * The log is opened on demand, but the first log entries may be caused * by rtThreadInit() below. */ const char *pszDisableHostCache = getenv("VBOX_DISABLE_HOST_DISK_CACHE"); if ( pszDisableHostCache != NULL && *pszDisableHostCache && strcmp(pszDisableHostCache, "0") != 0) { RTFileSetForceFlags(RTFILE_O_WRITE, RTFILE_O_WRITE_THROUGH, 0); RTFileSetForceFlags(RTFILE_O_READWRITE, RTFILE_O_WRITE_THROUGH, 0); } # endif /* VBOX */ #endif /* !IN_GUEST && !RT_NO_GIP */ /* * Thread Thread database and adopt the caller thread as 'main'. * This must be done before everything else or else we'll call into threading * without having initialized TLS entries and suchlike. */ rc = rtThreadInit(); AssertMsgRCReturn(rc, ("Failed to initialize threads, rc=%Rrc!\n", rc), rc); #if !defined(IN_GUEST) && !defined(RT_NO_GIP) if (fFlags & RTR3INIT_FLAGS_SUPLIB) { /* * Init GIP first. * (The more time for updates before real use, the better.) */ rc = SUPR3Init(NULL); AssertMsgRCReturn(rc, ("Failed to initializable the support library, rc=%Rrc!\n", rc), rc); } #endif /* * The executable path, name and directory. Convert arguments. */ rc = rtR3InitProgramPath(pszProgramPath); AssertLogRelMsgRCReturn(rc, ("Failed to get executable directory path, rc=%Rrc!\n", rc), rc); rc = rtR3InitArgv(fFlags, cArgs, papszArgs); AssertLogRelMsgRCReturn(rc, ("Failed to convert the arguments, rc=%Rrc!\n", rc), rc); #if !defined(IN_GUEST) && !defined(RT_NO_GIP) /* * The threading is initialized we can safely sleep a bit if GIP * needs some time to update itself updating. */ if ((fFlags & RTR3INIT_FLAGS_SUPLIB) && g_pSUPGlobalInfoPage) { RTThreadSleep(20); RTTimeNanoTS(); } #endif /* * Init the program start TSes. * Do that here to be sure that the GIP time was properly updated the 1st time. */ g_u64ProgramStartNanoTS = RTTimeNanoTS(); g_u64ProgramStartMicroTS = g_u64ProgramStartNanoTS / 1000; g_u64ProgramStartMilliTS = g_u64ProgramStartNanoTS / 1000000; /* * The remainder cannot easily be undone, so it has to go last. */ /* Fork and exit callbacks. */ #if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2) rc = pthread_atfork(NULL, NULL, rtR3ForkChildCallback); AssertMsg(rc == 0, ("%d\n", rc)); #endif atexit(rtR3ExitCallback); #ifdef IPRT_USE_SIG_CHILD_DUMMY /* * SIGCHLD must not be ignored (that's default), otherwise posix compliant waitpid * implementations won't work right. */ for (;;) { struct sigaction saOld; rc = sigaction(SIGCHLD, 0, &saOld); AssertMsg(rc == 0, ("%d/%d\n", rc, errno)); if ( rc != 0 || (saOld.sa_flags & SA_SIGINFO) || ( saOld.sa_handler != SIG_IGN && saOld.sa_handler != SIG_DFL) ) break; /* Try install dummy handler. */ struct sigaction saNew = saOld; saNew.sa_flags = SA_NOCLDSTOP | SA_RESTART; saNew.sa_handler = rtR3SigChildHandler; rc = sigemptyset(&saNew.sa_mask); AssertMsg(rc == 0, ("%d/%d\n", rc, errno)); struct sigaction saOld2; rc = sigaction(SIGCHLD, &saNew, &saOld2); AssertMsg(rc == 0, ("%d/%d\n", rc, errno)); if ( rc != 0 || ( saOld2.sa_handler == saOld.sa_handler && !(saOld2.sa_flags & SA_SIGINFO)) ) break; /* Race during dynamic load, restore and try again... */ sigaction(SIGCHLD, &saOld2, NULL); RTThreadYield(); } #endif /* IPRT_USE_SIG_CHILD_DUMMY */ #ifdef IPRT_WITH_ALIGNMENT_CHECKS /* * Enable alignment checks. */ const char *pszAlignmentChecks = getenv("IPRT_ALIGNMENT_CHECKS"); g_fRTAlignmentChecks = pszAlignmentChecks != NULL && pszAlignmentChecks[0] == '1' && pszAlignmentChecks[1] == '\0'; if (g_fRTAlignmentChecks) IPRT_ALIGNMENT_CHECKS_ENABLE(); #endif /* * Final native initialization. */ rc = rtR3InitNativeFinal(fFlags); AssertMsgRCReturn(rc, ("rtR3InitNativeFinal failed with %Rrc\n", rc), rc); return VINF_SUCCESS; }