4 * Copyright 1996-1998 Marcus Meissner
5 * Copyright 2018, 2020 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
40 #ifdef HAVE_SYS_TIME_H
41 # include <sys/time.h>
43 #ifdef HAVE_SYS_TIMES_H
44 # include <sys/times.h>
46 #include <sys/types.h>
47 #ifdef HAVE_SYS_WAIT_H
48 # include <sys/wait.h>
54 # include <CoreFoundation/CoreFoundation.h>
57 #ifdef HAVE_MACH_MACH_H
58 # include <mach/mach.h>
62 #define WIN32_NO_STATUS
65 #include "unix_private.h"
66 #include "wine/exception.h"
67 #include "wine/server.h"
68 #include "wine/debug.h"
71 static char **build_argv( const UNICODE_STRING
*cmdline
, int reserved
)
73 char **argv
, *arg
, *src
, *dst
;
74 int argc
, in_quotes
= 0, bcount
= 0, len
= cmdline
->Length
/ sizeof(WCHAR
);
76 if (!(src
= malloc( len
* 3 + 1 ))) return NULL
;
77 len
= ntdll_wcstoumbs( cmdline
->Buffer
, len
, src
, len
* 3, FALSE
);
80 argc
= reserved
+ 2 + len
/ 2;
81 argv
= malloc( argc
* sizeof(*argv
) + len
);
82 arg
= dst
= (char *)(argv
+ argc
);
86 if ((*src
== ' ' || *src
== '\t') && !in_quotes
)
88 /* skip the remaining spaces */
89 while (*src
== ' ' || *src
== '\t') src
++;
91 /* close the argument and copy it */
94 /* start with a new argument */
98 else if (*src
== '\\')
103 else if (*src
== '"')
105 if ((bcount
& 1) == 0)
107 /* Preceded by an even number of '\', this is half that
108 * number of '\', plus a '"' which we discard.
112 if (in_quotes
&& *src
== '"') *dst
++ = *src
++;
113 else in_quotes
= !in_quotes
;
117 /* Preceded by an odd number of '\', this is half that
118 * number of '\' followed by a '"'
120 dst
-= bcount
/ 2 + 1;
125 else /* a regular character */
139 /***********************************************************************
140 * terminate_main_thread
142 * On some versions of Mac OS X, the execve system call fails with
143 * ENOTSUP if the process has multiple threads. Wine is always multi-
144 * threaded on Mac OS X because it specifically reserves the main thread
145 * for use by the system frameworks (see apple_main_thread() in
146 * libs/wine/loader.c). So, when we need to exec without first forking,
147 * we need to terminate the main thread first. We do this by installing
148 * a custom run loop source onto the main run loop and signaling it.
149 * The source's "perform" callback is pthread_exit and it will be
150 * executed on the main thread, terminating it.
152 * Returns TRUE if there's still hope the main thread has terminated or
153 * will soon. Return FALSE if we've given up.
155 static BOOL
terminate_main_thread(void)
161 CFRunLoopSourceContext source_context
= { 0 };
162 CFRunLoopSourceRef source
;
164 source_context
.perform
= pthread_exit
;
165 if (!(source
= CFRunLoopSourceCreate( NULL
, 0, &source_context
)))
168 CFRunLoopAddSource( CFRunLoopGetMain(), source
, kCFRunLoopCommonModes
);
169 CFRunLoopSourceSignal( source
);
170 CFRunLoopWakeUp( CFRunLoopGetMain() );
179 usleep(delayms
* 1000);
187 /***********************************************************************
190 static void set_stdio_fd( int stdin_fd
, int stdout_fd
)
194 if (stdin_fd
== -1 || stdout_fd
== -1)
196 fd
= open( "/dev/null", O_RDWR
);
197 if (stdin_fd
== -1) stdin_fd
= fd
;
198 if (stdout_fd
== -1) stdout_fd
= fd
;
202 dup2( stdout_fd
, 1 );
203 if (fd
!= -1) close( fd
);
207 /***********************************************************************
210 NTSTATUS CDECL
spawn_process( const RTL_USER_PROCESS_PARAMETERS
*params
, int socketfd
,
211 const char *unixdir
, char *winedebug
, const pe_image_info_t
*pe_info
)
213 const int is_child_64bit
= (pe_info
->cpu
== CPU_x86_64
|| pe_info
->cpu
== CPU_ARM64
);
214 NTSTATUS status
= STATUS_SUCCESS
;
215 int stdin_fd
= -1, stdout_fd
= -1;
219 server_handle_to_fd( params
->hStdInput
, FILE_READ_DATA
, &stdin_fd
, NULL
);
220 server_handle_to_fd( params
->hStdOutput
, FILE_WRITE_DATA
, &stdout_fd
, NULL
);
222 if (!(pid
= fork())) /* child */
224 if (!(pid
= fork())) /* grandchild */
226 if (params
->ConsoleFlags
||
227 params
->ConsoleHandle
== (HANDLE
)1 /* KERNEL32_CONSOLE_ALLOC */ ||
228 (params
->hStdInput
== INVALID_HANDLE_VALUE
&& params
->hStdOutput
== INVALID_HANDLE_VALUE
))
231 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
233 else set_stdio_fd( stdin_fd
, stdout_fd
);
235 if (stdin_fd
!= -1) close( stdin_fd
);
236 if (stdout_fd
!= -1) close( stdout_fd
);
238 if (winedebug
) putenv( winedebug
);
239 if (unixdir
) chdir( unixdir
);
241 argv
= build_argv( ¶ms
->CommandLine
, 2 );
243 exec_wineloader( argv
, socketfd
, is_child_64bit
,
244 pe_info
->base
, pe_info
->base
+ pe_info
->map_size
);
256 wret
= waitpid(pid
, NULL
, 0);
257 } while (wret
< 0 && errno
== EINTR
);
259 else status
= STATUS_NO_MEMORY
;
261 if (stdin_fd
!= -1) close( stdin_fd
);
262 if (stdout_fd
!= -1) close( stdout_fd
);
267 /***********************************************************************
270 NTSTATUS CDECL
exec_process( const UNICODE_STRING
*cmdline
, const pe_image_info_t
*pe_info
)
272 const int is_child_64bit
= (pe_info
->cpu
== CPU_x86_64
|| pe_info
->cpu
== CPU_ARM64
);
277 if (socketpair( PF_UNIX
, SOCK_STREAM
, 0, socketfd
) == -1) return STATUS_TOO_MANY_OPENED_FILES
;
282 setsockopt( socketfd
[0], SOL_SOCKET
, SO_PASSCRED
, &enable
, sizeof(enable
) );
285 server_send_fd( socketfd
[1] );
286 close( socketfd
[1] );
288 SERVER_START_REQ( exec_process
)
290 req
->socket_fd
= socketfd
[1];
291 req
->cpu
= pe_info
->cpu
;
292 status
= wine_server_call( req
);
298 if (!(argv
= build_argv( cmdline
, 2 ))) return STATUS_NO_MEMORY
;
301 status
= exec_wineloader( argv
, socketfd
[0], is_child_64bit
,
302 pe_info
->base
, pe_info
->base
+ pe_info
->map_size
);
305 while (errno
== ENOTSUP
&& terminate_main_thread());
311 close( socketfd
[0] );
316 /***********************************************************************
319 * Fork and exec a new Unix binary, checking for errors.
321 NTSTATUS CDECL
fork_and_exec( const char *unix_name
, const char *unix_dir
,
322 const RTL_USER_PROCESS_PARAMETERS
*params
)
325 int fd
[2], stdin_fd
= -1, stdout_fd
= -1;
330 if (pipe2( fd
, O_CLOEXEC
) == -1)
333 if (pipe(fd
) == -1) return STATUS_TOO_MANY_OPENED_FILES
;
334 fcntl( fd
[0], F_SETFD
, FD_CLOEXEC
);
335 fcntl( fd
[1], F_SETFD
, FD_CLOEXEC
);
338 server_handle_to_fd( params
->hStdInput
, FILE_READ_DATA
, &stdin_fd
, NULL
);
339 server_handle_to_fd( params
->hStdOutput
, FILE_WRITE_DATA
, &stdout_fd
, NULL
);
341 if (!(pid
= fork())) /* child */
343 if (!(pid
= fork())) /* grandchild */
347 if (params
->ConsoleFlags
||
348 params
->ConsoleHandle
== (HANDLE
)1 /* KERNEL32_CONSOLE_ALLOC */ ||
349 (params
->hStdInput
== INVALID_HANDLE_VALUE
&& params
->hStdOutput
== INVALID_HANDLE_VALUE
))
352 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
354 else set_stdio_fd( stdin_fd
, stdout_fd
);
356 if (stdin_fd
!= -1) close( stdin_fd
);
357 if (stdout_fd
!= -1) close( stdout_fd
);
359 /* Reset signals that we previously set to SIG_IGN */
360 signal( SIGPIPE
, SIG_DFL
);
362 argv
= build_argv( ¶ms
->CommandLine
, 0 );
363 envp
= build_envp( params
->Environment
);
364 if (unix_dir
) chdir( unix_dir
);
366 execve( unix_name
, argv
, envp
);
369 if (pid
<= 0) /* grandchild if exec failed or child if fork failed */
374 case EACCES
: status
= STATUS_ACCESS_DENIED
; break;
375 case ENOENT
: status
= STATUS_OBJECT_NAME_NOT_FOUND
; break;
377 case ENFILE
: status
= STATUS_TOO_MANY_OPENED_FILES
; break;
379 case EINVAL
: status
= STATUS_INVALID_IMAGE_FORMAT
; break;
380 default: status
= STATUS_NO_MEMORY
; break;
382 write( fd
[1], &status
, sizeof(status
) );
385 _exit(0); /* child if fork succeeded */
394 wret
= waitpid(pid
, NULL
, 0);
395 } while (wret
< 0 && errno
== EINTR
);
396 read( fd
[0], &status
, sizeof(status
) ); /* if we read something, exec or second fork failed */
398 else status
= STATUS_NO_MEMORY
;
401 if (stdin_fd
!= -1) close( stdin_fd
);
402 if (stdout_fd
!= -1) close( stdout_fd
);