RTDECL(int) RTSystemQueryOSInfo(RTSYSOSINFO enmInfo, char *pszInfo, size_t cchInfo)
{
    /*
     * Quick validation.
     */
    AssertReturn(enmInfo > RTSYSOSINFO_INVALID && enmInfo < RTSYSOSINFO_END, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pszInfo, VERR_INVALID_POINTER);
    if (!cchInfo)
        return VERR_BUFFER_OVERFLOW;

    /*
     * Handle the request.
     */
    switch (enmInfo)
    {
        case RTSYSOSINFO_PRODUCT:
        case RTSYSOSINFO_RELEASE:
        case RTSYSOSINFO_VERSION:
        {
            struct utsname UtsInfo;
            if (uname(&UtsInfo) < 0)
                return RTErrConvertFromErrno(errno);
            const char *pszSrc;
            switch (enmInfo)
            {
                case RTSYSOSINFO_PRODUCT:   pszSrc = UtsInfo.sysname; break;
                case RTSYSOSINFO_RELEASE:   pszSrc = UtsInfo.release; break;
                case RTSYSOSINFO_VERSION:   pszSrc = UtsInfo.version; break;
                default: AssertFatalFailed(); /* screw gcc */
            }
            size_t cch = strlen(pszSrc);
            if (cch < cchInfo)
            {
                memcpy(pszInfo, pszSrc, cch + 1);
                return VINF_SUCCESS;
            }
            memcpy(pszInfo, pszSrc, cchInfo - 1);
            pszInfo[cchInfo - 1] = '\0';
            return VERR_BUFFER_OVERFLOW;
        }


        case RTSYSOSINFO_SERVICE_PACK:
        default:
            *pszInfo = '\0';
            return VERR_NOT_SUPPORTED;
    }

    return VINF_SUCCESS;
}
/**
 * Services the  RTSYSOSINFO_PRODUCT, RTSYSOSINFO_RELEASE
 * and RTSYSOSINFO_SERVICE_PACK requests.
 *
 * @returns See RTSystemQueryOSInfo.
 * @param   enmInfo         See RTSystemQueryOSInfo.
 * @param   pszInfo         See RTSystemQueryOSInfo.
 * @param   cchInfo         See RTSystemQueryOSInfo.
 */
