4 * Copyright 1996-1998 Marcus Meissner
5 * Copyright 2018, 2020 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
40 #ifdef HAVE_SYS_TIME_H
41 # include <sys/time.h>
43 #ifdef HAVE_SYS_TIMES_H
44 # include <sys/times.h>
46 #include <sys/types.h>
47 #ifdef HAVE_SYS_WAIT_H
48 # include <sys/wait.h>
54 # include <CoreFoundation/CoreFoundation.h>
57 #ifdef HAVE_MACH_MACH_H
58 # include <mach/mach.h>
62 #define WIN32_NO_STATUS
65 #include "unix_private.h"
66 #include "wine/exception.h"
67 #include "wine/server.h"
68 #include "wine/debug.h"
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
);
92 argc
= reserved
+ 2 + len
/ 2;
93 argv
= malloc( argc
* sizeof(*argv
) + len
);
94 arg
= dst
= (char *)(argv
+ argc
);
98 if ((*src
== ' ' || *src
== '\t') && !in_quotes
)
100 /* skip the remaining spaces */
101 while (*src
== ' ' || *src
== '\t') src
++;
103 /* close the argument and copy it */
106 /* start with a new argument */
110 else if (*src
== '\\')
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.
124 if (in_quotes
&& *src
== '"') *dst
++ = *src
++;
125 else in_quotes
= !in_quotes
;
129 /* Preceded by an odd number of '\', this is half that
130 * number of '\' followed by a '"'
132 dst
-= bcount
/ 2 + 1;
137 else /* a regular character */
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)
173 CFRunLoopSourceContext source_context
= { 0 };
174 CFRunLoopSourceRef source
;
176 source_context
.perform
= pthread_exit
;
177 if (!(source
= CFRunLoopSourceCreate( NULL
, 0, &source_context
)))
180 CFRunLoopAddSource( CFRunLoopGetMain(), source
, kCFRunLoopCommonModes
);
181 CFRunLoopSourceSignal( source
);
182 CFRunLoopWakeUp( CFRunLoopGetMain() );
191 usleep(delayms
* 1000);
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
);
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
;
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;
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
;
255 info
->curdir_len
= append_string( &ptr
, params
, ¶ms
->CurrentDirectory
.DosPath
);
256 info
->dllpath_len
= append_string( &ptr
, params
, ¶ms
->DllPath
);
257 info
->imagepath_len
= append_string( &ptr
, params
, ¶ms
->ImagePathName
);
258 info
->cmdline_len
= append_string( &ptr
, params
, ¶ms
->CommandLine
);
259 info
->title_len
= append_string( &ptr
, params
, ¶ms
->WindowTitle
);
260 info
->desktop_len
= append_string( &ptr
, params
, ¶ms
->Desktop
);
261 info
->shellinfo_len
= append_string( &ptr
, params
, ¶ms
->ShellInfo
);
262 info
->runtime_len
= append_string( &ptr
, params
, ¶ms
->RuntimeInfo
);
267 /***************************************************************************
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
;
283 if ((is_win64
|| is_wow64
) && path
->Length
> sizeof(wow64W
) &&
284 !wcsnicmp( path
->Buffer
, wow64W
, ARRAY_SIZE(wow64W
) ))
293 /***********************************************************************
296 static BOOL
get_so_file_info( HANDLE handle
, pe_image_info_t
*info
)
302 unsigned char magic
[4];
305 unsigned char version
;
306 unsigned char ignored1
[9];
308 unsigned short machine
;
309 unsigned char ignored2
[8];
311 unsigned char ignored3
[12];
312 unsigned short phnum
;
316 unsigned char magic
[4];
319 unsigned char ignored1
[10];
321 unsigned short machine
;
322 unsigned char ignored2
[12];
323 unsigned __int64 phoff
;
324 unsigned char ignored3
[16];
325 unsigned short phnum
;
330 unsigned int cputype
;
331 unsigned int cpusubtype
;
332 unsigned int filetype
;
338 LARGE_INTEGER offset
;
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 ))
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
;
353 if (header
.elf
.data
!= 1 /* ELFDATA2LSB */) return FALSE
;
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
;
370 offset
.QuadPart
= header
.elf
.phoff
;
371 phnum
= header
.elf
.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;
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
;
397 /***********************************************************************
400 static NTSTATUS
get_pe_file_info( UNICODE_STRING
*path
, HANDLE
*handle
, pe_image_info_t
*info
)
404 OBJECT_ATTRIBUTES attr
;
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
)))
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
;
421 info
->cpu
= client_cpu
;
424 return STATUS_SUCCESS
;
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
);
443 else if (status
== STATUS_INVALID_IMAGE_NOT_MZ
)
445 if (get_so_file_info( *handle
, info
)) return STATUS_SUCCESS
;
451 /***********************************************************************
454 static ULONG
get_env_size( const RTL_USER_PROCESS_PARAMETERS
*params
, char **winedebug
)
456 WCHAR
*ptr
= params
->Environment
;
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;
470 return (ptr
- params
->Environment
) * sizeof(WCHAR
);
474 /***********************************************************************
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
= ¶ms
->CurrentDirectory
.DosPath
;
482 const WCHAR
*dir
= curdir
->Buffer
;
483 UNICODE_STRING nt_name
;
484 OBJECT_ATTRIBUTES attr
;
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;
499 wcscat( nt_name
.Buffer
, uncprefixW
);
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
);
518 /***********************************************************************
521 static void set_stdio_fd( int stdin_fd
, int stdout_fd
)
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
;
533 dup2( stdout_fd
, 1 );
534 if (fd
!= -1) close( fd
);
538 /***********************************************************************
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;
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
))
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
);
574 argv
= build_argv( ¶ms
->CommandLine
, 2 );
576 exec_wineloader( argv
, socketfd
, pe_info
);
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
);
599 /***********************************************************************
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];
609 if (startup_info_size
) return status
; /* started from another Win32 process */
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
;
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
;
631 unixdir
= get_unix_curdir( NtCurrentTeb()->Peb
->ProcessParameters
);
633 if (socketpair( PF_UNIX
, SOCK_STREAM
, 0, socketfd
) == -1) return STATUS_TOO_MANY_OPENED_FILES
;
638 setsockopt( socketfd
[0], SOL_SOCKET
, SO_PASSCRED
, &enable
, sizeof(enable
) );
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
);
654 if (!(argv
= build_argv( cmdline
, 2 ))) return STATUS_NO_MEMORY
;
658 status
= exec_wineloader( argv
, socketfd
[0], &pe_info
);
661 while (errno
== ENOTSUP
&& terminate_main_thread());
667 close( socketfd
[0] );
672 /***********************************************************************
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
)
681 int fd
[2], stdin_fd
= -1, stdout_fd
= -1;
686 status
= nt_to_unix_file_name( path
, &unix_name
, FILE_OPEN
);
687 if (status
) return status
;
690 if (pipe2( fd
, O_CLOEXEC
) == -1)
695 status
= STATUS_TOO_MANY_OPENED_FILES
;
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 */
711 if (params
->ConsoleFlags
||
712 params
->ConsoleHandle
== (HANDLE
)1 /* KERNEL32_CONSOLE_ALLOC */ ||
713 (params
->hStdInput
== INVALID_HANDLE_VALUE
&& params
->hStdOutput
== INVALID_HANDLE_VALUE
))
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( ¶ms
->CommandLine
, 0 );
727 envp
= build_envp( params
->Environment
);
733 execve( unix_name
, argv
, envp
);
736 if (pid
<= 0) /* grandchild if exec failed or child if fork failed */
741 case EACCES
: status
= STATUS_ACCESS_DENIED
; break;
742 case ENOENT
: status
= STATUS_OBJECT_NAME_NOT_FOUND
; break;
744 case ENFILE
: status
= STATUS_TOO_MANY_OPENED_FILES
; break;
746 case EINVAL
: status
= STATUS_INVALID_IMAGE_FORMAT
; break;
747 default: status
= STATUS_NO_MEMORY
; break;
749 write( fd
[1], &status
, sizeof(status
) );
752 _exit(0); /* child if fork succeeded */
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
;
768 if (stdin_fd
!= -1) close( stdin_fd
);
769 if (stdout_fd
!= -1) close( stdout_fd
);
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
)
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
;
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
;
808 case PS_ATTRIBUTE_DEBUG_PORT
:
809 debug
= attr
->Attributes
[i
].ValuePtr
;
811 case PS_ATTRIBUTE_IMAGE_NAME
:
812 path
.Length
= attr
->Attributes
[i
].Size
;
813 path
.Buffer
= attr
->Attributes
[i
].ValuePtr
;
815 case PS_ATTRIBUTE_TOKEN
:
816 token
= attr
->Attributes
[i
].ValuePtr
;
819 if (attr
->Attributes
[i
].Attribute
& PS_ATTRIBUTE_INPUT
)
820 FIXME( "unhandled input attribute %lx\n", attr
->Attributes
[i
].Attribute
);
825 TRACE( "%s image %s cmdline %s parent %p\n", debugstr_us( &path
),
826 debugstr_us( ¶ms
->ImagePathName
), debugstr_us( ¶ms
->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
;
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
;
858 setsockopt( socketfd
[0], SOL_SOCKET
, SO_PASSCRED
, &enable
, sizeof(enable
) );
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
);
894 case STATUS_INVALID_IMAGE_WIN_64
:
895 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_us(&path
) );
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
] );
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
);
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] );
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
;
945 if (!status
) status
= STATUS_INTERNAL_ERROR
;
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
;
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
;
975 case PS_ATTRIBUTE_TEB_ADDRESS
:
977 if (!(attr
->Attributes
[i
].Attribute
& PS_ATTRIBUTE_INPUT
))
978 FIXME( "unhandled output attribute %lx\n", attr
->Attributes
[i
].Attribute
);
982 *process_handle_ptr
= process_handle
;
983 *thread_handle_ptr
= thread_handle
;
984 process_handle
= thread_handle
= 0;
985 status
= STATUS_SUCCESS
;
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
);
1000 /******************************************************************************
1001 * NtTerminateProcess (NTDLL.@)
1003 NTSTATUS WINAPI
NtTerminateProcess( HANDLE handle
, LONG exit_code
)
1005 static BOOL clean_exit
;
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
);
1019 if (!handle
) clean_exit
= TRUE
;
1020 else if (clean_exit
) exit_process( exit_code
);
1021 else abort_process( exit_code
);
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
;
1047 #elif defined(linux)
1049 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1052 char line
[256], path
[26];
1053 unsigned long value
;
1056 strcpy( path
, "/proc/self/status" );
1058 sprintf( path
, "/proc/%u/status", unix_pid
);
1059 f
= fopen( path
, "r" );
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
;
1084 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1086 /* FIXME : real data */
1091 #define UNIMPLEMENTED_INFO_CLASS(c) \
1093 FIXME( "(process=%p) Unimplemented information class: " #c "\n", handle); \
1094 ret = STATUS_INVALID_INFO_CLASS; \
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
;
1106 TRACE( "(%p,0x%08x,%p,0x%08x,%p)\n", handle
, class, info
, size
, ret_len
);
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
;
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
;
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
;
1163 len
= sizeof(PROCESS_BASIC_INFORMATION
);
1164 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1169 case ProcessIoCounters
:
1173 if (size
>= sizeof(IO_COUNTERS
))
1175 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1176 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
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
;
1188 len
= sizeof(IO_COUNTERS
);
1189 ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
1204 memset(&pvmi
, 0, sizeof(pvmi
));
1205 if (handle
== GetCurrentProcess()) fill_vm_counters( &pvmi
, -1 );
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
;
1224 if (size
>= sizeof(VM_COUNTERS_EX
))
1225 pvmi
.PrivateUsage
= pvmi
.PagefileUsage
;
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
;
1236 ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
1251 long ticks
= sysconf(_SC_CLK_TCK
);
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
;
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
;
1279 len
= sizeof(KERNEL_USER_TIMES
);
1280 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1285 case ProcessDebugPort
:
1286 len
= sizeof(DWORD_PTR
);
1289 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
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;
1303 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1306 case ProcessDebugFlags
:
1307 len
= sizeof(DWORD
);
1310 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
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
;
1324 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
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
);
1339 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1340 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1343 memset(info
, 0, size
);
1344 ret
= STATUS_PORT_NOT_SET
;
1347 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1350 case ProcessHandleCount
:
1353 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1354 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1360 if (size
> 4) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1365 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1369 case ProcessAffinityMask
:
1370 len
= sizeof(ULONG_PTR
);
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
;
1383 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
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
);
1406 *(ULONG_PTR
*)info
= val
;
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);
1434 case ProcessExecuteFlags
:
1435 len
= sizeof(ULONG
);
1436 if (size
== len
) *(ULONG
*)info
= execute_flags
;
1437 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1440 case ProcessPriorityClass
:
1441 len
= sizeof(PROCESS_PRIORITY_CLASS
);
1444 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
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
;
1462 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
1476 case ProcessImageInformation
:
1477 len
= sizeof(SECTION_IMAGE_INFORMATION
);
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
);
1493 else ret
= STATUS_ACCESS_VIOLATION
;
1495 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
1505 if (ret_len
) *ret_len
= len
;
1510 /**********************************************************************
1511 * NtSetInformationProcess (NTDLL.@)
1513 NTSTATUS WINAPI
NtSetInformationProcess( HANDLE handle
, PROCESSINFOCLASS
class, void *info
, ULONG size
)
1515 NTSTATUS ret
= STATUS_SUCCESS
;
1519 case ProcessDefaultHardErrorMode
:
1520 if (size
!= sizeof(UINT
)) return STATUS_INVALID_PARAMETER
;
1521 process_error_mode
= *(UINT
*)info
;
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
);
1543 case ProcessPriorityClass
:
1544 if (size
!= sizeof(PROCESS_PRIORITY_CLASS
)) return STATUS_INVALID_PARAMETER
;
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
);
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
;
1567 switch (*(ULONG
*)info
& (MEM_EXECUTE_OPTION_ENABLE
|MEM_EXECUTE_OPTION_DISABLE
))
1569 case MEM_EXECUTE_OPTION_ENABLE
:
1572 case MEM_EXECUTE_OPTION_DISABLE
:
1576 return STATUS_INVALID_PARAMETER
;
1578 execute_flags
= *(ULONG
*)info
;
1579 virtual_set_force_exec( enable
);
1583 case ProcessThreadStackAllocation
:
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
);
1597 #ifdef VALGRIND_STACK_REGISTER
1598 VALGRIND_STACK_REGISTER( addr
, (char *)addr
+ reserve
);
1600 stack
->StackBase
= addr
;
1606 FIXME( "(%p,0x%08x,%p,0x%08x) stub\n", handle
, class, info
, size
);
1607 ret
= STATUS_NOT_IMPLEMENTED
;
1614 /**********************************************************************
1615 * NtOpenProcess (NTDLL.@)
1617 NTSTATUS WINAPI
NtOpenProcess( HANDLE
*handle
, ACCESS_MASK access
,
1618 const OBJECT_ATTRIBUTES
*attr
, const CLIENT_ID
*id
)
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
);
1635 /**********************************************************************
1636 * NtSuspendProcess (NTDLL.@)
1638 NTSTATUS WINAPI
NtSuspendProcess( HANDLE handle
)
1642 SERVER_START_REQ( suspend_process
)
1644 req
->handle
= wine_server_obj_handle( handle
);
1645 ret
= wine_server_call( req
);
1652 /**********************************************************************
1653 * NtResumeProcess (NTDLL.@)
1655 NTSTATUS WINAPI
NtResumeProcess( HANDLE handle
)
1659 SERVER_START_REQ( resume_process
)
1661 req
->handle
= wine_server_obj_handle( handle
);
1662 ret
= wine_server_call( req
);