36
36
#include <fcntl.h>
37
37
#endif
38
38
39
+ #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP
40
+ /* Only defined on glibc >= 2.29, FreeBSD CURRENT, musl >= 1.1.24,
41
+ * MacOS Catalina or later..
42
+ * It should be posible to modify this so it is also
43
+ * used in older systems when $cwd == NULL but care must be taken
44
+ * as at least glibc < 2.24 has a legacy implementation known
45
+ * to be really buggy.
46
+ */
47
+ #include <spawn.h>
48
+ #define USE_POSIX_SPAWN
49
+ #endif
50
+
39
51
/* This symbol is defined in ext/standard/config.m4.
40
52
* Essentially, it is set if you HAVE_FORK || PHP_WIN32
41
53
* Other platforms may modify that configure check and add suitable #ifdefs
@@ -954,6 +966,36 @@ static zend_result set_proc_descriptor_from_resource(zval *resource, descriptors
954
966
}
955
967
956
968
#ifndef PHP_WIN32
969
+ #if defined(USE_POSIX_SPAWN )
970
+ static zend_result close_parentends_of_pipes (posix_spawn_file_actions_t * actions , descriptorspec_item * descriptors , int ndesc )
971
+ {
972
+ int r ;
973
+ for (int i = 0 ; i < ndesc ; i ++ ) {
974
+ if (descriptors [i ].type != DESCRIPTOR_TYPE_STD ) {
975
+ r = posix_spawn_file_actions_addclose (actions , descriptors [i ].parentend );
976
+ if (r != 0 ) {
977
+ php_error_docref (NULL , E_WARNING , "Cannot close file descriptor %d: %s" , descriptors [i ].parentend , strerror (r ));
978
+ return FAILURE ;
979
+ }
980
+ }
981
+ if (descriptors [i ].childend != descriptors [i ].index ) {
982
+ r = posix_spawn_file_actions_adddup2 (actions , descriptors [i ].childend , descriptors [i ].index );
983
+ if (r != 0 ) {
984
+ php_error_docref (NULL , E_WARNING , "Unable to copy file descriptor %d (for pipe) into "
985
+ "file descriptor %d: %s" , descriptors [i ].childend , descriptors [i ].index , strerror (r ));
986
+ return FAILURE ;
987
+ }
988
+ r = posix_spawn_file_actions_addclose (actions , descriptors [i ].childend );
989
+ if (r != 0 ) {
990
+ php_error_docref (NULL , E_WARNING , "Cannot close file descriptor %d: %s" , descriptors [i ].childend , strerror (r ));
991
+ return FAILURE ;
992
+ }
993
+ }
994
+ }
995
+
996
+ return SUCCESS ;
997
+ }
998
+ #else
957
999
static zend_result close_parentends_of_pipes (descriptorspec_item * descriptors , int ndesc )
958
1000
{
959
1001
/* We are running in child process
@@ -977,6 +1019,7 @@ static zend_result close_parentends_of_pipes(descriptorspec_item *descriptors, i
977
1019
return SUCCESS ;
978
1020
}
979
1021
#endif
1022
+ #endif
980
1023
981
1024
static void close_all_descriptors (descriptorspec_item * descriptors , int ndesc )
982
1025
{
@@ -1188,6 +1231,35 @@ PHP_FUNCTION(proc_open)
1188
1231
childHandle = pi .hProcess ;
1189
1232
child = pi .dwProcessId ;
1190
1233
CloseHandle (pi .hThread );
1234
+ #elif defined(USE_POSIX_SPAWN )
1235
+ posix_spawn_file_actions_t factions ;
1236
+ int r ;
1237
+ posix_spawn_file_actions_init (& factions );
1238
+
1239
+ if (close_parentends_of_pipes (& factions , descriptors , ndesc ) == FAILURE ) {
1240
+ posix_spawn_file_actions_destroy (& factions );
1241
+ close_all_descriptors (descriptors , ndesc );
1242
+ goto exit_fail ;
1243
+ }
1244
+
1245
+ if (cwd ) {
1246
+ /* This can fail only at spawn time */
1247
+ php_ignore_value (posix_spawn_file_actions_addchdir_np (& factions , cwd ));
1248
+ }
1249
+
1250
+ if (argv ) {
1251
+ r = posix_spawnp (& child , ZSTR_VAL (command_str ), & factions , NULL , argv , (env .envarray ? env .envarray : environ ));
1252
+ } else {
1253
+ r = posix_spawn (& child , "/bin/sh" , & factions , NULL ,
1254
+ (char * const []) {"sh" , "-c" , ZSTR_VAL (command_str ), NULL },
1255
+ env .envarray ? env .envarray : environ );
1256
+ }
1257
+ posix_spawn_file_actions_destroy (& factions );
1258
+ if (r != 0 ) {
1259
+ close_all_descriptors (descriptors , ndesc );
1260
+ php_error_docref (NULL , E_WARNING , "posix_spawn() failed: %s" , strerror (r ));
1261
+ goto exit_fail ;
1262
+ }
1191
1263
#elif HAVE_FORK
1192
1264
/* the Unix way */
1193
1265
child = fork ();
0 commit comments