static int rtSystemWinQueryOSVersion(RTSYSOSINFO enmInfo, char *pszInfo, size_t cchInfo)
{
    /*
     * Make sure it's terminated correctly in case of error.
     */
    *pszInfo = '\0';

    /*
     * Check that we got the windows version at init time.
     */
    AssertReturn(g_WinOsInfoEx.dwOSVersionInfoSize, VERR_WRONG_ORDER);

    /*
     * Service the request.
     */
    char szTmp[512];
    szTmp[0] = '\0';
    switch (enmInfo)
    {
        /*
         * The product name.
         */
        case RTSYSOSINFO_PRODUCT:
        {
            switch (g_enmWinVer)
            {
                case kRTWinOSType_95:           strcpy(szTmp, "Windows 95"); break;
                case kRTWinOSType_95SP1:        strcpy(szTmp, "Windows 95 (Service Pack 1)"); break;
                case kRTWinOSType_95OSR2:       strcpy(szTmp, "Windows 95 (OSR 2)"); break;
                case kRTWinOSType_98:           strcpy(szTmp, "Windows 98"); break;
                case kRTWinOSType_98SP1:        strcpy(szTmp, "Windows 98 (Service Pack 1)"); break;
                case kRTWinOSType_98SE:         strcpy(szTmp, "Windows 98 (Second Edition)"); break;
                case kRTWinOSType_ME:           strcpy(szTmp, "Windows Me"); break;
                case kRTWinOSType_NT351:        strcpy(szTmp, "Windows NT 3.51"); break;
                case kRTWinOSType_NT4:          strcpy(szTmp, "Windows NT 4.0"); break;
                case kRTWinOSType_2K:           strcpy(szTmp, "Windows 2000"); break;
                case kRTWinOSType_XP:
                    strcpy(szTmp, "Windows XP");
                    if (g_WinOsInfoEx.wSuiteMask & VER_SUITE_PERSONAL)
                        strcat(szTmp, " Home");
                    if (    g_WinOsInfoEx.wProductType == VER_NT_WORKSTATION
                        && !(g_WinOsInfoEx.wSuiteMask & VER_SUITE_PERSONAL))
                        strcat(szTmp, " Professional");
#if 0 /** @todo fixme */
                    if (GetSystemMetrics(SM_MEDIACENTER))
                        strcat(szTmp, " Media Center");
#endif
                    break;

                case kRTWinOSType_2003:         strcpy(szTmp, "Windows 2003"); break;
                case kRTWinOSType_VISTA:
                {
                    strcpy(szTmp, "Windows Vista");
                    rtSystemWinAppendProductType(szTmp);
                    break;
                }
                case kRTWinOSType_2008:         strcpy(szTmp, "Windows 2008"); break;
                case kRTWinOSType_7:            strcpy(szTmp, "Windows 7"); break;
                case kRTWinOSType_2008R2:       strcpy(szTmp, "Windows 2008 R2"); break;
                case kRTWinOSType_8:            strcpy(szTmp, "Windows 8"); break;
                case kRTWinOSType_2012:         strcpy(szTmp, "Windows 2012"); break;
                case kRTWinOSType_81:           strcpy(szTmp, "Windows 8.1"); break;
                case kRTWinOSType_2012R2:       strcpy(szTmp, "Windows 2012 R2"); break;
                case kRTWinOSType_10:           strcpy(szTmp, "Windows 10"); break;
                case kRTWinOSType_2016:         strcpy(szTmp, "Windows 2016"); break;

                case kRTWinOSType_NT_UNKNOWN:
                    RTStrPrintf(szTmp, sizeof(szTmp), "Unknown NT v%u.%u",
                                g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion);
                    break;

                default:
                    AssertFailed();
                case kRTWinOSType_UNKNOWN:
                    RTStrPrintf(szTmp, sizeof(szTmp), "Unknown %d v%u.%u",
                                g_WinOsInfoEx.dwPlatformId, g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion);
                    break;
            }
            break;
        }

        /*
         * The release.
         */
        case RTSYSOSINFO_RELEASE:
        {
            RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u.%u",
                        g_WinOsInfoEx.dwMajorVersion, g_WinOsInfoEx.dwMinorVersion, g_WinOsInfoEx.dwBuildNumber);
            break;
        }


        /*
         * Get the service pack.
         */
        case RTSYSOSINFO_SERVICE_PACK:
        {
            if (g_WinOsInfoEx.wServicePackMajor)
            {
                if (g_WinOsInfoEx.wServicePackMinor)
                    RTStrPrintf(szTmp, sizeof(szTmp), "%u.%u",
                                (unsigned)g_WinOsInfoEx.wServicePackMajor, (unsigned)g_WinOsInfoEx.wServicePackMinor);
                else
                    RTStrPrintf(szTmp, sizeof(szTmp), "%u",
                                (unsigned)g_WinOsInfoEx.wServicePackMajor);
            }
            else if (g_WinOsInfoEx.szCSDVersion[0])
            {
                /* just copy the entire string. */
                char *pszTmp = szTmp;
                int rc = RTUtf16ToUtf8Ex(g_WinOsInfoEx.szCSDVersion, RT_ELEMENTS(g_WinOsInfoEx.szCSDVersion),
                                         &pszTmp, sizeof(szTmp), NULL);
                if (RT_SUCCESS(rc))
                    RTStrStripR(szTmp);
                else
                    szTmp[0] = '\0';
                AssertCompile(sizeof(szTmp) > sizeof(g_WinOsInfoEx.szCSDVersion));
            }
            else
            {
                switch (g_enmWinVer)
                {
                    case kRTWinOSType_95SP1:    strcpy(szTmp, "1"); break;
                    case kRTWinOSType_98SP1:    strcpy(szTmp, "1"); break;
                    default:
                        break;
                }
            }
            break;
        }

        default:
            AssertFatalFailed();
    }

    /*
     * Copy the result to the return buffer.
     */
    size_t cchTmp = strlen(szTmp);
    Assert(cchTmp < sizeof(szTmp));
    if (cchTmp < cchInfo)
    {
        memcpy(pszInfo, szTmp, cchTmp + 1);
        return VINF_SUCCESS;
    }
    memcpy(pszInfo, szTmp, cchInfo - 1);
    pszInfo[cchInfo - 1] = '\0';
    return VERR_BUFFER_OVERFLOW;
}