Changeset 92671 in vbox for trunk/src/VBox
- Timestamp:
- Dec 1, 2021 12:35:07 PM (3 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/include/internal/string.h
r90821 r92671 97 97 char **ppszOutput, size_t cbOutput, const char *pszOutputCS, 98 98 unsigned cFactor, RTSTRICONV enmCacheIdx); 99 DECLHIDDEN(void) rtStrLocalCacheInit(void **ppvTmpCache); 100 DECLHIDDEN(int) rtStrLocalCacheConvert(const char *pchInput, size_t cchInput, const char *pszInputCS, 101 char **ppszOutput, size_t cbOutput, const char *pszOutputCS, 102 void **ppvTmpCache); 103 DECLHIDDEN(void) rtStrLocalCacheDelete(void **ppvTmpCache); 99 104 DECLHIDDEN(const char *) rtStrGetLocaleCodeset(void); 105 DECLHIDDEN(bool) rtStrIsLocaleCodesetUtf8(void); 106 DECLHIDDEN(bool) rtStrIsCodesetUtf8(const char *pszCodeset); 100 107 DECLHIDDEN(int) rtUtf8Length(const char *psz, size_t cch, size_t *pcuc, size_t *pcchActual); 101 108 -
trunk/src/VBox/Runtime/r3/posix/process-creation-posix.cpp
r92657 r92671 37 37 # define _GNU_SOURCE 38 38 #endif 39 #if defined(RT_OS_LINUX) && !defined(_XOPEN_SOURCE) 40 # define _XOPEN_SOURCE 700 /* for newlocale */ 41 #endif 39 42 40 43 #ifdef RT_OS_OS2 … … 51 54 #include <stdlib.h> 52 55 #include <errno.h> 56 #include <langinfo.h> 57 #include <locale.h> 53 58 #include <sys/types.h> 54 59 #include <sys/stat.h> … … 119 124 #include "internal/iprt.h" 120 125 126 #include <iprt/alloca.h> 121 127 #include <iprt/assert.h> 122 128 #include <iprt/ctype.h> … … 134 140 #include <iprt/mem.h> 135 141 #include "internal/process.h" 142 #include "internal/path.h" 143 #include "internal/string.h" 136 144 137 145 … … 1288 1296 1289 1297 /** 1298 * Converts the arguments to the child's LC_CTYPE charset if necessary. 1299 * 1300 * @returns IPRT status code. 1301 * @param papszArgs The arguments (UTF-8). 1302 * @param hEnvToUse The child process environment. 1303 * @param ppapszArgs Where to return the converted arguments. The array 1304 * entries must be freed by RTStrFree and the array itself 1305 * by RTMemFree. 1306 */ 1307 static int rtProcPosixConvertArgv(const char * const *papszArgs, RTENV hEnvToUse, char ***ppapszArgs) 1308 { 1309 *ppapszArgs = (char **)papszArgs; 1310 1311 /* 1312 * The first thing we need to do here is to try guess the codeset of the 1313 * child process and check if it's UTF-8 or not. 1314 */ 1315 const char *pszEncoding; 1316 char szEncoding[512]; 1317 if (hEnvToUse == RTENV_DEFAULT) 1318 { 1319 /* Same environment as us, assume setlocale is up to date: */ 1320 pszEncoding = rtStrGetLocaleCodeset(); 1321 } 1322 else 1323 { 1324 /* LC_ALL overrides everything else.*/ 1325 /** @todo I don't recall now if this can do LC_XXX= inside it's value, like 1326 * what setlocale returns on some systems. It's been 15-16 years 1327 * since I last worked on an setlocale implementation... */ 1328 const char *pszVar; 1329 int rc = RTEnvGetEx(hEnvToUse, pszVar = "LC_ALL", szEncoding, sizeof(szEncoding), NULL); 1330 if (rc == VERR_ENV_VAR_NOT_FOUND) 1331 rc = RTEnvGetEx(hEnvToUse, pszVar = "LC_CTYPE", szEncoding, sizeof(szEncoding), NULL); 1332 if (rc == VERR_ENV_VAR_NOT_FOUND) 1333 rc = RTEnvGetEx(hEnvToUse, pszVar = "LANG", szEncoding, sizeof(szEncoding), NULL); 1334 if (RT_SUCCESS(rc)) 1335 { 1336 const char *pszDot = strchr(szEncoding, '.'); 1337 if (pszDot) 1338 pszDot = RTStrStripL(pszDot + 1); 1339 if (pszDot && *pszDot) 1340 { 1341 pszEncoding = pszDot; 1342 Log2Func(("%s=%s -> %s (simple)\n", pszVar, szEncoding, pszEncoding)); 1343 } 1344 else 1345 { 1346 /* No charset is given, so the default of the locale should be 1347 used. To get at that we have to use newlocale and nl_langinfo_l, 1348 which is there since ancient days on linux but no necessarily else 1349 where. */ 1350 #ifdef LC_CTYPE_MASK 1351 locale_t hLocale = newlocale(LC_CTYPE_MASK, szEncoding, (locale_t)0); 1352 if (hLocale != (locale_t)0) 1353 { 1354 const char *pszCodeset = nl_langinfo_l(CODESET, hLocale); 1355 Log2Func(("nl_langinfo_l(CODESET, %s=%s) -> %s\n", pszVar, szEncoding, pszCodeset)); 1356 Assert(pszCodeset && *pszCodeset != '\0'); 1357 1358 rc = RTStrCopy(szEncoding, sizeof(szEncoding), pszCodeset); 1359 AssertRC(rc); /* cannot possibly overflow */ 1360 1361 freelocale(hLocale); 1362 pszEncoding = szEncoding; 1363 } 1364 else 1365 #endif 1366 { 1367 /* This is mostly wrong, but I cannot think of anything better now: */ 1368 pszEncoding = rtStrGetLocaleCodeset(); 1369 LogFunc(("No newlocale or it failed (on '%s=%s', errno=%d), falling back on %s that we're using...\n", 1370 pszVar, szEncoding, errno, pszEncoding)); 1371 } 1372 } 1373 RT_NOREF_PV(pszVar); 1374 } 1375 else 1376 pszEncoding = "C"; 1377 } 1378 1379 /* 1380 * Do nothing if it's UTF-8. 1381 */ 1382 if (rtStrIsCodesetUtf8(pszEncoding)) 1383 { 1384 LogFlowFunc(("No conversion needed (%s)\n", pszEncoding)); 1385 return VINF_SUCCESS; 1386 } 1387 1388 1389 /* 1390 * Do the conversion. 1391 */ 1392 size_t cArgs = 0; 1393 while (papszArgs[cArgs] != NULL) 1394 cArgs++; 1395 LogFunc(("Converting #%u arguments to %s...\n", cArgs, pszEncoding)); 1396 1397 char **papszArgsConverted = (char **)RTMemAllocZ(sizeof(papszArgsConverted[0]) * (cArgs + 2)); 1398 AssertReturn(papszArgsConverted, VERR_NO_MEMORY); 1399 1400 void *pvConversionCache = NULL; 1401 rtStrLocalCacheInit(&pvConversionCache); 1402 for (size_t i = 0; i < cArgs; i++) 1403 { 1404 int rc = rtStrLocalCacheConvert(papszArgs[i], strlen(papszArgs[i]), "UTF-8", 1405 &papszArgsConverted[i], 0, pszEncoding, &pvConversionCache); 1406 if (RT_SUCCESS(rc) && rc != VWRN_NO_TRANSLATION) 1407 { /* likely */ } 1408 else 1409 { 1410 Log(("Failed to convert argument #%u '%s' to '%s': %Rrc\n", i, papszArgs[i], pszEncoding, rc)); 1411 while (i-- > 0) 1412 RTStrFree(papszArgsConverted[i]); 1413 RTMemFree(papszArgsConverted); 1414 rtStrLocalCacheDelete(&pvConversionCache); 1415 return rc == VWRN_NO_TRANSLATION ? VERR_NO_TRANSLATION : rc; 1416 } 1417 } 1418 1419 rtStrLocalCacheDelete(&pvConversionCache); 1420 *ppapszArgs = papszArgsConverted; 1421 return VINF_SUCCESS; 1422 } 1423 1424 1425 /** 1426 * The result structure for rtPathFindExec/RTPathTraverseList. 1427 * @todo move to common path code? 1428 */ 1429 typedef struct RTPATHINTSEARCH 1430 { 1431 /** For EACCES or EPERM errors that we continued on. 1432 * @note Must be initialized to VINF_SUCCESS. */ 1433 int rcSticky; 1434 /** Buffer containing the filename. */ 1435 char szFound[RTPATH_MAX]; 1436 } RTPATHINTSEARCH; 1437 /** Pointer to a rtPathFindExec/RTPathTraverseList result. */ 1438 typedef RTPATHINTSEARCH *PRTPATHINTSEARCH; 1439 1440 1441 /** 1290 1442 * RTPathTraverseList callback used by RTProcCreateEx to locate the executable. 1291 1443 */ 1292 1444 static DECLCALLBACK(int) rtPathFindExec(char const *pchPath, size_t cchPath, void *pvUser1, void *pvUser2) 1293 1445 { 1294 const char *pszExec = (const char *)pvUser1; 1295 char *pszRealExec = (char *)pvUser2; 1296 int rc = RTPathJoinEx(pszRealExec, RTPATH_MAX, pchPath, cchPath, pszExec, RTSTR_MAX); 1297 if (RT_FAILURE(rc)) 1298 return rc; 1299 if (!access(pszRealExec, X_OK)) 1300 return VINF_SUCCESS; 1301 if ( errno == EACCES 1302 || errno == EPERM) 1303 return RTErrConvertFromErrno(errno); 1304 return VERR_TRY_AGAIN; 1446 const char *pszExec = (const char *)pvUser1; 1447 PRTPATHINTSEARCH pResult = (PRTPATHINTSEARCH)pvUser2; 1448 int rc = RTPathJoinEx(pResult->szFound, sizeof(pResult->szFound), pchPath, cchPath, pszExec, RTSTR_MAX); 1449 if (RT_SUCCESS(rc)) 1450 { 1451 const char *pszNativeExec = NULL; 1452 rc = rtPathToNative(&pszNativeExec, pResult->szFound, NULL); 1453 if (RT_SUCCESS(rc)) 1454 { 1455 if (!access(pszNativeExec, X_OK)) 1456 rc = VINF_SUCCESS; 1457 else 1458 { 1459 if ( errno == EACCES 1460 || errno == EPERM) 1461 pResult->rcSticky = RTErrConvertFromErrno(errno); 1462 rc = VERR_TRY_AGAIN; 1463 } 1464 rtPathFreeNative(pszNativeExec, pResult->szFound); 1465 } 1466 else 1467 AssertRCStmt(rc, rc = VERR_TRY_AGAIN /* don't stop on this, whatever it is */); 1468 } 1469 return rc; 1305 1470 } 1306 1471 … … 1456 1621 1457 1622 /* 1458 * Check for execute access to the file. 1459 */ 1460 char szRealExec[RTPATH_MAX]; 1461 if (access(pszExec, X_OK) == 0) 1462 rc = VINF_SUCCESS; 1463 else 1464 { 1465 rc = errno; 1466 if ( !(fFlags & RTPROC_FLAGS_SEARCH_PATH) 1467 || rc != ENOENT 1468 || RTPathHavePath(pszExec) ) 1469 rc = RTErrConvertFromErrno(rc); 1623 * Check for execute access to the file, searching the PATH if needed. 1624 */ 1625 const char *pszNativeExec = NULL; 1626 rc = rtPathToNative(&pszNativeExec, pszExec, NULL); 1627 if (RT_SUCCESS(rc)) 1628 { 1629 if (access(pszNativeExec, X_OK) == 0) 1630 rc = VINF_SUCCESS; 1470 1631 else 1471 1632 { 1472 /* search */ 1473 char *pszPath = RTEnvDupEx(hEnvToUse, "PATH"); 1474 rc = RTPathTraverseList(pszPath, ':', rtPathFindExec, (void *)pszExec, &szRealExec[0]); 1475 RTStrFree(pszPath); 1633 rc = errno; 1634 rtPathFreeNative(pszNativeExec, pszExec); 1635 1636 if ( !(fFlags & RTPROC_FLAGS_SEARCH_PATH) 1637 || rc != ENOENT 1638 || RTPathHavePath(pszExec) ) 1639 rc = RTErrConvertFromErrno(rc); 1640 else 1641 { 1642 /* Search the PATH for it: */ 1643 char *pszPath = RTEnvDupEx(hEnvToUse, "PATH"); 1644 if (pszPath) 1645 { 1646 PRTPATHINTSEARCH pResult = (PRTPATHINTSEARCH)alloca(sizeof(*pResult)); 1647 pResult->rcSticky = VINF_SUCCESS; 1648 rc = RTPathTraverseList(pszPath, ':', rtPathFindExec, (void *)pszExec, pResult); 1649 RTStrFree(pszPath); 1650 if (RT_SUCCESS(rc)) 1651 { 1652 /* Found it. Now, convert to native path: */ 1653 pszExec = pResult->szFound; 1654 rc = rtPathToNative(&pszNativeExec, pszExec, NULL); 1655 } 1656 else 1657 rc = rc != VERR_END_OF_STRING ? rc 1658 : pResult->rcSticky == VINF_SUCCESS ? VERR_FILE_NOT_FOUND : pResult->rcSticky; 1659 } 1660 else 1661 rc = VERR_NO_STR_MEMORY; 1662 } 1663 } 1664 if (RT_SUCCESS(rc)) 1665 { 1666 /* 1667 * Convert arguments to child codeset if necessary. 1668 */ 1669 char **papszArgsConverted = (char **)papszArgs; 1670 if (!(fFlags & RTPROC_FLAGS_UTF8_ARGV)) 1671 rc = rtProcPosixConvertArgv(papszArgs, hEnvToUse, &papszArgsConverted); 1476 1672 if (RT_SUCCESS(rc)) 1477 pszExec = szRealExec; 1478 else 1479 rc = rc == VERR_END_OF_STRING ? VERR_FILE_NOT_FOUND : rc; 1480 } 1481 } 1482 if (RT_SUCCESS(rc)) 1483 { 1484 /* 1485 * The rest of the process creation is reused internally by 1486 * rtProcPosixCreateProfileEnv. 1487 */ 1488 rc = rtProcPosixCreateInner(pszExec, papszArgs, hEnv, hEnvToUse, fFlags, pszAsUser, uid, gid, 1489 RT_ELEMENTS(aStdFds), aStdFds, phProcess); 1673 { 1674 /* 1675 * The rest of the process creation is reused internally by rtProcPosixCreateProfileEnv. 1676 */ 1677 rc = rtProcPosixCreateInner(pszNativeExec, papszArgsConverted, hEnv, hEnvToUse, fFlags, pszAsUser, uid, gid, 1678 RT_ELEMENTS(aStdFds), aStdFds, phProcess); 1679 1680 } 1681 1682 /* Free the translated argv copy, if needed. */ 1683 if (papszArgsConverted != (char **)papszArgs) 1684 { 1685 for (size_t i = 0; papszArgsConverted[i] != NULL; i++) 1686 RTStrFree(papszArgsConverted[i]); 1687 RTMemFree(papszArgsConverted); 1688 } 1689 rtPathFreeNative(pszNativeExec, pszExec); 1690 } 1490 1691 } 1491 1692 if (hEnvToUse != hEnv) … … 1501 1702 * 1502 1703 * @returns IPRT status code. 1503 * @param pszExec The executable to run (absolute path, X_OK). 1504 * @param papszArgs The arguments. 1505 * @param hEnv The original enviornment request, needed for adjustments 1506 * if starting as different user. 1507 * @param hEnvToUse The environment we should use. 1508 * @param fFlags The process creation flags, RTPROC_FLAGS_XXX. 1509 * @param pszAsUser The user to start the process as, if requested. 1510 * @param uid The UID corrsponding to @a pszAsUser, ~0 if NULL. 1511 * @param gid The GID corrsponding to @a pszAsUser, ~0 if NULL. 1512 * @param cRedirFds Number of redirection file descriptors. 1513 * @param paRedirFds Pointer to redirection file descriptors. Entries 1514 * containing -1 are not modified (inherit from parent), 1515 * -2 indicates that the descriptor should be closed in the 1516 * child. 1517 * @param phProcess Where to return the process ID on success. 1704 * @param pszNativeExec The executable to run (absolute path, X_OK). 1705 * Native path. 1706 * @param papszArgs The arguments. Caller has done codeset conversions. 1707 * @param hEnv The original enviornment request, needed for 1708 * adjustments if starting as different user. 1709 * @param hEnvToUse The environment we should use. 1710 * @param fFlags The process creation flags, RTPROC_FLAGS_XXX. 1711 * @param pszAsUser The user to start the process as, if requested. 1712 * @param uid The UID corrsponding to @a pszAsUser, ~0 if NULL. 1713 * @param gid The GID corrsponding to @a pszAsUser, ~0 if NULL. 1714 * @param cRedirFds Number of redirection file descriptors. 1715 * @param paRedirFds Pointer to redirection file descriptors. Entries 1716 * containing -1 are not modified (inherit from parent), 1717 * -2 indicates that the descriptor should be closed in the 1718 * child. 1719 * @param phProcess Where to return the process ID on success. 1518 1720 */ 1519 static int rtProcPosixCreateInner(const char *psz Exec, const char * const *papszArgs, RTENV hEnv, RTENV hEnvToUse,1721 static int rtProcPosixCreateInner(const char *pszNativeExec, const char * const *papszArgs, RTENV hEnv, RTENV hEnvToUse, 1520 1722 uint32_t fFlags, const char *pszAsUser, uid_t uid, gid_t gid, 1521 1723 unsigned cRedirFds, int *paRedirFds, PRTPROCESS phProcess) … … 1679 1881 1680 1882 if (!rc) 1681 rc = posix_spawn(&pid, psz Exec, pFileActions, &Attr, (char * const *)papszArgs,1883 rc = posix_spawn(&pid, pszNativeExec, pFileActions, &Attr, (char * const *)papszArgs, 1682 1884 (char * const *)papszEnv); 1683 1885 … … 1826 2028 * Finally, execute the requested program. 1827 2029 */ 1828 rc = execve(psz Exec, (char * const *)papszArgs, (char * const *)papszEnv);2030 rc = execve(pszNativeExec, (char * const *)papszArgs, (char * const *)papszEnv); 1829 2031 if (errno == ENOEXEC) 1830 2032 { -
trunk/src/VBox/Runtime/r3/posix/utf8-posix.cpp
r82968 r92671 34 34 #include <iprt/alloc.h> 35 35 #include <iprt/assert.h> 36 #include <iprt/ctype.h> 36 37 #include <iprt/err.h> 37 38 #include <iprt/string.h> … … 108 109 return nl_langinfo(CODESET); 109 110 } 111 112 113 /** 114 * Checks if the codeset specified by current locale (LC_CTYPE) is UTF-8. 115 * 116 * @returns true if UTF-8, false if not. 117 */ 118 DECLHIDDEN(bool) rtStrIsLocaleCodesetUtf8(void) 119 { 120 return rtStrIsCodesetUtf8(rtStrGetLocaleCodeset()); 121 } 122 123 124 /** 125 * Checks if @a pszCodeset specified UTF-8. 126 * 127 * @returns true if UTF-8, false if not. 128 * @param pszCodeset Codeset to test. 129 */ 130 DECLHIDDEN(bool) rtStrIsCodesetUtf8(const char *pszCodeset) 131 { 132 if (pszCodeset) 133 { 134 /* Skip leading spaces just in case: */ 135 while (RT_C_IS_SPACE(*pszCodeset)) 136 pszCodeset++; 137 138 /* If prefixed by 'ISO-10646/' skip that (iconv access this, dunno about 139 LC_CTYPE et al., but play it safe): */ 140 if ( strncmp(pszCodeset, RT_STR_TUPLE("ISO-10646/")) == 0 141 || strncmp(pszCodeset, RT_STR_TUPLE("iso-10646/")) == 0) 142 pszCodeset += sizeof("ISO-10646/") - 1; 143 144 /* Match 'utf': */ 145 if ( (pszCodeset[0] == 'u' || pszCodeset[0] == 'U') 146 && (pszCodeset[1] == 't' || pszCodeset[1] == 'T') 147 && (pszCodeset[2] == 'f' || pszCodeset[2] == 'F')) 148 { 149 pszCodeset += 3; 150 151 /* Treat the dash as optional: */ 152 if (*pszCodeset == '-') 153 pszCodeset++; 154 155 /* Match '8': */ 156 if (*pszCodeset == '8') 157 { 158 do 159 pszCodeset++; 160 while (RT_C_IS_SPACE(*pszCodeset)); 161 162 /* We ignore modifiers here (e.g. "[be_BY.]utf8@latin"). */ 163 if (!*pszCodeset || *pszCodeset == '@') 164 return true; 165 } 166 } 167 } 168 return false; 169 } 170 110 171 111 172 … … 475 536 476 537 538 /** 539 * Initializes a local conversion cache for use with rtStrLocalCacheConvert. 540 * 541 * Call rtStrLocalCacheDelete when done. 542 */ 543 DECLHIDDEN(void) rtStrLocalCacheInit(void **ppvTmpCache) 544 { 545 *ppvTmpCache = (iconv_t)-1; 546 } 547 548 549 /** 550 * Cleans up a local conversion cache. 551 */ 552 DECLHIDDEN(void) rtStrLocalCacheDelete(void **ppvTmpCache) 553 { 554 #ifdef RT_WITH_ICONV_CACHE 555 iconv_t icHandle = (iconv_t)*ppvTmpCache; 556 if (icHandle != (iconv_t)-1) 557 iconv_close(icHandle); 558 #endif 559 *ppvTmpCache = (iconv_t)-1; 560 } 561 562 563 /** 564 * Internal API for use by the process creation conversion code. 565 * 566 * @returns IPRT status code. 567 * 568 * @param pszInput Pointer to intput string. 569 * @param cchInput Size (in bytes) of input string. Excludes any 570 * terminators. 571 * @param pszInputCS Codeset of the input string. 572 * @param ppszOutput Pointer to pointer to output buffer if cbOutput > 0. 573 * If cbOutput is 0 this is where the pointer to the 574 * allocated buffer is stored. 575 * @param cbOutput Size of the passed in buffer. 576 * @param pszOutputCS Codeset of the input string. 577 * @param ppvTmpCache Pointer to local temporary cache. Must be 578 * initialized by calling rtStrLocalCacheInit and 579 * cleaned up afterwards by rtStrLocalCacheDelete. 580 * Optional. 581 */ 582 DECLHIDDEN(int) rtStrLocalCacheConvert(const char *pchInput, size_t cchInput, const char *pszInputCS, 583 char **ppszOutput, size_t cbOutput, const char *pszOutputCS, 584 void **ppvTmpCache) 585 { 586 #ifdef RT_WITH_ICONV_CACHE 587 if (ppvTmpCache) 588 return rtstrConvertCached(pchInput, cchInput, pszInputCS, (void **)ppszOutput, cbOutput, pszOutputCS, 589 1 /*cFactor*/, (iconv_t *)ppvTmpCache); 590 #else 591 RT_NOREF(ppvTmpCache); 592 #endif 593 594 return rtStrConvertUncached(pchInput, cchInput, pszInputCS, (void **)ppszOutput, cbOutput, pszOutputCS, 1 /*cFactor*/); 595 } 596 597 477 598 RTR3DECL(int) RTStrUtf8ToCurrentCPTag(char **ppszString, const char *pszString, const char *pszTag) 478 599 {
Note:
See TracChangeset
for help on using the changeset viewer.