@@ -1546,4 +1546,374 @@ CF_CROSS_PLATFORM_EXPORT void *_CFReallocf(void *ptr, size_t size) {
1546
1546
#endif
1547
1547
}
1548
1548
1549
+ #if TARGET_OS_ANDROID
1550
+
1551
+ #include <dlfcn.h>
1552
+ #include <spawn.h>
1553
+
1554
+ // Android doesn't provide posix_spawn APIs until recent API level, so we cannot
1555
+ // depend on them, but we can imitate the API, and perform the same work.
1556
+
1557
+ static pthread_once_t posixSpawnOnce = PTHREAD_ONCE_INIT ;
1558
+ static _CFPosixSpawnFileActionsRef (* _CFPosixSpawnFileActionsAllocImpl )(void );
1559
+ static int (* _CFPosixSpawnFileActionsInitImpl )(_CFPosixSpawnFileActionsRef );
1560
+ static int (* _CFPosixSpawnFileActionsDestroyImpl )(_CFPosixSpawnFileActionsRef );
1561
+ static void (* _CFPosixSpawnFileActionsDeallocImpl )(_CFPosixSpawnFileActionsRef );
1562
+ static int (* _CFPosixSpawnFileActionsAddDup2Impl )(_CFPosixSpawnFileActionsRef , int , int );
1563
+ static int (* _CFPosixSpawnFileActionsAddCloseImpl )(_CFPosixSpawnFileActionsRef , int );
1564
+ static int (* _CFPosixSpawnImpl )(pid_t * _CF_RESTRICT , const char * _CF_RESTRICT , _CFPosixSpawnFileActionsRef , _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT , char * _Nullable const [_Nullable _CF_RESTRICT ], char * _Nullable const [_Nullable _CF_RESTRICT ]);
1565
+
1566
+ static _CFPosixSpawnFileActionsRef _CFPosixSpawnFileActionsAllocImplPost28 () {
1567
+ _CFPosixSpawnFileActionsRef actions = malloc (sizeof (posix_spawn_file_actions_t ));
1568
+ CFAssert (actions != NULL , __kCFLogAssertion , "malloc failed" );
1569
+ return actions ;
1570
+ }
1571
+
1572
+ static void _CFPosixSpawnFileActionsDeallocImplBoth (_CFPosixSpawnFileActionsRef file_actions ) {
1573
+ free (file_actions );
1574
+ }
1575
+
1576
+ enum _CFPosixSpawnFileActionTypePre28 {
1577
+ _CFPosixSpawnFileActionDup2Pre28 ,
1578
+ _CFPosixSpawnFileActionClosePre28 ,
1579
+ };
1580
+
1581
+ struct _CFPosixSpawnFileActionPre28 {
1582
+ enum _CFPosixSpawnFileActionTypePre28 type ;
1583
+ union {
1584
+ struct {
1585
+ int filedes ;
1586
+ int newfiledes ;
1587
+ } dup2Action ;
1588
+ struct {
1589
+ int filedes ;
1590
+ } closeAction ;
1591
+ };
1592
+ };
1593
+
1594
+ struct _CFPosixSpawnFileActionsPre28 {
1595
+ struct _CFPosixSpawnFileActionPre28 * actions ;
1596
+ size_t actionsCount ;
1597
+ size_t actionsCapacity ;
1598
+ int32_t isValid ;
1599
+ };
1600
+
1601
+ static const int32_t _CFPosixSpawnFileActionsPre28Valid = 0x600D600D ;
1602
+
1603
+ static _CFPosixSpawnFileActionsRef _CFPosixSpawnFileActionsAllocImplPre28 () {
1604
+ _CFPosixSpawnFileActionsRef actions = calloc (1 , sizeof (struct _CFPosixSpawnFileActionsPre28 ));
1605
+ CFAssert (actions != NULL , __kCFLogAssertion , "malloc failed" );
1606
+ return actions ;
1607
+ }
1608
+
1609
+ static int _CFPosixSpawnFileActionsInitImplPre28 (_CFPosixSpawnFileActionsRef file_actions ) {
1610
+ if (file_actions == NULL ) {
1611
+ return EINVAL ;
1612
+ }
1613
+
1614
+ struct _CFPosixSpawnFileActionsPre28 * actions = (struct _CFPosixSpawnFileActionsPre28 * )file_actions ;
1615
+
1616
+ actions -> actions = malloc (8 * sizeof (struct _CFPosixSpawnFileActionPre28 ));
1617
+ if (actions -> actions == NULL ) {
1618
+ return ENOMEM ;
1619
+ }
1620
+ actions -> actionsCount = 0 ;
1621
+ actions -> actionsCapacity = 8 ;
1622
+
1623
+ actions -> isValid = _CFPosixSpawnFileActionsPre28Valid ;
1624
+
1625
+ return 0 ;
1626
+ }
1627
+
1628
+ static int _CFPosixSpawnFileActionsDestroyImplPre28 (_CFPosixSpawnFileActionsRef file_actions ) {
1629
+ if (file_actions == NULL ) {
1630
+ return EINVAL ;
1631
+ }
1632
+
1633
+ struct _CFPosixSpawnFileActionsPre28 * actions = (struct _CFPosixSpawnFileActionsPre28 * )file_actions ;
1634
+ if (actions -> isValid != _CFPosixSpawnFileActionsPre28Valid ) {
1635
+ return EINVAL ;
1636
+ }
1637
+
1638
+ free (actions -> actions );
1639
+ actions -> actionsCount = 0 ;
1640
+ actions -> actionsCapacity = 0 ;
1641
+
1642
+ actions -> isValid = 0 ;
1643
+
1644
+ return 0 ;
1645
+ }
1646
+
1647
+ static int _CFPosixSpawnFileActionsAddDup2ImplPre28 (_CFPosixSpawnFileActionsRef file_actions , int filedes , int newfiledes ) {
1648
+ if (file_actions == NULL ) {
1649
+ return EINVAL ;
1650
+ }
1651
+
1652
+ if (filedes < 0 || newfiledes < 0 ) {
1653
+ return EBADF ;
1654
+ }
1655
+
1656
+ struct _CFPosixSpawnFileActionsPre28 * actions = (struct _CFPosixSpawnFileActionsPre28 * )file_actions ;
1657
+ if (actions -> isValid != _CFPosixSpawnFileActionsPre28Valid ) {
1658
+ return EINVAL ;
1659
+ }
1660
+
1661
+ if (actions -> actionsCount == actions -> actionsCapacity ) {
1662
+ struct _CFPosixSpawnFileActionPre28 * newActions = realloc (actions -> actions , actions -> actionsCapacity * 2 );
1663
+ if (newActions == NULL ) {
1664
+ return ENOMEM ;
1665
+ }
1666
+ actions -> actions = newActions ;
1667
+ actions -> actionsCapacity *= 2 ;
1668
+ }
1669
+
1670
+ actions -> actions [actions -> actionsCount ++ ] = (struct _CFPosixSpawnFileActionPre28 ) {
1671
+ .type = _CFPosixSpawnFileActionDup2Pre28 ,
1672
+ .dup2Action = {
1673
+ .filedes = filedes ,
1674
+ .newfiledes = newfiledes
1675
+ }
1676
+ };
1677
+
1678
+ return 0 ;
1679
+ }
1680
+
1681
+ static int _CFPosixSpawnFileActionsAddCloseImplPre28 (_CFPosixSpawnFileActionsRef file_actions , int filedes ) {
1682
+ if (file_actions == NULL ) {
1683
+ return EINVAL ;
1684
+ }
1685
+
1686
+ if (filedes < 0 ) {
1687
+ return EBADF ;
1688
+ }
1689
+
1690
+ struct _CFPosixSpawnFileActionsPre28 * actions = (struct _CFPosixSpawnFileActionsPre28 * )file_actions ;
1691
+ if (actions -> isValid != _CFPosixSpawnFileActionsPre28Valid ) {
1692
+ return EINVAL ;
1693
+ }
1694
+
1695
+ if (actions -> actionsCount == actions -> actionsCapacity ) {
1696
+ struct _CFPosixSpawnFileActionPre28 * newActions = realloc (actions -> actions , actions -> actionsCapacity * 2 );
1697
+ if (newActions == NULL ) {
1698
+ return ENOMEM ;
1699
+ }
1700
+ actions -> actions = newActions ;
1701
+ actions -> actionsCapacity *= 2 ;
1702
+ }
1703
+
1704
+ actions -> actions [actions -> actionsCount ++ ] = (struct _CFPosixSpawnFileActionPre28 ) {
1705
+ .type = _CFPosixSpawnFileActionClosePre28 ,
1706
+ .closeAction = {
1707
+ .filedes = filedes
1708
+ }
1709
+ };
1710
+
1711
+ return 0 ;
1712
+ }
1713
+
1714
+ static int _CFPosixSpawnImplPre28 (pid_t * _CF_RESTRICT pid , const char * _CF_RESTRICT path , _CFPosixSpawnFileActionsRef file_actions , _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT attrp , char * _Nullable const argv [_Nullable _CF_RESTRICT ], char * _Nullable const envp [_Nullable _CF_RESTRICT ]) {
1715
+ // TODO: We completely ignore attrp, because at the moment, the only
1716
+ // invocation doesn't pass a value.
1717
+ if (attrp != NULL ) {
1718
+ return EINVAL ;
1719
+ }
1720
+
1721
+ struct _CFPosixSpawnFileActionsPre28 * actions = (struct _CFPosixSpawnFileActionsPre28 * )file_actions ;
1722
+ if (actions != NULL && actions -> isValid != _CFPosixSpawnFileActionsPre28Valid ) {
1723
+ return EINVAL ;
1724
+ }
1725
+
1726
+ // Block signals during this fork/execv dance.
1727
+ sigset_t signalSet ;
1728
+ sigfillset (& signalSet );
1729
+ sigset_t oldMask ;
1730
+ if (sigprocmask (SIG_BLOCK , & signalSet , & oldMask ) != 0 ) {
1731
+ CFAssert1 (FALSE, __kCFLogAssertion , "sigprocmask() failed: %d" , errno );
1732
+ }
1733
+
1734
+ pid_t forkPid = fork ();
1735
+ if (forkPid != 0 ) {
1736
+ // This is the parent. fork call might have been successful or not.
1737
+
1738
+ // Unblock signals.
1739
+ if (sigprocmask (SIG_SETMASK , & oldMask , NULL ) != 0 ) {
1740
+ CFAssert1 (FALSE, __kCFLogAssertion , "sigprocmask() failed: %d" , errno );
1741
+ }
1742
+
1743
+ if (forkPid < 0 ) {
1744
+ return forkPid ;
1745
+ }
1746
+
1747
+ if (pid != NULL ) {
1748
+ * pid = forkPid ;
1749
+ }
1750
+
1751
+ return 0 ;
1752
+ }
1753
+
1754
+ // This is the child.
1755
+
1756
+ // Clean up the parent signal handlers
1757
+ for (int idx = 1 ; idx < NSIG ; idx ++ ) {
1758
+ // Seems that SIGKILL/SIGSTOP are sometimes silently ignored, and
1759
+ // sometimes return EINVAL. Since one cannot change the handlers anyway,
1760
+ // skip them.
1761
+ if (idx == SIGKILL || idx == SIGSTOP ) {
1762
+ continue ;
1763
+ }
1764
+
1765
+ struct sigaction sigAction ;
1766
+ if (sigaction (idx , NULL , & sigAction ) != 0 ) {
1767
+ exit (127 );
1768
+ }
1769
+
1770
+ if (sigAction .sa_handler != SIG_IGN ) {
1771
+ sigAction .sa_handler = SIG_DFL ;
1772
+ if (sigaction (idx , & sigAction , NULL ) != 0 ) {
1773
+ exit (127 );
1774
+ }
1775
+ }
1776
+ }
1777
+
1778
+ // Perform the actions
1779
+ if (actions != NULL ) {
1780
+ for (size_t idx = 0 ; idx < actions -> actionsCount ; idx ++ ) {
1781
+ struct _CFPosixSpawnFileActionPre28 * action = & (actions -> actions [idx ]);
1782
+ if (action -> type == _CFPosixSpawnFileActionDup2Pre28 ) {
1783
+ if (dup2 (action -> dup2Action .filedes , action -> dup2Action .newfiledes ) < 0 ) {
1784
+ exit (127 );
1785
+ }
1786
+ } else if (actions -> actions [idx ].type == _CFPosixSpawnFileActionClosePre28 ) {
1787
+ if (close (action -> closeAction .filedes ) != 0 ) {
1788
+ exit (127 );
1789
+ }
1790
+ }
1791
+ }
1792
+ }
1793
+
1794
+ // Unblock the signals
1795
+ if (sigprocmask (SIG_SETMASK , & oldMask , NULL ) != 0 ) {
1796
+ CFAssert1 (FALSE, __kCFLogAssertion , "sigprocmask() failed: %d" , errno );
1797
+ }
1798
+
1799
+ // If execv fails, we will simply exit 127 as the standard says.
1800
+ execve (path , argv , envp ?: environ );
1801
+ exit (127 );
1802
+ // no need for return here
1803
+ }
1804
+
1805
+ static void _CFPosixSpawnInitializeCallback () {
1806
+ // Let's check if the posix_spawn is present.
1807
+ (void )dlerror (); // Clean up the error.
1808
+ _CFPosixSpawnImpl = (int (* )(pid_t * _CF_RESTRICT , const char * _CF_RESTRICT , void * , void * _CF_RESTRICT , char * const * _CF_RESTRICT , char * const * _CF_RESTRICT ))dlsym (RTLD_DEFAULT , "posix_spawn" );
1809
+ char * dlsymError = dlerror ();
1810
+ CFAssert1 (dlsymError == NULL , __kCFLogAssertion , "dlsym failed: %s" , dlsymError );
1811
+ if (_CFPosixSpawnImpl != NULL ) {
1812
+ // posix_spawn_fn is available, so use it
1813
+ _CFPosixSpawnFileActionsAllocImpl = _CFPosixSpawnFileActionsAllocImplPost28 ;
1814
+ _CFPosixSpawnFileActionsDeallocImpl = _CFPosixSpawnFileActionsDeallocImplBoth ;
1815
+
1816
+ _CFPosixSpawnFileActionsInitImpl = (int (* )(void * ))dlsym (RTLD_DEFAULT , "posix_spawn_file_actions_init" );
1817
+ dlsymError = dlerror ();
1818
+ CFAssert1 (_CFPosixSpawnFileActionsInitImpl != NULL , __kCFLogAssertion , "loading posix_spawn_file_actions_init failed: %s" , dlsymError );
1819
+
1820
+ _CFPosixSpawnFileActionsDestroyImpl = (int (* )(void * ))dlsym (RTLD_DEFAULT , "posix_spawn_file_actions_destroy" );
1821
+ dlsymError = dlerror ();
1822
+ CFAssert1 (_CFPosixSpawnFileActionsDestroyImpl != NULL , __kCFLogAssertion , "loading posix_spawn_file_actions_destroy failed: %s" , dlsymError );
1823
+
1824
+ _CFPosixSpawnFileActionsAddDup2Impl = (int (* )(void * , int , int ))dlsym (RTLD_DEFAULT , "posix_spawn_file_actions_adddup2" );
1825
+ dlsymError = dlerror ();
1826
+ CFAssert1 (_CFPosixSpawnFileActionsAddDup2Impl != NULL , __kCFLogAssertion , "loading posix_spawn_file_actions_adddup2 failed: %s" , dlsymError );
1827
+
1828
+ _CFPosixSpawnFileActionsAddCloseImpl = (int (* )(void * , int ))dlsym (RTLD_DEFAULT , "posix_spawn_file_actions_addclose" );
1829
+ dlsymError = dlerror ();
1830
+ CFAssert1 (_CFPosixSpawnFileActionsAddCloseImpl != NULL , __kCFLogAssertion , "loading posix_spawn_file_actions_addclose failed: %s" , dlsymError );
1831
+ } else {
1832
+ // posix_spawn_fn is not available, setup our workaround
1833
+ _CFPosixSpawnFileActionsAllocImpl = _CFPosixSpawnFileActionsAllocImplPre28 ;
1834
+ _CFPosixSpawnFileActionsDeallocImpl = _CFPosixSpawnFileActionsDeallocImplBoth ;
1835
+ _CFPosixSpawnFileActionsInitImpl = _CFPosixSpawnFileActionsInitImplPre28 ;
1836
+ _CFPosixSpawnFileActionsDestroyImpl = _CFPosixSpawnFileActionsDestroyImplPre28 ;
1837
+ _CFPosixSpawnFileActionsAddDup2Impl = _CFPosixSpawnFileActionsAddDup2ImplPre28 ;
1838
+ _CFPosixSpawnFileActionsAddCloseImpl = _CFPosixSpawnFileActionsAddCloseImplPre28 ;
1839
+ _CFPosixSpawnImpl = _CFPosixSpawnImplPre28 ;
1840
+ }
1841
+ }
1842
+
1843
+ static void _CFPosixSpawnInitialize () {
1844
+ int r = pthread_once (& posixSpawnOnce , _CFPosixSpawnInitializeCallback );
1845
+ CFAssert (r == 0 , __kCFLogAssertion , "pthread_once failed" );
1846
+ }
1847
+
1848
+ CF_EXPORT _CFPosixSpawnFileActionsRef _CFPosixSpawnFileActionsAlloc () {
1849
+ _CFPosixSpawnInitialize ();
1850
+ return _CFPosixSpawnFileActionsAllocImpl ();
1851
+ }
1852
+
1853
+ CF_EXPORT int _CFPosixSpawnFileActionsInit (_CFPosixSpawnFileActionsRef file_actions ) {
1854
+ _CFPosixSpawnInitialize ();
1855
+ return _CFPosixSpawnFileActionsInitImpl (file_actions );
1856
+ }
1857
+
1858
+ CF_EXPORT int _CFPosixSpawnFileActionsDestroy (_CFPosixSpawnFileActionsRef file_actions ) {
1859
+ _CFPosixSpawnInitialize ();
1860
+ return _CFPosixSpawnFileActionsDestroyImpl (file_actions );
1861
+ }
1862
+
1863
+ CF_EXPORT void _CFPosixSpawnFileActionsDealloc (_CFPosixSpawnFileActionsRef file_actions ) {
1864
+ _CFPosixSpawnInitialize ();
1865
+ _CFPosixSpawnFileActionsDeallocImpl (file_actions );
1866
+ }
1867
+
1868
+ CF_EXPORT int _CFPosixSpawnFileActionsAddDup2 (_CFPosixSpawnFileActionsRef file_actions , int filedes , int newfiledes ) {
1869
+ _CFPosixSpawnInitialize ();
1870
+ return _CFPosixSpawnFileActionsAddDup2Impl (file_actions , filedes , newfiledes );
1871
+ }
1872
+
1873
+ CF_EXPORT int _CFPosixSpawnFileActionsAddClose (_CFPosixSpawnFileActionsRef file_actions , int filedes ) {
1874
+ _CFPosixSpawnInitialize ();
1875
+ return _CFPosixSpawnFileActionsAddCloseImpl (file_actions , filedes );
1876
+ }
1877
+
1878
+ CF_EXPORT int _CFPosixSpawn (pid_t * _CF_RESTRICT pid , const char * _CF_RESTRICT path , _CFPosixSpawnFileActionsRef file_actions , _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT attrp , char * _Nullable const argv [_Nullable _CF_RESTRICT ], char * _Nullable const envp [_Nullable _CF_RESTRICT ]) {
1879
+ _CFPosixSpawnInitialize ();
1880
+ return _CFPosixSpawnImpl (pid , path , file_actions , attrp , argv , envp );
1881
+ }
1882
+
1883
+ #elif !TARGET_OS_WIN32
1884
+
1885
+ #include <spawn.h>
1886
+
1887
+ CF_EXPORT _CFPosixSpawnFileActionsRef _CFPosixSpawnFileActionsAlloc () {
1888
+ _CFPosixSpawnFileActionsRef actions = malloc (sizeof (posix_spawn_file_actions_t ));
1889
+ CFAssert (actions != NULL , __kCFLogAssertion , "malloc failed" );
1890
+ return actions ;
1891
+ }
1892
+
1893
+ CF_EXPORT int _CFPosixSpawnFileActionsInit (_CFPosixSpawnFileActionsRef file_actions ) {
1894
+ return posix_spawn_file_actions_init ((posix_spawn_file_actions_t * )file_actions );
1895
+ }
1896
+
1897
+ CF_EXPORT int _CFPosixSpawnFileActionsDestroy (_CFPosixSpawnFileActionsRef file_actions ) {
1898
+ return posix_spawn_file_actions_destroy ((posix_spawn_file_actions_t * )file_actions );
1899
+ }
1900
+
1901
+ CF_EXPORT void _CFPosixSpawnFileActionsDealloc (_CFPosixSpawnFileActionsRef file_actions ) {
1902
+ free (file_actions );
1903
+ }
1904
+
1905
+ CF_EXPORT int _CFPosixSpawnFileActionsAddDup2 (_CFPosixSpawnFileActionsRef file_actions , int filedes , int newfiledes ) {
1906
+ return posix_spawn_file_actions_adddup2 ((posix_spawn_file_actions_t * )file_actions , filedes , newfiledes );
1907
+ }
1908
+
1909
+ CF_EXPORT int _CFPosixSpawnFileActionsAddClose (_CFPosixSpawnFileActionsRef file_actions , int filedes ) {
1910
+ return posix_spawn_file_actions_addclose ((posix_spawn_file_actions_t * )file_actions , filedes );
1911
+ }
1912
+
1913
+ CF_EXPORT int _CFPosixSpawn (pid_t * _CF_RESTRICT pid , const char * _CF_RESTRICT path , _CFPosixSpawnFileActionsRef file_actions , _CFPosixSpawnAttrRef _Nullable _CF_RESTRICT attrp , char * _Nullable const argv [_Nullable _CF_RESTRICT ], char * _Nullable const envp [_Nullable _CF_RESTRICT ]) {
1914
+ return posix_spawn (pid , path , (posix_spawn_file_actions_t * )file_actions , (posix_spawnattr_t * )attrp , argv , envp );
1915
+ }
1916
+
1917
+ #endif
1918
+
1549
1919
#endif
0 commit comments