Пример #1
0
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;
}
Пример #2
0
/**
 * 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;
}
Пример #3
0
/**
 * 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;
}
Пример #4
0
/**
 * 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;
}