wined3d: Correctly destroy the adapter on format initialization failure in no3d mode.
[wine/zf.git] / dlls / ntdll / unix / process.c
blobbde46264d0aad618a6206be3299806fde601c479
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"
70 WINE_DEFAULT_DEBUG_CHANNEL(process);
73 static ULONG execute_flags = MEM_EXECUTE_OPTION_DISABLE | (sizeof(void *) > sizeof(int) ?
74 MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION |
75 MEM_EXECUTE_OPTION_PERMANENT : 0);
77 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
79 static const char * const cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" };
81 static UINT process_error_mode;
83 static char **build_argv( const UNICODE_STRING *cmdline, int reserved )
85 char **argv, *arg, *src, *dst;
86 int argc, in_quotes = 0, bcount = 0, len = cmdline->Length / sizeof(WCHAR);
88 if (!(src = malloc( len * 3 + 1 ))) return NULL;
89 len = ntdll_wcstoumbs( cmdline->Buffer, len, src, len * 3, FALSE );
90 src[len++] = 0;
92 argc = reserved + 2 + len / 2;
93 argv = malloc( argc * sizeof(*argv) + len );
94 arg = dst = (char *)(argv + argc);
95 argc = reserved;
96 while (*src)
98 if ((*src == ' ' || *src == '\t') && !in_quotes)
100 /* skip the remaining spaces */
101 while (*src == ' ' || *src == '\t') src++;
102 if (!*src) break;
103 /* close the argument and copy it */
104 *dst++ = 0;
105 argv[argc++] = arg;
106 /* start with a new argument */
107 arg = dst;
108 bcount = 0;
110 else if (*src == '\\')
112 *dst++ = *src++;
113 bcount++;
115 else if (*src == '"')
117 if ((bcount & 1) == 0)
119 /* Preceded by an even number of '\', this is half that
120 * number of '\', plus a '"' which we discard.
122 dst -= bcount / 2;
123 src++;
124 if (in_quotes && *src == '"') *dst++ = *src++;
125 else in_quotes = !in_quotes;
127 else
129 /* Preceded by an odd number of '\', this is half that
130 * number of '\' followed by a '"'
132 dst -= bcount / 2 + 1;
133 *dst++ = *src++;
135 bcount = 0;
137 else /* a regular character */
139 *dst++ = *src++;
140 bcount = 0;
143 *dst = 0;
144 argv[argc++] = arg;
145 argv[argc] = NULL;
146 return argv;
150 #ifdef __APPLE__
151 /***********************************************************************
152 * terminate_main_thread
154 * On some versions of Mac OS X, the execve system call fails with
155 * ENOTSUP if the process has multiple threads. Wine is always multi-
156 * threaded on Mac OS X because it specifically reserves the main thread
157 * for use by the system frameworks (see apple_main_thread() in
158 * libs/wine/loader.c). So, when we need to exec without first forking,
159 * we need to terminate the main thread first. We do this by installing
160 * a custom run loop source onto the main run loop and signaling it.
161 * The source's "perform" callback is pthread_exit and it will be
162 * executed on the main thread, terminating it.
164 * Returns TRUE if there's still hope the main thread has terminated or
165 * will soon. Return FALSE if we've given up.
167 static BOOL terminate_main_thread(void)
169 static int delayms;
171 if (!delayms)
173 CFRunLoopSourceContext source_context = { 0 };
174 CFRunLoopSourceRef source;
176 source_context.perform = pthread_exit;
177 if (!(source = CFRunLoopSourceCreate( NULL, 0, &source_context )))
178 return FALSE;
180 CFRunLoopAddSource( CFRunLoopGetMain(), source, kCFRunLoopCommonModes );
181 CFRunLoopSourceSignal( source );
182 CFRunLoopWakeUp( CFRunLoopGetMain() );
183 CFRelease( source );
185 delayms = 20;
188 if (delayms > 1000)
189 return FALSE;
191 usleep(delayms * 1000);
192 delayms *= 2;
194 return TRUE;
196 #endif
199 static inline const WCHAR *get_params_string( const RTL_USER_PROCESS_PARAMETERS *params,
200 const UNICODE_STRING *str )
202 if (params->Flags & PROCESS_PARAMS_FLAG_NORMALIZED) return str->Buffer;
203 return (const WCHAR *)((const char *)params + (UINT_PTR)str->Buffer);
206 static inline DWORD append_string( void **ptr, const RTL_USER_PROCESS_PARAMETERS *params,
207 const UNICODE_STRING *str )
209 const WCHAR *buffer = get_params_string( params, str );
210 memcpy( *ptr, buffer, str->Length );
211 *ptr = (WCHAR *)*ptr + str->Length / sizeof(WCHAR);
212 return str->Length;
215 /***********************************************************************
216 * create_startup_info
218 static startup_info_t *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *params, DWORD *info_size )
220 startup_info_t *info;
221 DWORD size;
222 void *ptr;
224 size = sizeof(*info);
225 size += params->CurrentDirectory.DosPath.Length;
226 size += params->DllPath.Length;
227 size += params->ImagePathName.Length;
228 size += params->CommandLine.Length;
229 size += params->WindowTitle.Length;
230 size += params->Desktop.Length;
231 size += params->ShellInfo.Length;
232 size += params->RuntimeInfo.Length;
233 size = (size + 1) & ~1;
234 *info_size = size;
236 if (!(info = calloc( size, 1 ))) return NULL;
238 info->debug_flags = params->DebugFlags;
239 info->console_flags = params->ConsoleFlags;
240 info->console = wine_server_obj_handle( params->ConsoleHandle );
241 info->hstdin = wine_server_obj_handle( params->hStdInput );
242 info->hstdout = wine_server_obj_handle( params->hStdOutput );
243 info->hstderr = wine_server_obj_handle( params->hStdError );
244 info->x = params->dwX;
245 info->y = params->dwY;
246 info->xsize = params->dwXSize;
247 info->ysize = params->dwYSize;
248 info->xchars = params->dwXCountChars;
249 info->ychars = params->dwYCountChars;
250 info->attribute = params->dwFillAttribute;
251 info->flags = params->dwFlags;
252 info->show = params->wShowWindow;
254 ptr = info + 1;
255 info->curdir_len = append_string( &ptr, params, &params->CurrentDirectory.DosPath );
256 info->dllpath_len = append_string( &ptr, params, &params->DllPath );
257 info->imagepath_len = append_string( &ptr, params, &params->ImagePathName );
258 info->cmdline_len = append_string( &ptr, params, &params->CommandLine );
259 info->title_len = append_string( &ptr, params, &params->WindowTitle );
260 info->desktop_len = append_string( &ptr, params, &params->Desktop );
261 info->shellinfo_len = append_string( &ptr, params, &params->ShellInfo );
262 info->runtime_len = append_string( &ptr, params, &params->RuntimeInfo );
263 return info;
267 /***************************************************************************
268 * is_builtin_path
270 static BOOL is_builtin_path( UNICODE_STRING *path, BOOL *is_64bit )
272 static const WCHAR systemW[] = {'\\','?','?','\\','c',':','\\','w','i','n','d','o','w','s','\\',
273 's','y','s','t','e','m','3','2','\\'};
274 static const WCHAR wow64W[] = {'\\','?','?','\\','c',':','\\','w','i','n','d','o','w','s','\\',
275 's','y','s','w','o','w','6','4'};
277 *is_64bit = is_win64;
278 if (path->Length > sizeof(systemW) && !wcsnicmp( path->Buffer, systemW, ARRAY_SIZE(systemW) ))
280 if (is_wow64 && !ntdll_get_thread_data()->wow64_redir) *is_64bit = TRUE;
281 return TRUE;
283 if ((is_win64 || is_wow64) && path->Length > sizeof(wow64W) &&
284 !wcsnicmp( path->Buffer, wow64W, ARRAY_SIZE(wow64W) ))
286 *is_64bit = FALSE;
287 return TRUE;
289 return FALSE;
293 /***********************************************************************
294 * get_so_file_info
296 static BOOL get_so_file_info( HANDLE handle, pe_image_info_t *info )
298 union
300 struct
302 unsigned char magic[4];
303 unsigned char class;
304 unsigned char data;
305 unsigned char version;
306 unsigned char ignored1[9];
307 unsigned short type;
308 unsigned short machine;
309 unsigned char ignored2[8];
310 unsigned int phoff;
311 unsigned char ignored3[12];
312 unsigned short phnum;
313 } elf;
314 struct
316 unsigned char magic[4];
317 unsigned char class;
318 unsigned char data;
319 unsigned char ignored1[10];
320 unsigned short type;
321 unsigned short machine;
322 unsigned char ignored2[12];
323 unsigned __int64 phoff;
324 unsigned char ignored3[16];
325 unsigned short phnum;
326 } elf64;
327 struct
329 unsigned int magic;
330 unsigned int cputype;
331 unsigned int cpusubtype;
332 unsigned int filetype;
333 } macho;
334 IMAGE_DOS_HEADER mz;
335 } header;
337 IO_STATUS_BLOCK io;
338 LARGE_INTEGER offset;
340 offset.QuadPart = 0;
341 if (NtReadFile( handle, 0, NULL, NULL, &io, &header, sizeof(header), &offset, 0 )) return FALSE;
342 if (io.Information != sizeof(header)) return FALSE;
344 if (!memcmp( header.elf.magic, "\177ELF", 4 ))
346 unsigned int type;
347 unsigned short phnum;
349 if (header.elf.version != 1 /* EV_CURRENT */) return FALSE;
350 #ifdef WORDS_BIGENDIAN
351 if (header.elf.data != 2 /* ELFDATA2MSB */) return FALSE;
352 #else
353 if (header.elf.data != 1 /* ELFDATA2LSB */) return FALSE;
354 #endif
355 switch (header.elf.machine)
357 case 3: info->cpu = CPU_x86; break;
358 case 40: info->cpu = CPU_ARM; break;
359 case 62: info->cpu = CPU_x86_64; break;
360 case 183: info->cpu = CPU_ARM64; break;
362 if (header.elf.type != 3 /* ET_DYN */) return FALSE;
363 if (header.elf.class == 2 /* ELFCLASS64 */)
365 offset.QuadPart = header.elf64.phoff;
366 phnum = header.elf64.phnum;
368 else
370 offset.QuadPart = header.elf.phoff;
371 phnum = header.elf.phnum;
373 while (phnum--)
375 if (NtReadFile( handle, 0, NULL, NULL, &io, &type, sizeof(type), &offset, 0 )) return FALSE;
376 if (io.Information < sizeof(type)) return FALSE;
377 if (type == 3 /* PT_INTERP */) return FALSE;
378 offset.QuadPart += (header.elf.class == 2) ? 56 : 32;
380 return TRUE;
382 else if (header.macho.magic == 0xfeedface || header.macho.magic == 0xfeedfacf)
384 switch (header.macho.cputype)
386 case 0x00000007: info->cpu = CPU_x86; break;
387 case 0x01000007: info->cpu = CPU_x86_64; break;
388 case 0x0000000c: info->cpu = CPU_ARM; break;
389 case 0x0100000c: info->cpu = CPU_ARM64; break;
391 if (header.macho.filetype == 8) return TRUE;
393 return FALSE;
397 /***********************************************************************
398 * get_pe_file_info
400 static NTSTATUS get_pe_file_info( UNICODE_STRING *path, HANDLE *handle, pe_image_info_t *info )
402 NTSTATUS status;
403 HANDLE mapping;
404 OBJECT_ATTRIBUTES attr;
405 IO_STATUS_BLOCK io;
407 memset( info, 0, sizeof(*info) );
408 InitializeObjectAttributes( &attr, path, OBJ_CASE_INSENSITIVE, 0, 0 );
409 if ((status = NtOpenFile( handle, GENERIC_READ, &attr, &io,
410 FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT )))
412 BOOL is_64bit;
414 if (is_builtin_path( path, &is_64bit ))
416 TRACE( "assuming %u-bit builtin for %s\n", is_64bit ? 64 : 32, debugstr_us(path));
417 /* assume current arch */
418 #if defined(__i386__) || defined(__x86_64__)
419 info->cpu = is_64bit ? CPU_x86_64 : CPU_x86;
420 #else
421 info->cpu = client_cpu;
422 #endif
423 *handle = 0;
424 return STATUS_SUCCESS;
426 return status;
429 if (!(status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
430 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
431 NULL, NULL, PAGE_EXECUTE_READ, SEC_IMAGE, *handle )))
433 SERVER_START_REQ( get_mapping_info )
435 req->handle = wine_server_obj_handle( mapping );
436 req->access = SECTION_QUERY;
437 wine_server_set_reply( req, info, sizeof(*info) );
438 status = wine_server_call( req );
440 SERVER_END_REQ;
441 NtClose( mapping );
443 else if (status == STATUS_INVALID_IMAGE_NOT_MZ)
445 if (get_so_file_info( *handle, info )) return STATUS_SUCCESS;
447 return status;
451 /***********************************************************************
452 * get_env_size
454 static ULONG get_env_size( const RTL_USER_PROCESS_PARAMETERS *params, char **winedebug )
456 WCHAR *ptr = params->Environment;
458 while (*ptr)
460 static const WCHAR WINEDEBUG[] = {'W','I','N','E','D','E','B','U','G','=',0};
461 if (!*winedebug && !wcsncmp( ptr, WINEDEBUG, ARRAY_SIZE( WINEDEBUG ) - 1 ))
463 DWORD len = wcslen(ptr) * 3 + 1;
464 if ((*winedebug = malloc( len )))
465 ntdll_wcstoumbs( ptr, wcslen(ptr) + 1, *winedebug, len, FALSE );
467 ptr += wcslen(ptr) + 1;
469 ptr++;
470 return (ptr - params->Environment) * sizeof(WCHAR);
474 /***********************************************************************
475 * get_unix_curdir
477 static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params )
479 static const WCHAR ntprefixW[] = {'\\','?','?','\\',0};
480 static const WCHAR uncprefixW[] = {'U','N','C','\\',0};
481 const UNICODE_STRING *curdir = &params->CurrentDirectory.DosPath;
482 const WCHAR *dir = curdir->Buffer;
483 UNICODE_STRING nt_name;
484 OBJECT_ATTRIBUTES attr;
485 IO_STATUS_BLOCK io;
486 NTSTATUS status;
487 HANDLE handle;
488 int fd = -1;
490 if (!(nt_name.Buffer = malloc( curdir->Length + 8 * sizeof(WCHAR) ))) return -1;
492 /* simplified version of RtlDosPathNameToNtPathName_U */
493 wcscpy( nt_name.Buffer, ntprefixW );
494 if (dir[0] == '\\' && dir[1] == '\\')
496 if ((dir[2] == '.' || dir[2] == '?') && dir[3] == '\\') dir += 4;
497 else
499 wcscat( nt_name.Buffer, uncprefixW );
500 dir += 2;
503 wcscat( nt_name.Buffer, dir );
504 nt_name.Length = wcslen( nt_name.Buffer ) * sizeof(WCHAR);
506 InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
507 status = NtOpenFile( &handle, FILE_TRAVERSE | SYNCHRONIZE, &attr, &io,
508 FILE_SHARE_READ | FILE_SHARE_WRITE,
509 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
510 free( nt_name.Buffer );
511 if (status) return -1;
512 server_handle_to_fd( handle, FILE_TRAVERSE, &fd, NULL );
513 NtClose( handle );
514 return fd;
518 /***********************************************************************
519 * set_stdio_fd
521 static void set_stdio_fd( int stdin_fd, int stdout_fd )
523 int fd = -1;
525 if (stdin_fd == -1 || stdout_fd == -1)
527 fd = open( "/dev/null", O_RDWR );
528 if (stdin_fd == -1) stdin_fd = fd;
529 if (stdout_fd == -1) stdout_fd = fd;
532 dup2( stdin_fd, 0 );
533 dup2( stdout_fd, 1 );
534 if (fd != -1) close( fd );
538 /***********************************************************************
539 * spawn_process
541 static NTSTATUS spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd,
542 int unixdir, char *winedebug, const pe_image_info_t *pe_info )
544 NTSTATUS status = STATUS_SUCCESS;
545 int stdin_fd = -1, stdout_fd = -1;
546 pid_t pid;
547 char **argv;
549 server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL );
550 server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL );
552 if (!(pid = fork())) /* child */
554 if (!(pid = fork())) /* grandchild */
556 if (params->ConsoleFlags ||
557 params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ ||
558 (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
560 setsid();
561 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
563 else set_stdio_fd( stdin_fd, stdout_fd );
565 if (stdin_fd != -1) close( stdin_fd );
566 if (stdout_fd != -1) close( stdout_fd );
568 if (winedebug) putenv( winedebug );
569 if (unixdir != -1)
571 fchdir( unixdir );
572 close( unixdir );
574 argv = build_argv( &params->CommandLine, 2 );
576 exec_wineloader( argv, socketfd, pe_info );
577 _exit(1);
580 _exit(pid == -1);
583 if (pid != -1)
585 /* reap child */
586 pid_t wret;
587 do {
588 wret = waitpid(pid, NULL, 0);
589 } while (wret < 0 && errno == EINTR);
591 else status = STATUS_NO_MEMORY;
593 if (stdin_fd != -1) close( stdin_fd );
594 if (stdout_fd != -1) close( stdout_fd );
595 return status;
599 /***********************************************************************
600 * exec_process
602 NTSTATUS CDECL exec_process( UNICODE_STRING *path, UNICODE_STRING *cmdline, NTSTATUS status )
604 pe_image_info_t pe_info;
605 int unixdir, socketfd[2];
606 char **argv;
607 HANDLE handle;
609 if (startup_info_size) return status; /* started from another Win32 process */
611 switch (status)
613 case STATUS_CONFLICTING_ADDRESSES:
614 case STATUS_NO_MEMORY:
615 case STATUS_INVALID_IMAGE_FORMAT:
616 case STATUS_INVALID_IMAGE_NOT_MZ:
617 if (getenv( "WINEPRELOADRESERVE" )) return status;
618 if ((status = get_pe_file_info( path, &handle, &pe_info ))) return status;
619 break;
620 case STATUS_INVALID_IMAGE_WIN_16:
621 case STATUS_INVALID_IMAGE_NE_FORMAT:
622 case STATUS_INVALID_IMAGE_PROTECT:
623 /* we'll start winevdm */
624 memset( &pe_info, 0, sizeof(pe_info) );
625 pe_info.cpu = CPU_x86;
626 break;
627 default:
628 return status;
631 unixdir = get_unix_curdir( NtCurrentTeb()->Peb->ProcessParameters );
633 if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1) return STATUS_TOO_MANY_OPENED_FILES;
634 #ifdef SO_PASSCRED
635 else
637 int enable = 1;
638 setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
640 #endif
641 server_send_fd( socketfd[1] );
642 close( socketfd[1] );
644 SERVER_START_REQ( exec_process )
646 req->socket_fd = socketfd[1];
647 req->cpu = pe_info.cpu;
648 status = wine_server_call( req );
650 SERVER_END_REQ;
652 if (!status)
654 if (!(argv = build_argv( cmdline, 2 ))) return STATUS_NO_MEMORY;
655 fchdir( unixdir );
658 status = exec_wineloader( argv, socketfd[0], &pe_info );
660 #ifdef __APPLE__
661 while (errno == ENOTSUP && terminate_main_thread());
662 #else
663 while (0);
664 #endif
665 free( argv );
667 close( socketfd[0] );
668 return status;
672 /***********************************************************************
673 * fork_and_exec
675 * Fork and exec a new Unix binary, checking for errors.
677 static NTSTATUS fork_and_exec( UNICODE_STRING *path, int unixdir,
678 const RTL_USER_PROCESS_PARAMETERS *params )
680 pid_t pid;
681 int fd[2], stdin_fd = -1, stdout_fd = -1;
682 char **argv, **envp;
683 char *unix_name;
684 NTSTATUS status;
686 status = nt_to_unix_file_name( path, &unix_name, FILE_OPEN );
687 if (status) return status;
689 #ifdef HAVE_PIPE2
690 if (pipe2( fd, O_CLOEXEC ) == -1)
691 #endif
693 if (pipe(fd) == -1)
695 status = STATUS_TOO_MANY_OPENED_FILES;
696 goto done;
698 fcntl( fd[0], F_SETFD, FD_CLOEXEC );
699 fcntl( fd[1], F_SETFD, FD_CLOEXEC );
702 server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL );
703 server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL );
705 if (!(pid = fork())) /* child */
707 if (!(pid = fork())) /* grandchild */
709 close( fd[0] );
711 if (params->ConsoleFlags ||
712 params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ ||
713 (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
715 setsid();
716 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
718 else set_stdio_fd( stdin_fd, stdout_fd );
720 if (stdin_fd != -1) close( stdin_fd );
721 if (stdout_fd != -1) close( stdout_fd );
723 /* Reset signals that we previously set to SIG_IGN */
724 signal( SIGPIPE, SIG_DFL );
726 argv = build_argv( &params->CommandLine, 0 );
727 envp = build_envp( params->Environment );
728 if (unixdir != -1)
730 fchdir( unixdir );
731 close( unixdir );
733 execve( unix_name, argv, envp );
736 if (pid <= 0) /* grandchild if exec failed or child if fork failed */
738 switch (errno)
740 case EPERM:
741 case EACCES: status = STATUS_ACCESS_DENIED; break;
742 case ENOENT: status = STATUS_OBJECT_NAME_NOT_FOUND; break;
743 case EMFILE:
744 case ENFILE: status = STATUS_TOO_MANY_OPENED_FILES; break;
745 case ENOEXEC:
746 case EINVAL: status = STATUS_INVALID_IMAGE_FORMAT; break;
747 default: status = STATUS_NO_MEMORY; break;
749 write( fd[1], &status, sizeof(status) );
750 _exit(1);
752 _exit(0); /* child if fork succeeded */
754 close( fd[1] );
756 if (pid != -1)
758 /* reap child */
759 pid_t wret;
760 do {
761 wret = waitpid(pid, NULL, 0);
762 } while (wret < 0 && errno == EINTR);
763 read( fd[0], &status, sizeof(status) ); /* if we read something, exec or second fork failed */
765 else status = STATUS_NO_MEMORY;
767 close( fd[0] );
768 if (stdin_fd != -1) close( stdin_fd );
769 if (stdout_fd != -1) close( stdout_fd );
770 done:
771 free( unix_name );
772 return status;
776 /**********************************************************************
777 * NtCreateUserProcess (NTDLL.@)
779 NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_handle_ptr,
780 ACCESS_MASK process_access, ACCESS_MASK thread_access,
781 OBJECT_ATTRIBUTES *process_attr, OBJECT_ATTRIBUTES *thread_attr,
782 ULONG process_flags, ULONG thread_flags,
783 RTL_USER_PROCESS_PARAMETERS *params, PS_CREATE_INFO *info,
784 PS_ATTRIBUTE_LIST *attr )
786 NTSTATUS status;
787 BOOL success = FALSE;
788 HANDLE file_handle, process_info = 0, process_handle = 0, thread_handle = 0;
789 struct object_attributes *objattr;
790 data_size_t attr_len;
791 char *winedebug = NULL;
792 startup_info_t *startup_info = NULL;
793 ULONG startup_info_size, env_size;
794 int unixdir, socketfd[2] = { -1, -1 };
795 pe_image_info_t pe_info;
796 CLIENT_ID id;
797 HANDLE parent = 0, debug = 0, token = 0;
798 UNICODE_STRING path = {0};
799 SIZE_T i, attr_count = (attr->TotalLength - sizeof(attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
801 for (i = 0; i < attr_count; i++)
803 switch (attr->Attributes[i].Attribute)
805 case PS_ATTRIBUTE_PARENT_PROCESS:
806 parent = attr->Attributes[i].ValuePtr;
807 break;
808 case PS_ATTRIBUTE_DEBUG_PORT:
809 debug = attr->Attributes[i].ValuePtr;
810 break;
811 case PS_ATTRIBUTE_IMAGE_NAME:
812 path.Length = attr->Attributes[i].Size;
813 path.Buffer = attr->Attributes[i].ValuePtr;
814 break;
815 case PS_ATTRIBUTE_TOKEN:
816 token = attr->Attributes[i].ValuePtr;
817 break;
818 default:
819 if (attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT)
820 FIXME( "unhandled input attribute %lx\n", attr->Attributes[i].Attribute );
821 break;
825 TRACE( "%s image %s cmdline %s parent %p\n", debugstr_us( &path ),
826 debugstr_us( &params->ImagePathName ), debugstr_us( &params->CommandLine ), parent );
827 if (debug) FIXME( "debug port %p not supported yet\n", debug );
828 if (token) FIXME( "token %p not supported yet\n", token );
830 unixdir = get_unix_curdir( params );
832 if ((status = get_pe_file_info( &path, &file_handle, &pe_info )))
834 if (status == STATUS_INVALID_IMAGE_NOT_MZ && !fork_and_exec( &path, unixdir, params ))
836 memset( info, 0, sizeof(*info) );
837 return STATUS_SUCCESS;
839 goto done;
841 if (!(startup_info = create_startup_info( params, &startup_info_size ))) goto done;
842 env_size = get_env_size( params, &winedebug );
844 if ((status = alloc_object_attributes( process_attr, &objattr, &attr_len ))) goto done;
846 /* create the socket for the new process */
848 if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
850 status = STATUS_TOO_MANY_OPENED_FILES;
851 free( objattr );
852 goto done;
854 #ifdef SO_PASSCRED
855 else
857 int enable = 1;
858 setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
860 #endif
862 server_send_fd( socketfd[1] );
863 close( socketfd[1] );
865 /* create the process on the server side */
867 SERVER_START_REQ( new_process )
869 req->parent_process = wine_server_obj_handle( parent );
870 req->inherit_all = !!(process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES);
871 req->create_flags = params->DebugFlags; /* hack: creation flags stored in DebugFlags for now */
872 req->socket_fd = socketfd[1];
873 req->exe_file = wine_server_obj_handle( file_handle );
874 req->access = process_access;
875 req->cpu = pe_info.cpu;
876 req->info_size = startup_info_size;
877 wine_server_add_data( req, objattr, attr_len );
878 wine_server_add_data( req, startup_info, startup_info_size );
879 wine_server_add_data( req, params->Environment, env_size );
880 if (!(status = wine_server_call( req )))
882 process_handle = wine_server_ptr_handle( reply->handle );
883 id.UniqueProcess = ULongToHandle( reply->pid );
885 process_info = wine_server_ptr_handle( reply->info );
887 SERVER_END_REQ;
888 free( objattr );
890 if (status)
892 switch (status)
894 case STATUS_INVALID_IMAGE_WIN_64:
895 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_us(&path) );
896 break;
897 case STATUS_INVALID_IMAGE_FORMAT:
898 ERR( "%s not supported on this installation (%s binary)\n",
899 debugstr_us(&path), cpu_names[pe_info.cpu] );
900 break;
902 goto done;
905 if ((status = alloc_object_attributes( thread_attr, &objattr, &attr_len ))) goto done;
907 SERVER_START_REQ( new_thread )
909 req->process = wine_server_obj_handle( process_handle );
910 req->access = thread_access;
911 req->suspend = !!(thread_flags & THREAD_CREATE_FLAGS_CREATE_SUSPENDED);
912 req->request_fd = -1;
913 wine_server_add_data( req, objattr, attr_len );
914 if (!(status = wine_server_call( req )))
916 thread_handle = wine_server_ptr_handle( reply->handle );
917 id.UniqueThread = ULongToHandle( reply->tid );
920 SERVER_END_REQ;
921 free( objattr );
922 if (status) goto done;
924 /* create the child process */
926 if ((status = spawn_process( params, socketfd[0], unixdir, winedebug, &pe_info ))) goto done;
928 close( socketfd[0] );
929 socketfd[0] = -1;
931 /* wait for the new process info to be ready */
933 NtWaitForSingleObject( process_info, FALSE, NULL );
934 SERVER_START_REQ( get_new_process_info )
936 req->info = wine_server_obj_handle( process_info );
937 wine_server_call( req );
938 success = reply->success;
939 status = reply->exit_code;
941 SERVER_END_REQ;
943 if (!success)
945 if (!status) status = STATUS_INTERNAL_ERROR;
946 goto done;
949 TRACE( "%s pid %04x tid %04x handles %p/%p\n", debugstr_us(&path),
950 HandleToULong(id.UniqueProcess), HandleToULong(id.UniqueThread),
951 process_handle, thread_handle );
953 /* update output attributes */
955 for (i = 0; i < attr_count; i++)
957 switch (attr->Attributes[i].Attribute)
959 case PS_ATTRIBUTE_CLIENT_ID:
961 SIZE_T size = min( attr->Attributes[i].Size, sizeof(id) );
962 memcpy( attr->Attributes[i].ValuePtr, &id, size );
963 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
964 break;
966 case PS_ATTRIBUTE_IMAGE_INFO:
968 SECTION_IMAGE_INFORMATION info;
969 SIZE_T size = min( attr->Attributes[i].Size, sizeof(info) );
970 virtual_fill_image_information( &pe_info, &info );
971 memcpy( attr->Attributes[i].ValuePtr, &info, size );
972 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
973 break;
975 case PS_ATTRIBUTE_TEB_ADDRESS:
976 default:
977 if (!(attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT))
978 FIXME( "unhandled output attribute %lx\n", attr->Attributes[i].Attribute );
979 break;
982 *process_handle_ptr = process_handle;
983 *thread_handle_ptr = thread_handle;
984 process_handle = thread_handle = 0;
985 status = STATUS_SUCCESS;
987 done:
988 if (file_handle) NtClose( file_handle );
989 if (process_info) NtClose( process_info );
990 if (process_handle) NtClose( process_handle );
991 if (thread_handle) NtClose( thread_handle );
992 if (socketfd[0] != -1) close( socketfd[0] );
993 if (unixdir != -1) close( unixdir );
994 free( startup_info );
995 free( winedebug );
996 return status;
1000 /******************************************************************************
1001 * NtTerminateProcess (NTDLL.@)
1003 NTSTATUS WINAPI NtTerminateProcess( HANDLE handle, LONG exit_code )
1005 static BOOL clean_exit;
1006 NTSTATUS ret;
1007 BOOL self;
1009 SERVER_START_REQ( terminate_process )
1011 req->handle = wine_server_obj_handle( handle );
1012 req->exit_code = exit_code;
1013 ret = wine_server_call( req );
1014 self = reply->self;
1016 SERVER_END_REQ;
1017 if (self)
1019 if (!handle) clean_exit = TRUE;
1020 else if (clean_exit) exit_process( exit_code );
1021 else abort_process( exit_code );
1023 return ret;
1027 #if defined(HAVE_MACH_MACH_H)
1029 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1031 #if defined(MACH_TASK_BASIC_INFO)
1032 struct mach_task_basic_info info;
1034 if (unix_pid != -1) return; /* FIXME: Retrieve information for other processes. */
1036 mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
1037 if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS)
1039 pvmi->VirtualSize = info.resident_size + info.virtual_size;
1040 pvmi->PagefileUsage = info.virtual_size;
1041 pvmi->WorkingSetSize = info.resident_size;
1042 pvmi->PeakWorkingSetSize = info.resident_size_max;
1044 #endif
1047 #elif defined(linux)
1049 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1051 FILE *f;
1052 char line[256], path[26];
1053 unsigned long value;
1055 if (unix_pid == -1)
1056 strcpy( path, "/proc/self/status" );
1057 else
1058 sprintf( path, "/proc/%u/status", unix_pid);
1059 f = fopen( path, "r" );
1060 if (!f) return;
1062 while (fgets(line, sizeof(line), f))
1064 if (sscanf(line, "VmPeak: %lu", &value))
1065 pvmi->PeakVirtualSize = (ULONG64)value * 1024;
1066 else if (sscanf(line, "VmSize: %lu", &value))
1067 pvmi->VirtualSize = (ULONG64)value * 1024;
1068 else if (sscanf(line, "VmHWM: %lu", &value))
1069 pvmi->PeakWorkingSetSize = (ULONG64)value * 1024;
1070 else if (sscanf(line, "VmRSS: %lu", &value))
1071 pvmi->WorkingSetSize = (ULONG64)value * 1024;
1072 else if (sscanf(line, "RssAnon: %lu", &value))
1073 pvmi->PagefileUsage += (ULONG64)value * 1024;
1074 else if (sscanf(line, "VmSwap: %lu", &value))
1075 pvmi->PagefileUsage += (ULONG64)value * 1024;
1077 pvmi->PeakPagefileUsage = pvmi->PagefileUsage;
1079 fclose(f);
1082 #else
1084 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1086 /* FIXME : real data */
1089 #endif
1091 #define UNIMPLEMENTED_INFO_CLASS(c) \
1092 case c: \
1093 FIXME( "(process=%p) Unimplemented information class: " #c "\n", handle); \
1094 ret = STATUS_INVALID_INFO_CLASS; \
1095 break
1097 /**********************************************************************
1098 * NtQueryInformationProcess (NTDLL.@)
1100 NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class, void *info,
1101 ULONG size, ULONG *ret_len )
1103 NTSTATUS ret = STATUS_SUCCESS;
1104 ULONG len = 0;
1106 TRACE( "(%p,0x%08x,%p,0x%08x,%p)\n", handle, class, info, size, ret_len );
1108 switch (class)
1110 UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits);
1111 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority);
1112 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority);
1113 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort);
1114 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken);
1115 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation);
1116 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize);
1117 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers);
1118 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits);
1119 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch);
1120 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL);
1121 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup);
1122 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information);
1123 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost);
1124 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap);
1125 UNIMPLEMENTED_INFO_CLASS(ProcessSessionInformation);
1126 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation);
1127 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled);
1128 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination);
1129 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing);
1131 case ProcessBasicInformation:
1133 PROCESS_BASIC_INFORMATION pbi;
1134 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1136 if (size >= sizeof(PROCESS_BASIC_INFORMATION))
1138 if (!info) ret = STATUS_ACCESS_VIOLATION;
1139 else
1141 SERVER_START_REQ(get_process_info)
1143 req->handle = wine_server_obj_handle( handle );
1144 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1146 pbi.ExitStatus = reply->exit_code;
1147 pbi.PebBaseAddress = wine_server_get_ptr( reply->peb );
1148 pbi.AffinityMask = reply->affinity & affinity_mask;
1149 pbi.BasePriority = reply->priority;
1150 pbi.UniqueProcessId = reply->pid;
1151 pbi.InheritedFromUniqueProcessId = reply->ppid;
1154 SERVER_END_REQ;
1156 memcpy( info, &pbi, sizeof(PROCESS_BASIC_INFORMATION) );
1157 len = sizeof(PROCESS_BASIC_INFORMATION);
1159 if (size > sizeof(PROCESS_BASIC_INFORMATION)) ret = STATUS_INFO_LENGTH_MISMATCH;
1161 else
1163 len = sizeof(PROCESS_BASIC_INFORMATION);
1164 ret = STATUS_INFO_LENGTH_MISMATCH;
1167 break;
1169 case ProcessIoCounters:
1171 IO_COUNTERS pii;
1173 if (size >= sizeof(IO_COUNTERS))
1175 if (!info) ret = STATUS_ACCESS_VIOLATION;
1176 else if (!handle) ret = STATUS_INVALID_HANDLE;
1177 else
1179 /* FIXME : real data */
1180 memset(&pii, 0 , sizeof(IO_COUNTERS));
1181 memcpy(info, &pii, sizeof(IO_COUNTERS));
1182 len = sizeof(IO_COUNTERS);
1184 if (size > sizeof(IO_COUNTERS)) ret = STATUS_INFO_LENGTH_MISMATCH;
1186 else
1188 len = sizeof(IO_COUNTERS);
1189 ret = STATUS_INFO_LENGTH_MISMATCH;
1192 break;
1194 case ProcessVmCounters:
1196 VM_COUNTERS_EX pvmi;
1198 /* older Windows versions don't have the PrivateUsage field */
1199 if (size >= sizeof(VM_COUNTERS))
1201 if (!info) ret = STATUS_ACCESS_VIOLATION;
1202 else
1204 memset(&pvmi, 0, sizeof(pvmi));
1205 if (handle == GetCurrentProcess()) fill_vm_counters( &pvmi, -1 );
1206 else
1208 SERVER_START_REQ(get_process_vm_counters)
1210 req->handle = wine_server_obj_handle( handle );
1211 if (!(ret = wine_server_call( req )))
1213 pvmi.PeakVirtualSize = reply->peak_virtual_size;
1214 pvmi.VirtualSize = reply->virtual_size;
1215 pvmi.PeakWorkingSetSize = reply->peak_working_set_size;
1216 pvmi.WorkingSetSize = reply->working_set_size;
1217 pvmi.PagefileUsage = reply->pagefile_usage;
1218 pvmi.PeakPagefileUsage = reply->peak_pagefile_usage;
1221 SERVER_END_REQ;
1222 if (ret) break;
1224 if (size >= sizeof(VM_COUNTERS_EX))
1225 pvmi.PrivateUsage = pvmi.PagefileUsage;
1226 len = size;
1227 if (len != sizeof(VM_COUNTERS)) len = sizeof(VM_COUNTERS_EX);
1228 memcpy(info, &pvmi, min(size, sizeof(pvmi)));
1230 if (size != sizeof(VM_COUNTERS) && size != sizeof(VM_COUNTERS_EX))
1231 ret = STATUS_INFO_LENGTH_MISMATCH;
1233 else
1235 len = sizeof(pvmi);
1236 ret = STATUS_INFO_LENGTH_MISMATCH;
1239 break;
1241 case ProcessTimes:
1243 KERNEL_USER_TIMES pti = {{{0}}};
1245 if (size >= sizeof(KERNEL_USER_TIMES))
1247 if (!info) ret = STATUS_ACCESS_VIOLATION;
1248 else if (!handle) ret = STATUS_INVALID_HANDLE;
1249 else
1251 long ticks = sysconf(_SC_CLK_TCK);
1252 struct tms tms;
1254 /* FIXME: user/kernel times only work for current process */
1255 if (ticks && times( &tms ) != -1)
1257 pti.UserTime.QuadPart = (ULONGLONG)tms.tms_utime * 10000000 / ticks;
1258 pti.KernelTime.QuadPart = (ULONGLONG)tms.tms_stime * 10000000 / ticks;
1261 SERVER_START_REQ(get_process_info)
1263 req->handle = wine_server_obj_handle( handle );
1264 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1266 pti.CreateTime.QuadPart = reply->start_time;
1267 pti.ExitTime.QuadPart = reply->end_time;
1270 SERVER_END_REQ;
1272 memcpy(info, &pti, sizeof(KERNEL_USER_TIMES));
1273 len = sizeof(KERNEL_USER_TIMES);
1275 if (size > sizeof(KERNEL_USER_TIMES)) ret = STATUS_INFO_LENGTH_MISMATCH;
1277 else
1279 len = sizeof(KERNEL_USER_TIMES);
1280 ret = STATUS_INFO_LENGTH_MISMATCH;
1283 break;
1285 case ProcessDebugPort:
1286 len = sizeof(DWORD_PTR);
1287 if (size == len)
1289 if (!info) ret = STATUS_ACCESS_VIOLATION;
1290 else
1292 SERVER_START_REQ(get_process_info)
1294 req->handle = wine_server_obj_handle( handle );
1295 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1297 *(DWORD_PTR *)info = reply->debugger_present ? ~(DWORD_PTR)0 : 0;
1300 SERVER_END_REQ;
1303 else ret = STATUS_INFO_LENGTH_MISMATCH;
1304 break;
1306 case ProcessDebugFlags:
1307 len = sizeof(DWORD);
1308 if (size == len)
1310 if (!info) ret = STATUS_ACCESS_VIOLATION;
1311 else
1313 SERVER_START_REQ(get_process_info)
1315 req->handle = wine_server_obj_handle( handle );
1316 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1318 *(DWORD *)info = reply->debug_children;
1321 SERVER_END_REQ;
1324 else ret = STATUS_INFO_LENGTH_MISMATCH;
1325 break;
1327 case ProcessDefaultHardErrorMode:
1328 len = sizeof(process_error_mode);
1329 if (size == len) memcpy(info, &process_error_mode, len);
1330 else ret = STATUS_INFO_LENGTH_MISMATCH;
1331 break;
1333 case ProcessDebugObjectHandle:
1334 /* "These are not the debuggers you are looking for." *
1335 * set it to 0 aka "no debugger" to satisfy copy protections */
1336 len = sizeof(HANDLE);
1337 if (size == len)
1339 if (!info) ret = STATUS_ACCESS_VIOLATION;
1340 else if (!handle) ret = STATUS_INVALID_HANDLE;
1341 else
1343 memset(info, 0, size);
1344 ret = STATUS_PORT_NOT_SET;
1347 else ret = STATUS_INFO_LENGTH_MISMATCH;
1348 break;
1350 case ProcessHandleCount:
1351 if (size >= 4)
1353 if (!info) ret = STATUS_ACCESS_VIOLATION;
1354 else if (!handle) ret = STATUS_INVALID_HANDLE;
1355 else
1357 memset(info, 0, 4);
1358 len = 4;
1360 if (size > 4) ret = STATUS_INFO_LENGTH_MISMATCH;
1362 else
1364 len = 4;
1365 ret = STATUS_INFO_LENGTH_MISMATCH;
1367 break;
1369 case ProcessAffinityMask:
1370 len = sizeof(ULONG_PTR);
1371 if (size == len)
1373 const ULONG_PTR system_mask = get_system_affinity_mask();
1375 SERVER_START_REQ(get_process_info)
1377 req->handle = wine_server_obj_handle( handle );
1378 if (!(ret = wine_server_call( req )))
1379 *(ULONG_PTR *)info = reply->affinity & system_mask;
1381 SERVER_END_REQ;
1383 else ret = STATUS_INFO_LENGTH_MISMATCH;
1384 break;
1386 case ProcessWow64Information:
1387 len = sizeof(ULONG_PTR);
1388 if (size != len) ret = STATUS_INFO_LENGTH_MISMATCH;
1389 else if (!info) ret = STATUS_ACCESS_VIOLATION;
1390 else if (!handle) ret = STATUS_INVALID_HANDLE;
1391 else
1393 ULONG_PTR val = 0;
1395 if (handle == GetCurrentProcess()) val = is_wow64;
1396 else if (server_cpus & ((1 << CPU_x86_64) | (1 << CPU_ARM64)))
1398 SERVER_START_REQ( get_process_info )
1400 req->handle = wine_server_obj_handle( handle );
1401 if (!(ret = wine_server_call( req )))
1402 val = (reply->cpu != CPU_x86_64 && reply->cpu != CPU_ARM64);
1404 SERVER_END_REQ;
1406 *(ULONG_PTR *)info = val;
1408 break;
1410 case ProcessImageFileName:
1411 /* FIXME: Should return a device path */
1412 case ProcessImageFileNameWin32:
1413 SERVER_START_REQ(get_dll_info)
1415 UNICODE_STRING *image_file_name_str = info;
1417 req->handle = wine_server_obj_handle( handle );
1418 req->base_address = 0; /* main module */
1419 wine_server_set_reply( req, image_file_name_str ? image_file_name_str + 1 : NULL,
1420 size > sizeof(UNICODE_STRING) ? size - sizeof(UNICODE_STRING) : 0 );
1421 ret = wine_server_call( req );
1422 if (ret == STATUS_BUFFER_TOO_SMALL) ret = STATUS_INFO_LENGTH_MISMATCH;
1424 len = sizeof(UNICODE_STRING) + reply->filename_len;
1425 if (ret == STATUS_SUCCESS)
1427 image_file_name_str->MaximumLength = image_file_name_str->Length = reply->filename_len;
1428 image_file_name_str->Buffer = (PWSTR)(image_file_name_str + 1);
1431 SERVER_END_REQ;
1432 break;
1434 case ProcessExecuteFlags:
1435 len = sizeof(ULONG);
1436 if (size == len) *(ULONG *)info = execute_flags;
1437 else ret = STATUS_INFO_LENGTH_MISMATCH;
1438 break;
1440 case ProcessPriorityClass:
1441 len = sizeof(PROCESS_PRIORITY_CLASS);
1442 if (size == len)
1444 if (!info) ret = STATUS_ACCESS_VIOLATION;
1445 else
1447 PROCESS_PRIORITY_CLASS *priority = info;
1449 SERVER_START_REQ(get_process_info)
1451 req->handle = wine_server_obj_handle( handle );
1452 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1454 priority->PriorityClass = reply->priority;
1455 /* FIXME: Not yet supported by the wineserver */
1456 priority->Foreground = FALSE;
1459 SERVER_END_REQ;
1462 else ret = STATUS_INFO_LENGTH_MISMATCH;
1463 break;
1465 case ProcessCookie:
1466 FIXME( "ProcessCookie (%p,%p,0x%08x,%p) stub\n", handle, info, size, ret_len );
1467 if (handle == NtCurrentProcess())
1469 len = sizeof(ULONG);
1470 if (size == len) *(ULONG *)info = 0;
1471 else ret = STATUS_INFO_LENGTH_MISMATCH;
1473 else ret = STATUS_INVALID_PARAMETER;
1474 break;
1476 case ProcessImageInformation:
1477 len = sizeof(SECTION_IMAGE_INFORMATION);
1478 if (size == len)
1480 if (info)
1482 pe_image_info_t pe_info;
1484 SERVER_START_REQ( get_process_info )
1486 req->handle = wine_server_obj_handle( handle );
1487 wine_server_set_reply( req, &pe_info, sizeof(pe_info) );
1488 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1489 virtual_fill_image_information( &pe_info, info );
1491 SERVER_END_REQ;
1493 else ret = STATUS_ACCESS_VIOLATION;
1495 else ret = STATUS_INFO_LENGTH_MISMATCH;
1496 break;
1498 default:
1499 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
1500 handle, class, info, size, ret_len );
1501 ret = STATUS_INVALID_INFO_CLASS;
1502 break;
1505 if (ret_len) *ret_len = len;
1506 return ret;
1510 /**********************************************************************
1511 * NtSetInformationProcess (NTDLL.@)
1513 NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class, void *info, ULONG size )
1515 NTSTATUS ret = STATUS_SUCCESS;
1517 switch (class)
1519 case ProcessDefaultHardErrorMode:
1520 if (size != sizeof(UINT)) return STATUS_INVALID_PARAMETER;
1521 process_error_mode = *(UINT *)info;
1522 break;
1524 case ProcessAffinityMask:
1526 const ULONG_PTR system_mask = get_system_affinity_mask();
1528 if (size != sizeof(DWORD_PTR)) return STATUS_INVALID_PARAMETER;
1529 if (*(PDWORD_PTR)info & ~system_mask)
1530 return STATUS_INVALID_PARAMETER;
1531 if (!*(PDWORD_PTR)info)
1532 return STATUS_INVALID_PARAMETER;
1533 SERVER_START_REQ( set_process_info )
1535 req->handle = wine_server_obj_handle( handle );
1536 req->affinity = *(PDWORD_PTR)info;
1537 req->mask = SET_PROCESS_INFO_AFFINITY;
1538 ret = wine_server_call( req );
1540 SERVER_END_REQ;
1541 break;
1543 case ProcessPriorityClass:
1544 if (size != sizeof(PROCESS_PRIORITY_CLASS)) return STATUS_INVALID_PARAMETER;
1545 else
1547 PROCESS_PRIORITY_CLASS* ppc = info;
1549 SERVER_START_REQ( set_process_info )
1551 req->handle = wine_server_obj_handle( handle );
1552 /* FIXME Foreground isn't used */
1553 req->priority = ppc->PriorityClass;
1554 req->mask = SET_PROCESS_INFO_PRIORITY;
1555 ret = wine_server_call( req );
1557 SERVER_END_REQ;
1559 break;
1561 case ProcessExecuteFlags:
1562 if (is_win64 || size != sizeof(ULONG)) return STATUS_INVALID_PARAMETER;
1563 if (execute_flags & MEM_EXECUTE_OPTION_PERMANENT) return STATUS_ACCESS_DENIED;
1564 else
1566 BOOL enable;
1567 switch (*(ULONG *)info & (MEM_EXECUTE_OPTION_ENABLE|MEM_EXECUTE_OPTION_DISABLE))
1569 case MEM_EXECUTE_OPTION_ENABLE:
1570 enable = TRUE;
1571 break;
1572 case MEM_EXECUTE_OPTION_DISABLE:
1573 enable = FALSE;
1574 break;
1575 default:
1576 return STATUS_INVALID_PARAMETER;
1578 execute_flags = *(ULONG *)info;
1579 virtual_set_force_exec( enable );
1581 break;
1583 case ProcessThreadStackAllocation:
1585 void *addr = NULL;
1586 SIZE_T reserve;
1587 PROCESS_STACK_ALLOCATION_INFORMATION *stack = info;
1588 if (size == sizeof(PROCESS_STACK_ALLOCATION_INFORMATION_EX))
1589 stack = &((PROCESS_STACK_ALLOCATION_INFORMATION_EX *)info)->AllocInfo;
1590 else if (size != sizeof(*stack)) return STATUS_INFO_LENGTH_MISMATCH;
1592 reserve = stack->ReserveSize;
1593 ret = NtAllocateVirtualMemory( GetCurrentProcess(), &addr, stack->ZeroBits, &reserve,
1594 MEM_RESERVE, PAGE_READWRITE );
1595 if (!ret)
1597 #ifdef VALGRIND_STACK_REGISTER
1598 VALGRIND_STACK_REGISTER( addr, (char *)addr + reserve );
1599 #endif
1600 stack->StackBase = addr;
1602 break;
1605 default:
1606 FIXME( "(%p,0x%08x,%p,0x%08x) stub\n", handle, class, info, size );
1607 ret = STATUS_NOT_IMPLEMENTED;
1608 break;
1610 return ret;
1614 /**********************************************************************
1615 * NtOpenProcess (NTDLL.@)
1617 NTSTATUS WINAPI NtOpenProcess( HANDLE *handle, ACCESS_MASK access,
1618 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
1620 NTSTATUS status;
1622 SERVER_START_REQ( open_process )
1624 req->pid = HandleToULong( id->UniqueProcess );
1625 req->access = access;
1626 req->attributes = attr ? attr->Attributes : 0;
1627 status = wine_server_call( req );
1628 if (!status) *handle = wine_server_ptr_handle( reply->handle );
1630 SERVER_END_REQ;
1631 return status;
1635 /**********************************************************************
1636 * NtSuspendProcess (NTDLL.@)
1638 NTSTATUS WINAPI NtSuspendProcess( HANDLE handle )
1640 NTSTATUS ret;
1642 SERVER_START_REQ( suspend_process )
1644 req->handle = wine_server_obj_handle( handle );
1645 ret = wine_server_call( req );
1647 SERVER_END_REQ;
1648 return ret;
1652 /**********************************************************************
1653 * NtResumeProcess (NTDLL.@)
1655 NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
1657 NTSTATUS ret;
1659 SERVER_START_REQ( resume_process )
1661 req->handle = wine_server_obj_handle( handle );
1662 ret = wine_server_call( req );
1664 SERVER_END_REQ;
1665 return ret;