1111#include <fcntl.h>
1212#include <errno.h>
1313#include <sys/wait.h>
14+ #include <spawn.h>
1415
1516#if defined(__FreeBSD__ ) || defined(__APPLE__ )
1617 #include <sys/types.h>
3334 #include <image.h>
3435#endif
3536
37+ #ifndef environ
38+ extern char * * environ ;
39+ #endif
40+
3641enum { FF_PIPE_BUFSIZ = 8192 };
3742
3843static inline int ffPipe2 (int * fds , int flags )
@@ -56,27 +61,38 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
5661 if (ffPipe2 (pipes , O_CLOEXEC ) == -1 )
5762 return "pipe() failed" ;
5863
59- pid_t childPid = fork ();
60- if (childPid == -1 )
61- {
62- close (pipes [0 ]);
63- close (pipes [1 ]);
64- return "fork() failed" ;
65- }
64+ posix_spawn_file_actions_t file_actions ;
65+ posix_spawn_file_actions_init (& file_actions );
66+ posix_spawn_file_actions_adddup2 (& file_actions , pipes [1 ], useStdErr ? STDERR_FILENO : STDOUT_FILENO );
67+ posix_spawn_file_actions_addopen (& file_actions , useStdErr ? STDOUT_FILENO : STDERR_FILENO , "/dev/null" , O_WRONLY , 0 );
68+ pid_t childPid = -1 ;
6669
67- //Child
68- if (childPid == 0 )
70+ char * oldLang = NULL ;
71+ int langIndex = -1 ;
72+ for (int i = 0 ; environ [i ] != NULL ; i ++ )
6973 {
70- int nullFile = open ("/dev/null" , O_WRONLY | O_CLOEXEC );
71- dup2 (pipes [1 ], useStdErr ? STDERR_FILENO : STDOUT_FILENO );
72- dup2 (nullFile , useStdErr ? STDOUT_FILENO : STDERR_FILENO );
73- setenv ("LANG" , "C" , 1 );
74- execvp (argv [0 ], argv );
75- _exit (127 );
74+ if (ffStrStartsWith (environ [i ], "LANG=" ))
75+ {
76+ oldLang = environ [i ];
77+ environ [i ] = (char * ) "LANG=C" ;
78+ langIndex = i ;
79+ break ;
80+ }
7681 }
7782
78- //Parent
83+ int ret = posix_spawnp (& childPid , argv [0 ], & file_actions , NULL , argv , environ );
84+
85+ if (oldLang )
86+ environ [langIndex ] = oldLang ;
87+
88+ posix_spawn_file_actions_destroy (& file_actions );
89+
7990 close (pipes [1 ]);
91+ if (ret != 0 )
92+ {
93+ close (pipes [0 ]);
94+ return "posix_spawnp() failed" ;
95+ }
8096
8197 int FF_AUTO_CLOSE_FD childPipeFd = pipes [0 ];
8298 char str [FF_PIPE_BUFSIZ ];
@@ -86,20 +102,30 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
86102 if (timeout >= 0 )
87103 {
88104 struct pollfd pollfd = { childPipeFd , POLLIN , 0 };
89- if (poll (& pollfd , 1 , timeout ) == 0 )
105+ int pollret = poll (& pollfd , 1 , timeout );
106+ if (pollret == 0 )
90107 {
91108 kill (childPid , SIGTERM );
92109 waitpid (childPid , NULL , 0 );
93110 return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)" ;
94111 }
95- else if (errno == EINTR )
112+ else if (pollret < 0 )
96113 {
97- // The child process has been terminated. See `chldSignalHandler` in `common/init.c`
98- if (waitpid (childPid , NULL , WNOHANG ) == childPid )
114+ if (errno == EINTR )
115+ {
116+ // The child process has been terminated. See `chldSignalHandler` in `common/init.c`
117+ if (waitpid (childPid , NULL , WNOHANG ) == childPid )
118+ {
119+ // Read remaining data from the pipe
120+ fcntl (childPipeFd , F_SETFL , O_CLOEXEC | O_NONBLOCK );
121+ childPid = -1 ;
122+ }
123+ }
124+ else
99125 {
100- // Read remaining data from the pipe
101- fcntl ( childPipeFd , F_SETFL , O_CLOEXEC | O_NONBLOCK );
102- childPid = -1 ;
126+ kill ( childPid , SIGTERM );
127+ waitpid ( childPid , NULL , 0 );
128+ return "poll(&pollfd, 1, timeout) error" ;
103129 }
104130 }
105131 else if (pollfd .revents & POLLERR )
0 commit comments