server: Return the NT name for the ProcessImageFileName query.
[wine.git] / dlls / ntdll / unix / process.c
blob6b7cbcd9c1a3788646ef9d12e855b2cf1dd73edf
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 #ifndef _WIN64
281 if (NtCurrentTeb64() && NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR]) *is_64bit = TRUE;
282 #endif
283 return TRUE;
285 if ((is_win64 || is_wow64) && path->Length > sizeof(wow64W) &&
286 !wcsnicmp( path->Buffer, wow64W, ARRAY_SIZE(wow64W) ))
288 *is_64bit = FALSE;
289 return TRUE;
291 return FALSE;
295 /***********************************************************************
296 * get_so_file_info
298 static BOOL get_so_file_info( HANDLE handle, pe_image_info_t *info )
300 union
302 struct
304 unsigned char magic[4];
305 unsigned char class;
306 unsigned char data;
307 unsigned char version;
308 unsigned char ignored1[9];
309 unsigned short type;
310 unsigned short machine;
311 unsigned char ignored2[8];
312 unsigned int phoff;
313 unsigned char ignored3[12];
314 unsigned short phnum;
315 } elf;
316 struct
318 unsigned char magic[4];
319 unsigned char class;
320 unsigned char data;
321 unsigned char ignored1[10];
322 unsigned short type;
323 unsigned short machine;
324 unsigned char ignored2[12];
325 unsigned __int64 phoff;
326 unsigned char ignored3[16];
327 unsigned short phnum;
328 } elf64;
329 struct
331 unsigned int magic;
332 unsigned int cputype;
333 unsigned int cpusubtype;
334 unsigned int filetype;
335 } macho;
336 IMAGE_DOS_HEADER mz;
337 } header;
339 IO_STATUS_BLOCK io;
340 LARGE_INTEGER offset;
342 offset.QuadPart = 0;
343 if (NtReadFile( handle, 0, NULL, NULL, &io, &header, sizeof(header), &offset, 0 )) return FALSE;
344 if (io.Information != sizeof(header)) return FALSE;
346 if (!memcmp( header.elf.magic, "\177ELF", 4 ))
348 unsigned int type;
349 unsigned short phnum;
351 if (header.elf.version != 1 /* EV_CURRENT */) return FALSE;
352 #ifdef WORDS_BIGENDIAN
353 if (header.elf.data != 2 /* ELFDATA2MSB */) return FALSE;
354 #else
355 if (header.elf.data != 1 /* ELFDATA2LSB */) return FALSE;
356 #endif
357 switch (header.elf.machine)
359 case 3: info->cpu = CPU_x86; break;
360 case 40: info->cpu = CPU_ARM; break;
361 case 62: info->cpu = CPU_x86_64; break;
362 case 183: info->cpu = CPU_ARM64; break;
364 if (header.elf.type != 3 /* ET_DYN */) return FALSE;
365 if (header.elf.class == 2 /* ELFCLASS64 */)
367 offset.QuadPart = header.elf64.phoff;
368 phnum = header.elf64.phnum;
370 else
372 offset.QuadPart = header.elf.phoff;
373 phnum = header.elf.phnum;
375 while (phnum--)
377 if (NtReadFile( handle, 0, NULL, NULL, &io, &type, sizeof(type), &offset, 0 )) return FALSE;
378 if (io.Information < sizeof(type)) return FALSE;
379 if (type == 3 /* PT_INTERP */) return FALSE;
380 offset.QuadPart += (header.elf.class == 2) ? 56 : 32;
382 return TRUE;
384 else if (header.macho.magic == 0xfeedface || header.macho.magic == 0xfeedfacf)
386 switch (header.macho.cputype)
388 case 0x00000007: info->cpu = CPU_x86; break;
389 case 0x01000007: info->cpu = CPU_x86_64; break;
390 case 0x0000000c: info->cpu = CPU_ARM; break;
391 case 0x0100000c: info->cpu = CPU_ARM64; break;
393 if (header.macho.filetype == 8) return TRUE;
395 return FALSE;
399 /***********************************************************************
400 * get_pe_file_info
402 static NTSTATUS get_pe_file_info( UNICODE_STRING *path, HANDLE *handle, pe_image_info_t *info )
404 NTSTATUS status;
405 HANDLE mapping;
406 OBJECT_ATTRIBUTES attr;
407 IO_STATUS_BLOCK io;
409 *handle = 0;
410 memset( info, 0, sizeof(*info) );
411 InitializeObjectAttributes( &attr, path, OBJ_CASE_INSENSITIVE, 0, 0 );
412 if ((status = NtOpenFile( handle, GENERIC_READ, &attr, &io,
413 FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT )))
415 BOOL is_64bit;
417 if (is_builtin_path( path, &is_64bit ))
419 TRACE( "assuming %u-bit builtin for %s\n", is_64bit ? 64 : 32, debugstr_us(path));
420 /* assume current arch */
421 #if defined(__i386__) || defined(__x86_64__)
422 info->cpu = is_64bit ? CPU_x86_64 : CPU_x86;
423 #else
424 info->cpu = client_cpu;
425 #endif
426 return STATUS_SUCCESS;
428 return status;
431 if (!(status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
432 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
433 NULL, NULL, PAGE_EXECUTE_READ, SEC_IMAGE, *handle )))
435 SERVER_START_REQ( get_mapping_info )
437 req->handle = wine_server_obj_handle( mapping );
438 req->access = SECTION_QUERY;
439 wine_server_set_reply( req, info, sizeof(*info) );
440 status = wine_server_call( req );
442 SERVER_END_REQ;
443 NtClose( mapping );
445 else if (status == STATUS_INVALID_IMAGE_NOT_MZ)
447 if (get_so_file_info( *handle, info )) return STATUS_SUCCESS;
449 return status;
453 /***********************************************************************
454 * get_env_size
456 static ULONG get_env_size( const RTL_USER_PROCESS_PARAMETERS *params, char **winedebug )
458 WCHAR *ptr = params->Environment;
460 while (*ptr)
462 static const WCHAR WINEDEBUG[] = {'W','I','N','E','D','E','B','U','G','=',0};
463 if (!*winedebug && !wcsncmp( ptr, WINEDEBUG, ARRAY_SIZE( WINEDEBUG ) - 1 ))
465 DWORD len = wcslen(ptr) * 3 + 1;
466 if ((*winedebug = malloc( len )))
467 ntdll_wcstoumbs( ptr, wcslen(ptr) + 1, *winedebug, len, FALSE );
469 ptr += wcslen(ptr) + 1;
471 ptr++;
472 return (ptr - params->Environment) * sizeof(WCHAR);
476 /***********************************************************************
477 * get_nt_pathname
479 * Simplified version of RtlDosPathNameToNtPathName_U.
481 static WCHAR *get_nt_pathname( const UNICODE_STRING *str )
483 static const WCHAR ntprefixW[] = {'\\','?','?','\\',0};
484 static const WCHAR uncprefixW[] = {'U','N','C','\\',0};
485 const WCHAR *name = str->Buffer;
486 WCHAR *ret;
488 if (!(ret = malloc( str->Length + 8 * sizeof(WCHAR) ))) return NULL;
490 wcscpy( ret, ntprefixW );
491 if (name[0] == '\\' && name[1] == '\\')
493 if ((name[2] == '.' || name[2] == '?') && name[3] == '\\') name += 4;
494 else
496 wcscat( ret, uncprefixW );
497 name += 2;
500 wcscat( ret, name );
501 return ret;
505 /***********************************************************************
506 * get_unix_curdir
508 static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params )
510 UNICODE_STRING nt_name;
511 OBJECT_ATTRIBUTES attr;
512 IO_STATUS_BLOCK io;
513 NTSTATUS status;
514 HANDLE handle;
515 int fd = -1;
517 if (!(nt_name.Buffer = get_nt_pathname( &params->CurrentDirectory.DosPath ))) return -1;
518 nt_name.Length = wcslen( nt_name.Buffer ) * sizeof(WCHAR);
520 InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
521 status = NtOpenFile( &handle, FILE_TRAVERSE | SYNCHRONIZE, &attr, &io,
522 FILE_SHARE_READ | FILE_SHARE_WRITE,
523 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
524 free( nt_name.Buffer );
525 if (status) return -1;
526 wine_server_handle_to_fd( handle, FILE_TRAVERSE, &fd, NULL );
527 NtClose( handle );
528 return fd;
532 /***********************************************************************
533 * set_stdio_fd
535 static void set_stdio_fd( int stdin_fd, int stdout_fd )
537 int fd = -1;
539 if (stdin_fd == -1 || stdout_fd == -1)
541 fd = open( "/dev/null", O_RDWR );
542 if (stdin_fd == -1) stdin_fd = fd;
543 if (stdout_fd == -1) stdout_fd = fd;
546 dup2( stdin_fd, 0 );
547 dup2( stdout_fd, 1 );
548 if (fd != -1) close( fd );
552 /***********************************************************************
553 * spawn_process
555 static NTSTATUS spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd,
556 int unixdir, char *winedebug, const pe_image_info_t *pe_info )
558 NTSTATUS status = STATUS_SUCCESS;
559 int stdin_fd = -1, stdout_fd = -1;
560 pid_t pid;
561 char **argv;
563 wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL );
564 wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL );
566 if (!(pid = fork())) /* child */
568 if (!(pid = fork())) /* grandchild */
570 if (params->ConsoleFlags ||
571 params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ ||
572 (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
574 setsid();
575 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
577 else set_stdio_fd( stdin_fd, stdout_fd );
579 if (stdin_fd != -1) close( stdin_fd );
580 if (stdout_fd != -1) close( stdout_fd );
582 if (winedebug) putenv( winedebug );
583 if (unixdir != -1)
585 fchdir( unixdir );
586 close( unixdir );
588 argv = build_argv( &params->CommandLine, 2 );
590 exec_wineloader( argv, socketfd, pe_info );
591 _exit(1);
594 _exit(pid == -1);
597 if (pid != -1)
599 /* reap child */
600 pid_t wret;
601 do {
602 wret = waitpid(pid, NULL, 0);
603 } while (wret < 0 && errno == EINTR);
605 else status = STATUS_NO_MEMORY;
607 if (stdin_fd != -1) close( stdin_fd );
608 if (stdout_fd != -1) close( stdout_fd );
609 return status;
613 /***********************************************************************
614 * exec_process
616 void DECLSPEC_NORETURN exec_process( NTSTATUS status )
618 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
619 pe_image_info_t pe_info;
620 int unixdir, socketfd[2];
621 char **argv;
622 HANDLE handle;
624 if (startup_info_size) goto done; /* started from another Win32 process */
626 switch (status)
628 case STATUS_CONFLICTING_ADDRESSES:
629 case STATUS_NO_MEMORY:
630 case STATUS_INVALID_IMAGE_FORMAT:
631 case STATUS_INVALID_IMAGE_NOT_MZ:
633 UNICODE_STRING image;
634 if (getenv( "WINEPRELOADRESERVE" )) goto done;
635 image.Buffer = get_nt_pathname( &params->ImagePathName );
636 image.Length = wcslen( image.Buffer ) * sizeof(WCHAR);
637 if ((status = get_pe_file_info( &image, &handle, &pe_info ))) goto done;
638 break;
640 case STATUS_INVALID_IMAGE_WIN_16:
641 case STATUS_INVALID_IMAGE_NE_FORMAT:
642 case STATUS_INVALID_IMAGE_PROTECT:
643 /* we'll start winevdm */
644 memset( &pe_info, 0, sizeof(pe_info) );
645 pe_info.cpu = CPU_x86;
646 break;
647 default:
648 goto done;
651 unixdir = get_unix_curdir( params );
653 if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
655 status = STATUS_TOO_MANY_OPENED_FILES;
656 goto done;
658 #ifdef SO_PASSCRED
659 else
661 int enable = 1;
662 setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
664 #endif
665 wine_server_send_fd( socketfd[1] );
666 close( socketfd[1] );
668 SERVER_START_REQ( exec_process )
670 req->socket_fd = socketfd[1];
671 req->cpu = pe_info.cpu;
672 status = wine_server_call( req );
674 SERVER_END_REQ;
676 if (!status)
678 if (!(argv = build_argv( &params->CommandLine, 2 )))
680 status = STATUS_NO_MEMORY;
681 goto done;
683 fchdir( unixdir );
686 status = exec_wineloader( argv, socketfd[0], &pe_info );
688 #ifdef __APPLE__
689 while (errno == ENOTSUP && terminate_main_thread());
690 #else
691 while (0);
692 #endif
693 free( argv );
695 close( socketfd[0] );
697 done:
698 switch (status)
700 case STATUS_INVALID_IMAGE_FORMAT:
701 case STATUS_INVALID_IMAGE_NOT_MZ:
702 ERR( "%s not supported on this system\n", debugstr_us(&params->ImagePathName) );
703 break;
704 default:
705 ERR( "failed to load %s error %x\n", debugstr_us(&params->ImagePathName), status );
706 break;
708 for (;;) NtTerminateProcess( GetCurrentProcess(), status );
712 /***********************************************************************
713 * fork_and_exec
715 * Fork and exec a new Unix binary, checking for errors.
717 static NTSTATUS fork_and_exec( UNICODE_STRING *path, int unixdir,
718 const RTL_USER_PROCESS_PARAMETERS *params )
720 pid_t pid;
721 int fd[2], stdin_fd = -1, stdout_fd = -1;
722 char **argv, **envp;
723 char *unix_name;
724 NTSTATUS status;
726 status = nt_to_unix_file_name( path, &unix_name, NULL, FILE_OPEN );
727 if (status) return status;
729 #ifdef HAVE_PIPE2
730 if (pipe2( fd, O_CLOEXEC ) == -1)
731 #endif
733 if (pipe(fd) == -1)
735 status = STATUS_TOO_MANY_OPENED_FILES;
736 goto done;
738 fcntl( fd[0], F_SETFD, FD_CLOEXEC );
739 fcntl( fd[1], F_SETFD, FD_CLOEXEC );
742 wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL );
743 wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL );
745 if (!(pid = fork())) /* child */
747 if (!(pid = fork())) /* grandchild */
749 close( fd[0] );
751 if (params->ConsoleFlags ||
752 params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ ||
753 (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
755 setsid();
756 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
758 else set_stdio_fd( stdin_fd, stdout_fd );
760 if (stdin_fd != -1) close( stdin_fd );
761 if (stdout_fd != -1) close( stdout_fd );
763 /* Reset signals that we previously set to SIG_IGN */
764 signal( SIGPIPE, SIG_DFL );
766 argv = build_argv( &params->CommandLine, 0 );
767 envp = build_envp( params->Environment );
768 if (unixdir != -1)
770 fchdir( unixdir );
771 close( unixdir );
773 execve( unix_name, argv, envp );
776 if (pid <= 0) /* grandchild if exec failed or child if fork failed */
778 switch (errno)
780 case EPERM:
781 case EACCES: status = STATUS_ACCESS_DENIED; break;
782 case ENOENT: status = STATUS_OBJECT_NAME_NOT_FOUND; break;
783 case EMFILE:
784 case ENFILE: status = STATUS_TOO_MANY_OPENED_FILES; break;
785 case ENOEXEC:
786 case EINVAL: status = STATUS_INVALID_IMAGE_FORMAT; break;
787 default: status = STATUS_NO_MEMORY; break;
789 write( fd[1], &status, sizeof(status) );
790 _exit(1);
792 _exit(0); /* child if fork succeeded */
794 close( fd[1] );
796 if (pid != -1)
798 /* reap child */
799 pid_t wret;
800 do {
801 wret = waitpid(pid, NULL, 0);
802 } while (wret < 0 && errno == EINTR);
803 read( fd[0], &status, sizeof(status) ); /* if we read something, exec or second fork failed */
805 else status = STATUS_NO_MEMORY;
807 close( fd[0] );
808 if (stdin_fd != -1) close( stdin_fd );
809 if (stdout_fd != -1) close( stdout_fd );
810 done:
811 free( unix_name );
812 return status;
815 static NTSTATUS alloc_handle_list( const PS_ATTRIBUTE *handles_attr, obj_handle_t **handles, data_size_t *handles_len )
817 SIZE_T count, i;
818 HANDLE *src;
820 *handles = NULL;
821 *handles_len = 0;
823 if (!handles_attr) return STATUS_SUCCESS;
825 count = handles_attr->Size / sizeof(HANDLE);
827 if (!(*handles = calloc( sizeof(**handles), count ))) return STATUS_NO_MEMORY;
829 src = handles_attr->ValuePtr;
830 for (i = 0; i < count; ++i)
831 (*handles)[i] = wine_server_obj_handle( src[i] );
833 *handles_len = count * sizeof(**handles);
835 return STATUS_SUCCESS;
838 /**********************************************************************
839 * NtCreateUserProcess (NTDLL.@)
841 NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_handle_ptr,
842 ACCESS_MASK process_access, ACCESS_MASK thread_access,
843 OBJECT_ATTRIBUTES *process_attr, OBJECT_ATTRIBUTES *thread_attr,
844 ULONG process_flags, ULONG thread_flags,
845 RTL_USER_PROCESS_PARAMETERS *params, PS_CREATE_INFO *info,
846 PS_ATTRIBUTE_LIST *attr )
848 NTSTATUS status;
849 BOOL success = FALSE;
850 HANDLE file_handle, process_info = 0, process_handle = 0, thread_handle = 0;
851 struct object_attributes *objattr;
852 data_size_t attr_len;
853 char *winedebug = NULL;
854 startup_info_t *startup_info = NULL;
855 ULONG startup_info_size, env_size;
856 int unixdir, socketfd[2] = { -1, -1 };
857 pe_image_info_t pe_info;
858 CLIENT_ID id;
859 HANDLE parent = 0, debug = 0, token = 0;
860 UNICODE_STRING path = {0};
861 SIZE_T i, attr_count = (attr->TotalLength - sizeof(attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
862 const PS_ATTRIBUTE *handles_attr = NULL;
863 data_size_t handles_size;
864 obj_handle_t *handles;
866 for (i = 0; i < attr_count; i++)
868 switch (attr->Attributes[i].Attribute)
870 case PS_ATTRIBUTE_PARENT_PROCESS:
871 parent = attr->Attributes[i].ValuePtr;
872 break;
873 case PS_ATTRIBUTE_DEBUG_PORT:
874 debug = attr->Attributes[i].ValuePtr;
875 break;
876 case PS_ATTRIBUTE_IMAGE_NAME:
877 path.Length = attr->Attributes[i].Size;
878 path.Buffer = attr->Attributes[i].ValuePtr;
879 break;
880 case PS_ATTRIBUTE_TOKEN:
881 token = attr->Attributes[i].ValuePtr;
882 break;
883 case PS_ATTRIBUTE_HANDLE_LIST:
884 if (process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES)
885 handles_attr = &attr->Attributes[i];
886 break;
887 default:
888 if (attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT)
889 FIXME( "unhandled input attribute %lx\n", attr->Attributes[i].Attribute );
890 break;
894 TRACE( "%s image %s cmdline %s parent %p\n", debugstr_us( &path ),
895 debugstr_us( &params->ImagePathName ), debugstr_us( &params->CommandLine ), parent );
897 unixdir = get_unix_curdir( params );
899 if ((status = get_pe_file_info( &path, &file_handle, &pe_info )))
901 if (status == STATUS_INVALID_IMAGE_NOT_MZ && !fork_and_exec( &path, unixdir, params ))
903 memset( info, 0, sizeof(*info) );
904 return STATUS_SUCCESS;
906 goto done;
908 if (!(startup_info = create_startup_info( params, &startup_info_size ))) goto done;
909 env_size = get_env_size( params, &winedebug );
911 if ((status = alloc_object_attributes( process_attr, &objattr, &attr_len ))) goto done;
913 if ((status = alloc_handle_list( handles_attr, &handles, &handles_size )))
915 free( objattr );
916 goto done;
919 /* create the socket for the new process */
921 if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
923 status = STATUS_TOO_MANY_OPENED_FILES;
924 free( objattr );
925 free( handles );
926 goto done;
928 #ifdef SO_PASSCRED
929 else
931 int enable = 1;
932 setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
934 #endif
936 wine_server_send_fd( socketfd[1] );
937 close( socketfd[1] );
939 /* create the process on the server side */
941 SERVER_START_REQ( new_process )
943 req->token = wine_server_obj_handle( token );
944 req->debug = wine_server_obj_handle( debug );
945 req->parent_process = wine_server_obj_handle( parent );
946 req->inherit_all = !!(process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES);
947 req->create_flags = params->DebugFlags; /* hack: creation flags stored in DebugFlags for now */
948 req->socket_fd = socketfd[1];
949 req->access = process_access;
950 req->cpu = pe_info.cpu;
951 req->info_size = startup_info_size;
952 req->handles_size = handles_size;
953 wine_server_add_data( req, objattr, attr_len );
954 wine_server_add_data( req, handles, handles_size );
955 wine_server_add_data( req, startup_info, startup_info_size );
956 wine_server_add_data( req, params->Environment, env_size );
957 if (!(status = wine_server_call( req )))
959 process_handle = wine_server_ptr_handle( reply->handle );
960 id.UniqueProcess = ULongToHandle( reply->pid );
962 process_info = wine_server_ptr_handle( reply->info );
964 SERVER_END_REQ;
965 free( objattr );
966 free( handles );
968 if (status)
970 switch (status)
972 case STATUS_INVALID_IMAGE_WIN_64:
973 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_us(&path) );
974 break;
975 case STATUS_INVALID_IMAGE_FORMAT:
976 ERR( "%s not supported on this installation (%s binary)\n",
977 debugstr_us(&path), cpu_names[pe_info.cpu] );
978 break;
980 goto done;
983 if ((status = alloc_object_attributes( thread_attr, &objattr, &attr_len ))) goto done;
985 SERVER_START_REQ( new_thread )
987 req->process = wine_server_obj_handle( process_handle );
988 req->access = thread_access;
989 req->suspend = !!(thread_flags & THREAD_CREATE_FLAGS_CREATE_SUSPENDED);
990 req->request_fd = -1;
991 wine_server_add_data( req, objattr, attr_len );
992 if (!(status = wine_server_call( req )))
994 thread_handle = wine_server_ptr_handle( reply->handle );
995 id.UniqueThread = ULongToHandle( reply->tid );
998 SERVER_END_REQ;
999 free( objattr );
1000 if (status) goto done;
1002 /* create the child process */
1004 if ((status = spawn_process( params, socketfd[0], unixdir, winedebug, &pe_info ))) goto done;
1006 close( socketfd[0] );
1007 socketfd[0] = -1;
1009 /* wait for the new process info to be ready */
1011 NtWaitForSingleObject( process_info, FALSE, NULL );
1012 SERVER_START_REQ( get_new_process_info )
1014 req->info = wine_server_obj_handle( process_info );
1015 wine_server_call( req );
1016 success = reply->success;
1017 status = reply->exit_code;
1019 SERVER_END_REQ;
1021 if (!success)
1023 if (!status) status = STATUS_INTERNAL_ERROR;
1024 goto done;
1027 TRACE( "%s pid %04x tid %04x handles %p/%p\n", debugstr_us(&path),
1028 HandleToULong(id.UniqueProcess), HandleToULong(id.UniqueThread),
1029 process_handle, thread_handle );
1031 /* update output attributes */
1033 for (i = 0; i < attr_count; i++)
1035 switch (attr->Attributes[i].Attribute)
1037 case PS_ATTRIBUTE_CLIENT_ID:
1039 SIZE_T size = min( attr->Attributes[i].Size, sizeof(id) );
1040 memcpy( attr->Attributes[i].ValuePtr, &id, size );
1041 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
1042 break;
1044 case PS_ATTRIBUTE_IMAGE_INFO:
1046 SECTION_IMAGE_INFORMATION info;
1047 SIZE_T size = min( attr->Attributes[i].Size, sizeof(info) );
1048 virtual_fill_image_information( &pe_info, &info );
1049 memcpy( attr->Attributes[i].ValuePtr, &info, size );
1050 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
1051 break;
1053 case PS_ATTRIBUTE_TEB_ADDRESS:
1054 default:
1055 if (!(attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT))
1056 FIXME( "unhandled output attribute %lx\n", attr->Attributes[i].Attribute );
1057 break;
1060 *process_handle_ptr = process_handle;
1061 *thread_handle_ptr = thread_handle;
1062 process_handle = thread_handle = 0;
1063 status = STATUS_SUCCESS;
1065 done:
1066 if (file_handle) NtClose( file_handle );
1067 if (process_info) NtClose( process_info );
1068 if (process_handle) NtClose( process_handle );
1069 if (thread_handle) NtClose( thread_handle );
1070 if (socketfd[0] != -1) close( socketfd[0] );
1071 if (unixdir != -1) close( unixdir );
1072 free( startup_info );
1073 free( winedebug );
1074 return status;
1078 /******************************************************************************
1079 * NtTerminateProcess (NTDLL.@)
1081 NTSTATUS WINAPI NtTerminateProcess( HANDLE handle, LONG exit_code )
1083 NTSTATUS ret;
1084 BOOL self;
1086 SERVER_START_REQ( terminate_process )
1088 req->handle = wine_server_obj_handle( handle );
1089 req->exit_code = exit_code;
1090 ret = wine_server_call( req );
1091 self = reply->self;
1093 SERVER_END_REQ;
1094 if (self)
1096 if (!handle) process_exiting = TRUE;
1097 else if (process_exiting) exit_process( exit_code );
1098 else abort_process( exit_code );
1100 return ret;
1104 #if defined(HAVE_MACH_MACH_H)
1106 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1108 #if defined(MACH_TASK_BASIC_INFO)
1109 struct mach_task_basic_info info;
1111 if (unix_pid != -1) return; /* FIXME: Retrieve information for other processes. */
1113 mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
1114 if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS)
1116 pvmi->VirtualSize = info.resident_size + info.virtual_size;
1117 pvmi->PagefileUsage = info.virtual_size;
1118 pvmi->WorkingSetSize = info.resident_size;
1119 pvmi->PeakWorkingSetSize = info.resident_size_max;
1121 #endif
1124 #elif defined(linux)
1126 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1128 FILE *f;
1129 char line[256], path[26];
1130 unsigned long value;
1132 if (unix_pid == -1)
1133 strcpy( path, "/proc/self/status" );
1134 else
1135 sprintf( path, "/proc/%u/status", unix_pid);
1136 f = fopen( path, "r" );
1137 if (!f) return;
1139 while (fgets(line, sizeof(line), f))
1141 if (sscanf(line, "VmPeak: %lu", &value))
1142 pvmi->PeakVirtualSize = (ULONG64)value * 1024;
1143 else if (sscanf(line, "VmSize: %lu", &value))
1144 pvmi->VirtualSize = (ULONG64)value * 1024;
1145 else if (sscanf(line, "VmHWM: %lu", &value))
1146 pvmi->PeakWorkingSetSize = (ULONG64)value * 1024;
1147 else if (sscanf(line, "VmRSS: %lu", &value))
1148 pvmi->WorkingSetSize = (ULONG64)value * 1024;
1149 else if (sscanf(line, "RssAnon: %lu", &value))
1150 pvmi->PagefileUsage += (ULONG64)value * 1024;
1151 else if (sscanf(line, "VmSwap: %lu", &value))
1152 pvmi->PagefileUsage += (ULONG64)value * 1024;
1154 pvmi->PeakPagefileUsage = pvmi->PagefileUsage;
1156 fclose(f);
1159 #else
1161 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1163 /* FIXME : real data */
1166 #endif
1168 #define UNIMPLEMENTED_INFO_CLASS(c) \
1169 case c: \
1170 FIXME( "(process=%p) Unimplemented information class: " #c "\n", handle); \
1171 ret = STATUS_INVALID_INFO_CLASS; \
1172 break
1174 /**********************************************************************
1175 * NtQueryInformationProcess (NTDLL.@)
1177 NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class, void *info,
1178 ULONG size, ULONG *ret_len )
1180 NTSTATUS ret = STATUS_SUCCESS;
1181 ULONG len = 0;
1183 TRACE( "(%p,0x%08x,%p,0x%08x,%p)\n", handle, class, info, size, ret_len );
1185 switch (class)
1187 UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits);
1188 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority);
1189 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority);
1190 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort);
1191 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken);
1192 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation);
1193 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize);
1194 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers);
1195 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits);
1196 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch);
1197 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL);
1198 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup);
1199 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information);
1200 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost);
1201 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap);
1202 UNIMPLEMENTED_INFO_CLASS(ProcessSessionInformation);
1203 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation);
1204 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled);
1205 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination);
1206 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing);
1208 case ProcessBasicInformation:
1210 PROCESS_BASIC_INFORMATION pbi;
1211 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1213 if (size >= sizeof(PROCESS_BASIC_INFORMATION))
1215 if (!info) ret = STATUS_ACCESS_VIOLATION;
1216 else
1218 SERVER_START_REQ(get_process_info)
1220 req->handle = wine_server_obj_handle( handle );
1221 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1223 pbi.ExitStatus = reply->exit_code;
1224 pbi.PebBaseAddress = wine_server_get_ptr( reply->peb );
1225 pbi.AffinityMask = reply->affinity & affinity_mask;
1226 pbi.BasePriority = reply->priority;
1227 pbi.UniqueProcessId = reply->pid;
1228 pbi.InheritedFromUniqueProcessId = reply->ppid;
1231 SERVER_END_REQ;
1233 memcpy( info, &pbi, sizeof(PROCESS_BASIC_INFORMATION) );
1234 len = sizeof(PROCESS_BASIC_INFORMATION);
1236 if (size > sizeof(PROCESS_BASIC_INFORMATION)) ret = STATUS_INFO_LENGTH_MISMATCH;
1238 else
1240 len = sizeof(PROCESS_BASIC_INFORMATION);
1241 ret = STATUS_INFO_LENGTH_MISMATCH;
1244 break;
1246 case ProcessIoCounters:
1248 IO_COUNTERS pii;
1250 if (size >= sizeof(IO_COUNTERS))
1252 if (!info) ret = STATUS_ACCESS_VIOLATION;
1253 else if (!handle) ret = STATUS_INVALID_HANDLE;
1254 else
1256 /* FIXME : real data */
1257 memset(&pii, 0 , sizeof(IO_COUNTERS));
1258 memcpy(info, &pii, sizeof(IO_COUNTERS));
1259 len = sizeof(IO_COUNTERS);
1261 if (size > sizeof(IO_COUNTERS)) ret = STATUS_INFO_LENGTH_MISMATCH;
1263 else
1265 len = sizeof(IO_COUNTERS);
1266 ret = STATUS_INFO_LENGTH_MISMATCH;
1269 break;
1271 case ProcessVmCounters:
1273 VM_COUNTERS_EX pvmi;
1275 /* older Windows versions don't have the PrivateUsage field */
1276 if (size >= sizeof(VM_COUNTERS))
1278 if (!info) ret = STATUS_ACCESS_VIOLATION;
1279 else
1281 memset(&pvmi, 0, sizeof(pvmi));
1282 if (handle == GetCurrentProcess()) fill_vm_counters( &pvmi, -1 );
1283 else
1285 SERVER_START_REQ(get_process_vm_counters)
1287 req->handle = wine_server_obj_handle( handle );
1288 if (!(ret = wine_server_call( req )))
1290 pvmi.PeakVirtualSize = reply->peak_virtual_size;
1291 pvmi.VirtualSize = reply->virtual_size;
1292 pvmi.PeakWorkingSetSize = reply->peak_working_set_size;
1293 pvmi.WorkingSetSize = reply->working_set_size;
1294 pvmi.PagefileUsage = reply->pagefile_usage;
1295 pvmi.PeakPagefileUsage = reply->peak_pagefile_usage;
1298 SERVER_END_REQ;
1299 if (ret) break;
1301 if (size >= sizeof(VM_COUNTERS_EX))
1302 pvmi.PrivateUsage = pvmi.PagefileUsage;
1303 len = size;
1304 if (len != sizeof(VM_COUNTERS)) len = sizeof(VM_COUNTERS_EX);
1305 memcpy(info, &pvmi, min(size, sizeof(pvmi)));
1307 if (size != sizeof(VM_COUNTERS) && size != sizeof(VM_COUNTERS_EX))
1308 ret = STATUS_INFO_LENGTH_MISMATCH;
1310 else
1312 len = sizeof(pvmi);
1313 ret = STATUS_INFO_LENGTH_MISMATCH;
1316 break;
1318 case ProcessTimes:
1320 KERNEL_USER_TIMES pti = {{{0}}};
1322 if (size >= sizeof(KERNEL_USER_TIMES))
1324 if (!info) ret = STATUS_ACCESS_VIOLATION;
1325 else if (!handle) ret = STATUS_INVALID_HANDLE;
1326 else
1328 long ticks = sysconf(_SC_CLK_TCK);
1329 struct tms tms;
1331 /* FIXME: user/kernel times only work for current process */
1332 if (ticks && times( &tms ) != -1)
1334 pti.UserTime.QuadPart = (ULONGLONG)tms.tms_utime * 10000000 / ticks;
1335 pti.KernelTime.QuadPart = (ULONGLONG)tms.tms_stime * 10000000 / ticks;
1338 SERVER_START_REQ(get_process_info)
1340 req->handle = wine_server_obj_handle( handle );
1341 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1343 pti.CreateTime.QuadPart = reply->start_time;
1344 pti.ExitTime.QuadPart = reply->end_time;
1347 SERVER_END_REQ;
1349 memcpy(info, &pti, sizeof(KERNEL_USER_TIMES));
1350 len = sizeof(KERNEL_USER_TIMES);
1352 if (size > sizeof(KERNEL_USER_TIMES)) ret = STATUS_INFO_LENGTH_MISMATCH;
1354 else
1356 len = sizeof(KERNEL_USER_TIMES);
1357 ret = STATUS_INFO_LENGTH_MISMATCH;
1360 break;
1362 case ProcessDebugPort:
1363 len = sizeof(DWORD_PTR);
1364 if (size == len)
1366 if (!info) ret = STATUS_ACCESS_VIOLATION;
1367 else
1369 HANDLE debug;
1371 SERVER_START_REQ(get_process_debug_info)
1373 req->handle = wine_server_obj_handle( handle );
1374 ret = wine_server_call( req );
1375 debug = wine_server_ptr_handle( reply->debug );
1377 SERVER_END_REQ;
1378 if (ret == STATUS_SUCCESS)
1380 *(DWORD_PTR *)info = ~0ul;
1381 NtClose( debug );
1383 else if (ret == STATUS_PORT_NOT_SET)
1385 *(DWORD_PTR *)info = 0;
1386 ret = STATUS_SUCCESS;
1390 else ret = STATUS_INFO_LENGTH_MISMATCH;
1391 break;
1393 case ProcessDebugFlags:
1394 len = sizeof(DWORD);
1395 if (size == len)
1397 if (!info) ret = STATUS_ACCESS_VIOLATION;
1398 else
1400 HANDLE debug;
1402 SERVER_START_REQ(get_process_debug_info)
1404 req->handle = wine_server_obj_handle( handle );
1405 ret = wine_server_call( req );
1406 debug = wine_server_ptr_handle( reply->debug );
1407 *(DWORD *)info = reply->debug_children;
1409 SERVER_END_REQ;
1410 if (ret == STATUS_SUCCESS) NtClose( debug );
1411 else if (ret == STATUS_PORT_NOT_SET) ret = STATUS_SUCCESS;
1414 else ret = STATUS_INFO_LENGTH_MISMATCH;
1415 break;
1417 case ProcessDefaultHardErrorMode:
1418 len = sizeof(process_error_mode);
1419 if (size == len) memcpy(info, &process_error_mode, len);
1420 else ret = STATUS_INFO_LENGTH_MISMATCH;
1421 break;
1423 case ProcessDebugObjectHandle:
1424 len = sizeof(HANDLE);
1425 if (size == len)
1427 if (!info) ret = STATUS_ACCESS_VIOLATION;
1428 else
1430 SERVER_START_REQ(get_process_debug_info)
1432 req->handle = wine_server_obj_handle( handle );
1433 ret = wine_server_call( req );
1434 *(HANDLE *)info = wine_server_ptr_handle( reply->debug );
1436 SERVER_END_REQ;
1439 else ret = STATUS_INFO_LENGTH_MISMATCH;
1440 break;
1442 case ProcessHandleCount:
1443 if (size >= 4)
1445 if (!info) ret = STATUS_ACCESS_VIOLATION;
1446 else if (!handle) ret = STATUS_INVALID_HANDLE;
1447 else
1449 memset(info, 0, 4);
1450 len = 4;
1452 if (size > 4) ret = STATUS_INFO_LENGTH_MISMATCH;
1454 else
1456 len = 4;
1457 ret = STATUS_INFO_LENGTH_MISMATCH;
1459 break;
1461 case ProcessAffinityMask:
1462 len = sizeof(ULONG_PTR);
1463 if (size == len)
1465 const ULONG_PTR system_mask = get_system_affinity_mask();
1467 SERVER_START_REQ(get_process_info)
1469 req->handle = wine_server_obj_handle( handle );
1470 if (!(ret = wine_server_call( req )))
1471 *(ULONG_PTR *)info = reply->affinity & system_mask;
1473 SERVER_END_REQ;
1475 else ret = STATUS_INFO_LENGTH_MISMATCH;
1476 break;
1478 case ProcessWow64Information:
1479 len = sizeof(ULONG_PTR);
1480 if (size != len) ret = STATUS_INFO_LENGTH_MISMATCH;
1481 else if (!info) ret = STATUS_ACCESS_VIOLATION;
1482 else if (!handle) ret = STATUS_INVALID_HANDLE;
1483 else
1485 ULONG_PTR val = 0;
1487 if (handle == GetCurrentProcess()) val = is_wow64;
1488 else if (server_cpus & ((1 << CPU_x86_64) | (1 << CPU_ARM64)))
1490 SERVER_START_REQ( get_process_info )
1492 req->handle = wine_server_obj_handle( handle );
1493 if (!(ret = wine_server_call( req )))
1494 val = (reply->cpu != CPU_x86_64 && reply->cpu != CPU_ARM64);
1496 SERVER_END_REQ;
1498 *(ULONG_PTR *)info = val;
1500 break;
1502 case ProcessImageFileName:
1503 /* FIXME: Should return a device path */
1504 case ProcessImageFileNameWin32:
1505 SERVER_START_REQ( get_process_image_name )
1507 UNICODE_STRING *str = info;
1509 req->handle = wine_server_obj_handle( handle );
1510 req->win32 = (class == ProcessImageFileNameWin32);
1511 wine_server_set_reply( req, str ? str + 1 : NULL,
1512 size > sizeof(UNICODE_STRING) ? size - sizeof(UNICODE_STRING) : 0 );
1513 ret = wine_server_call( req );
1514 if (ret == STATUS_BUFFER_TOO_SMALL) ret = STATUS_INFO_LENGTH_MISMATCH;
1515 len = sizeof(UNICODE_STRING) + reply->len;
1516 if (ret == STATUS_SUCCESS)
1518 str->MaximumLength = str->Length = reply->len;
1519 str->Buffer = (PWSTR)(str + 1);
1522 SERVER_END_REQ;
1523 break;
1525 case ProcessExecuteFlags:
1526 len = sizeof(ULONG);
1527 if (size == len) *(ULONG *)info = execute_flags;
1528 else ret = STATUS_INFO_LENGTH_MISMATCH;
1529 break;
1531 case ProcessPriorityClass:
1532 len = sizeof(PROCESS_PRIORITY_CLASS);
1533 if (size == len)
1535 if (!info) ret = STATUS_ACCESS_VIOLATION;
1536 else
1538 PROCESS_PRIORITY_CLASS *priority = info;
1540 SERVER_START_REQ(get_process_info)
1542 req->handle = wine_server_obj_handle( handle );
1543 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1545 priority->PriorityClass = reply->priority;
1546 /* FIXME: Not yet supported by the wineserver */
1547 priority->Foreground = FALSE;
1550 SERVER_END_REQ;
1553 else ret = STATUS_INFO_LENGTH_MISMATCH;
1554 break;
1556 case ProcessCookie:
1557 FIXME( "ProcessCookie (%p,%p,0x%08x,%p) stub\n", handle, info, size, ret_len );
1558 if (handle == NtCurrentProcess())
1560 len = sizeof(ULONG);
1561 if (size == len) *(ULONG *)info = 0;
1562 else ret = STATUS_INFO_LENGTH_MISMATCH;
1564 else ret = STATUS_INVALID_PARAMETER;
1565 break;
1567 case ProcessImageInformation:
1568 len = sizeof(SECTION_IMAGE_INFORMATION);
1569 if (size == len)
1571 if (info)
1573 pe_image_info_t pe_info;
1575 SERVER_START_REQ( get_process_info )
1577 req->handle = wine_server_obj_handle( handle );
1578 wine_server_set_reply( req, &pe_info, sizeof(pe_info) );
1579 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1580 virtual_fill_image_information( &pe_info, info );
1582 SERVER_END_REQ;
1584 else ret = STATUS_ACCESS_VIOLATION;
1586 else ret = STATUS_INFO_LENGTH_MISMATCH;
1587 break;
1589 default:
1590 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
1591 handle, class, info, size, ret_len );
1592 ret = STATUS_INVALID_INFO_CLASS;
1593 break;
1596 if (ret_len) *ret_len = len;
1597 return ret;
1601 /**********************************************************************
1602 * NtSetInformationProcess (NTDLL.@)
1604 NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class, void *info, ULONG size )
1606 NTSTATUS ret = STATUS_SUCCESS;
1608 switch (class)
1610 case ProcessDefaultHardErrorMode:
1611 if (size != sizeof(UINT)) return STATUS_INVALID_PARAMETER;
1612 process_error_mode = *(UINT *)info;
1613 break;
1615 case ProcessAffinityMask:
1617 const ULONG_PTR system_mask = get_system_affinity_mask();
1619 if (size != sizeof(DWORD_PTR)) return STATUS_INVALID_PARAMETER;
1620 if (*(PDWORD_PTR)info & ~system_mask)
1621 return STATUS_INVALID_PARAMETER;
1622 if (!*(PDWORD_PTR)info)
1623 return STATUS_INVALID_PARAMETER;
1624 SERVER_START_REQ( set_process_info )
1626 req->handle = wine_server_obj_handle( handle );
1627 req->affinity = *(PDWORD_PTR)info;
1628 req->mask = SET_PROCESS_INFO_AFFINITY;
1629 ret = wine_server_call( req );
1631 SERVER_END_REQ;
1632 break;
1634 case ProcessPriorityClass:
1635 if (size != sizeof(PROCESS_PRIORITY_CLASS)) return STATUS_INVALID_PARAMETER;
1636 else
1638 PROCESS_PRIORITY_CLASS* ppc = info;
1640 SERVER_START_REQ( set_process_info )
1642 req->handle = wine_server_obj_handle( handle );
1643 /* FIXME Foreground isn't used */
1644 req->priority = ppc->PriorityClass;
1645 req->mask = SET_PROCESS_INFO_PRIORITY;
1646 ret = wine_server_call( req );
1648 SERVER_END_REQ;
1650 break;
1652 case ProcessExecuteFlags:
1653 if (is_win64 || size != sizeof(ULONG)) return STATUS_INVALID_PARAMETER;
1654 if (execute_flags & MEM_EXECUTE_OPTION_PERMANENT) return STATUS_ACCESS_DENIED;
1655 else
1657 BOOL enable;
1658 switch (*(ULONG *)info & (MEM_EXECUTE_OPTION_ENABLE|MEM_EXECUTE_OPTION_DISABLE))
1660 case MEM_EXECUTE_OPTION_ENABLE:
1661 enable = TRUE;
1662 break;
1663 case MEM_EXECUTE_OPTION_DISABLE:
1664 enable = FALSE;
1665 break;
1666 default:
1667 return STATUS_INVALID_PARAMETER;
1669 execute_flags = *(ULONG *)info;
1670 virtual_set_force_exec( enable );
1672 break;
1674 case ProcessThreadStackAllocation:
1676 void *addr = NULL;
1677 SIZE_T reserve;
1678 PROCESS_STACK_ALLOCATION_INFORMATION *stack = info;
1679 if (size == sizeof(PROCESS_STACK_ALLOCATION_INFORMATION_EX))
1680 stack = &((PROCESS_STACK_ALLOCATION_INFORMATION_EX *)info)->AllocInfo;
1681 else if (size != sizeof(*stack)) return STATUS_INFO_LENGTH_MISMATCH;
1683 reserve = stack->ReserveSize;
1684 ret = NtAllocateVirtualMemory( GetCurrentProcess(), &addr, stack->ZeroBits, &reserve,
1685 MEM_RESERVE, PAGE_READWRITE );
1686 if (!ret)
1688 #ifdef VALGRIND_STACK_REGISTER
1689 VALGRIND_STACK_REGISTER( addr, (char *)addr + reserve );
1690 #endif
1691 stack->StackBase = addr;
1693 break;
1696 default:
1697 FIXME( "(%p,0x%08x,%p,0x%08x) stub\n", handle, class, info, size );
1698 ret = STATUS_NOT_IMPLEMENTED;
1699 break;
1701 return ret;
1705 /**********************************************************************
1706 * NtOpenProcess (NTDLL.@)
1708 NTSTATUS WINAPI NtOpenProcess( HANDLE *handle, ACCESS_MASK access,
1709 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
1711 NTSTATUS status;
1713 SERVER_START_REQ( open_process )
1715 req->pid = HandleToULong( id->UniqueProcess );
1716 req->access = access;
1717 req->attributes = attr ? attr->Attributes : 0;
1718 status = wine_server_call( req );
1719 if (!status) *handle = wine_server_ptr_handle( reply->handle );
1721 SERVER_END_REQ;
1722 return status;
1726 /**********************************************************************
1727 * NtSuspendProcess (NTDLL.@)
1729 NTSTATUS WINAPI NtSuspendProcess( HANDLE handle )
1731 NTSTATUS ret;
1733 SERVER_START_REQ( suspend_process )
1735 req->handle = wine_server_obj_handle( handle );
1736 ret = wine_server_call( req );
1738 SERVER_END_REQ;
1739 return ret;
1743 /**********************************************************************
1744 * NtResumeProcess (NTDLL.@)
1746 NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
1748 NTSTATUS ret;
1750 SERVER_START_REQ( resume_process )
1752 req->handle = wine_server_obj_handle( handle );
1753 ret = wine_server_call( req );
1755 SERVER_END_REQ;
1756 return ret;
1760 /**********************************************************************
1761 * NtDebugActiveProcess (NTDLL.@)
1763 NTSTATUS WINAPI NtDebugActiveProcess( HANDLE process, HANDLE debug )
1765 NTSTATUS ret;
1767 SERVER_START_REQ( debug_process )
1769 req->handle = wine_server_obj_handle( process );
1770 req->debug = wine_server_obj_handle( debug );
1771 req->attach = 1;
1772 ret = wine_server_call( req );
1774 SERVER_END_REQ;
1775 return ret;
1779 /**********************************************************************
1780 * NtRemoveProcessDebug (NTDLL.@)
1782 NTSTATUS WINAPI NtRemoveProcessDebug( HANDLE process, HANDLE debug )
1784 NTSTATUS ret;
1786 SERVER_START_REQ( debug_process )
1788 req->handle = wine_server_obj_handle( process );
1789 req->debug = wine_server_obj_handle( debug );
1790 req->attach = 0;
1791 ret = wine_server_call( req );
1793 SERVER_END_REQ;
1794 return ret;
1798 /**********************************************************************
1799 * NtDebugContinue (NTDLL.@)
1801 NTSTATUS WINAPI NtDebugContinue( HANDLE handle, CLIENT_ID *client, NTSTATUS status )
1803 NTSTATUS ret;
1805 SERVER_START_REQ( continue_debug_event )
1807 req->debug = wine_server_obj_handle( handle );
1808 req->pid = HandleToULong( client->UniqueProcess );
1809 req->tid = HandleToULong( client->UniqueThread );
1810 req->status = status;
1811 ret = wine_server_call( req );
1813 SERVER_END_REQ;
1814 return ret;
1818 /***********************************************************************
1819 * __wine_make_process_system (NTDLL.@)
1821 * Mark the current process as a system process.
1822 * Returns the event that is signaled when all non-system processes have exited.
1824 HANDLE CDECL __wine_make_process_system(void)
1826 HANDLE ret = 0;
1828 SERVER_START_REQ( make_process_system )
1830 if (!wine_server_call( req )) ret = wine_server_ptr_handle( reply->event );
1832 SERVER_END_REQ;
1833 return ret;