ntdll: Include <signal.h> where needed in the Unix library.
[wine.git] / dlls / ntdll / unix / process.c
blob58ba03142190a356a3d4cd5fce73a1affe78b135
1 /*
2 * NT process handling
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
22 #if 0
23 #pragma makedep unix
24 #endif
26 #include "config.h"
27 #include "wine/port.h"
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <signal.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
39 #endif
40 #ifdef HAVE_SYS_TIME_H
41 # include <sys/time.h>
42 #endif
43 #ifdef HAVE_SYS_TIMES_H
44 # include <sys/times.h>
45 #endif
46 #include <sys/types.h>
47 #ifdef HAVE_SYS_WAIT_H
48 # include <sys/wait.h>
49 #endif
50 #ifdef HAVE_UNISTD_H
51 # include <unistd.h>
52 #endif
53 #ifdef __APPLE__
54 # include <CoreFoundation/CoreFoundation.h>
55 # include <pthread.h>
56 #endif
57 #ifdef HAVE_MACH_MACH_H
58 # include <mach/mach.h>
59 #endif
61 #include "ntstatus.h"
62 #define WIN32_NO_STATUS
63 #include "windef.h"
64 #include "winternl.h"
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 );
78 src[len++] = 0;
80 argc = reserved + 2 + len / 2;
81 argv = malloc( argc * sizeof(*argv) + len );
82 arg = dst = (char *)(argv + argc);
83 argc = reserved;
84 while (*src)
86 if ((*src == ' ' || *src == '\t') && !in_quotes)
88 /* skip the remaining spaces */
89 while (*src == ' ' || *src == '\t') src++;
90 if (!*src) break;
91 /* close the argument and copy it */
92 *dst++ = 0;
93 argv[argc++] = arg;
94 /* start with a new argument */
95 arg = dst;
96 bcount = 0;
98 else if (*src == '\\')
100 *dst++ = *src++;
101 bcount++;
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.
110 dst -= bcount / 2;
111 src++;
112 if (in_quotes && *src == '"') *dst++ = *src++;
113 else in_quotes = !in_quotes;
115 else
117 /* Preceded by an odd number of '\', this is half that
118 * number of '\' followed by a '"'
120 dst -= bcount / 2 + 1;
121 *dst++ = *src++;
123 bcount = 0;
125 else /* a regular character */
127 *dst++ = *src++;
128 bcount = 0;
131 *dst = 0;
132 argv[argc++] = arg;
133 argv[argc] = NULL;
134 return argv;
138 #ifdef __APPLE__
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)
157 static int delayms;
159 if (!delayms)
161 CFRunLoopSourceContext source_context = { 0 };
162 CFRunLoopSourceRef source;
164 source_context.perform = pthread_exit;
165 if (!(source = CFRunLoopSourceCreate( NULL, 0, &source_context )))
166 return FALSE;
168 CFRunLoopAddSource( CFRunLoopGetMain(), source, kCFRunLoopCommonModes );
169 CFRunLoopSourceSignal( source );
170 CFRunLoopWakeUp( CFRunLoopGetMain() );
171 CFRelease( source );
173 delayms = 20;
176 if (delayms > 1000)
177 return FALSE;
179 usleep(delayms * 1000);
180 delayms *= 2;
182 return TRUE;
184 #endif
187 /***********************************************************************
188 * set_stdio_fd
190 static void set_stdio_fd( int stdin_fd, int stdout_fd )
192 int fd = -1;
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;
201 dup2( stdin_fd, 0 );
202 dup2( stdout_fd, 1 );
203 if (fd != -1) close( fd );
207 /***********************************************************************
208 * spawn_process
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;
216 pid_t pid;
217 char **argv;
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))
230 setsid();
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( &params->CommandLine, 2 );
243 exec_wineloader( argv, socketfd, is_child_64bit,
244 pe_info->base, pe_info->base + pe_info->map_size );
245 _exit(1);
248 _exit(pid == -1);
251 if (pid != -1)
253 /* reap child */
254 pid_t wret;
255 do {
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 );
263 return status;
267 /***********************************************************************
268 * exec_process
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);
273 NTSTATUS status;
274 int socketfd[2];
275 char **argv;
277 if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1) return STATUS_TOO_MANY_OPENED_FILES;
278 #ifdef SO_PASSCRED
279 else
281 int enable = 1;
282 setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
284 #endif
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 );
294 SERVER_END_REQ;
296 if (!status)
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 );
304 #ifdef __APPLE__
305 while (errno == ENOTSUP && terminate_main_thread());
306 #else
307 while (0);
308 #endif
309 free( argv );
311 close( socketfd[0] );
312 return status;
316 /***********************************************************************
317 * fork_and_exec
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 )
324 pid_t pid;
325 int fd[2], stdin_fd = -1, stdout_fd = -1;
326 char **argv, **envp;
327 NTSTATUS status;
329 #ifdef HAVE_PIPE2
330 if (pipe2( fd, O_CLOEXEC ) == -1)
331 #endif
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 */
345 close( fd[0] );
347 if (params->ConsoleFlags ||
348 params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ ||
349 (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
351 setsid();
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( &params->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 */
371 switch (errno)
373 case EPERM:
374 case EACCES: status = STATUS_ACCESS_DENIED; break;
375 case ENOENT: status = STATUS_OBJECT_NAME_NOT_FOUND; break;
376 case EMFILE:
377 case ENFILE: status = STATUS_TOO_MANY_OPENED_FILES; break;
378 case ENOEXEC:
379 case EINVAL: status = STATUS_INVALID_IMAGE_FORMAT; break;
380 default: status = STATUS_NO_MEMORY; break;
382 write( fd[1], &status, sizeof(status) );
383 _exit(1);
385 _exit(0); /* child if fork succeeded */
387 close( fd[1] );
389 if (pid != -1)
391 /* reap child */
392 pid_t wret;
393 do {
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;
400 close( fd[0] );
401 if (stdin_fd != -1) close( stdin_fd );
402 if (stdout_fd != -1) close( stdout_fd );
403 return status;