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
) ))
281 if (NtCurrentTeb64() && NtCurrentTeb64()->TlsSlots
[WOW64_TLS_FILESYSREDIR
]) *is_64bit
= TRUE
;
285 if ((is_win64
|| is_wow64
) && path
->Length
> sizeof(wow64W
) &&
286 !wcsnicmp( path
->Buffer
, wow64W
, ARRAY_SIZE(wow64W
) ))
295 /***********************************************************************
298 static BOOL
get_so_file_info( HANDLE handle
, pe_image_info_t
*info
)
304 unsigned char magic
[4];
307 unsigned char version
;
308 unsigned char ignored1
[9];
310 unsigned short machine
;
311 unsigned char ignored2
[8];
313 unsigned char ignored3
[12];
314 unsigned short phnum
;
318 unsigned char magic
[4];
321 unsigned char ignored1
[10];
323 unsigned short machine
;
324 unsigned char ignored2
[12];
325 unsigned __int64 phoff
;
326 unsigned char ignored3
[16];
327 unsigned short phnum
;
332 unsigned int cputype
;
333 unsigned int cpusubtype
;
334 unsigned int filetype
;
340 LARGE_INTEGER offset
;
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 ))
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
;
355 if (header
.elf
.data
!= 1 /* ELFDATA2LSB */) return FALSE
;
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
;
372 offset
.QuadPart
= header
.elf
.phoff
;
373 phnum
= header
.elf
.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;
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
;
399 /***********************************************************************
402 static NTSTATUS
get_pe_file_info( UNICODE_STRING
*path
, HANDLE
*handle
, pe_image_info_t
*info
)
406 OBJECT_ATTRIBUTES attr
;
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
)))
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
;
424 info
->cpu
= client_cpu
;
426 return STATUS_SUCCESS
;
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
);
445 else if (status
== STATUS_INVALID_IMAGE_NOT_MZ
)
447 if (get_so_file_info( *handle
, info
)) return STATUS_SUCCESS
;
453 /***********************************************************************
456 static ULONG
get_env_size( const RTL_USER_PROCESS_PARAMETERS
*params
, char **winedebug
)
458 WCHAR
*ptr
= params
->Environment
;
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;
472 return (ptr
- params
->Environment
) * sizeof(WCHAR
);
476 /***********************************************************************
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
;
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;
496 wcscat( ret
, uncprefixW
);
505 /***********************************************************************
508 static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS
*params
)
510 UNICODE_STRING nt_name
;
511 OBJECT_ATTRIBUTES attr
;
517 if (!(nt_name
.Buffer
= get_nt_pathname( ¶ms
->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
);
532 /***********************************************************************
535 static void set_stdio_fd( int stdin_fd
, int stdout_fd
)
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
;
547 dup2( stdout_fd
, 1 );
548 if (fd
!= -1) close( fd
);
552 /***********************************************************************
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;
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
))
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
);
588 argv
= build_argv( ¶ms
->CommandLine
, 2 );
590 exec_wineloader( argv
, socketfd
, pe_info
);
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
);
613 /***********************************************************************
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];
624 if (startup_info_size
) goto done
; /* started from another Win32 process */
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( ¶ms
->ImagePathName
);
636 image
.Length
= wcslen( image
.Buffer
) * sizeof(WCHAR
);
637 if ((status
= get_pe_file_info( &image
, &handle
, &pe_info
))) goto done
;
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
;
651 unixdir
= get_unix_curdir( params
);
653 if (socketpair( PF_UNIX
, SOCK_STREAM
, 0, socketfd
) == -1)
655 status
= STATUS_TOO_MANY_OPENED_FILES
;
662 setsockopt( socketfd
[0], SOL_SOCKET
, SO_PASSCRED
, &enable
, sizeof(enable
) );
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
);
678 if (!(argv
= build_argv( ¶ms
->CommandLine
, 2 )))
680 status
= STATUS_NO_MEMORY
;
686 status
= exec_wineloader( argv
, socketfd
[0], &pe_info
);
689 while (errno
== ENOTSUP
&& terminate_main_thread());
695 close( socketfd
[0] );
700 case STATUS_INVALID_IMAGE_FORMAT
:
701 case STATUS_INVALID_IMAGE_NOT_MZ
:
702 ERR( "%s not supported on this system\n", debugstr_us(¶ms
->ImagePathName
) );
705 ERR( "failed to load %s error %x\n", debugstr_us(¶ms
->ImagePathName
), status
);
708 for (;;) NtTerminateProcess( GetCurrentProcess(), status
);
712 /***********************************************************************
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
)
721 int fd
[2], stdin_fd
= -1, stdout_fd
= -1;
726 status
= nt_to_unix_file_name( path
, &unix_name
, NULL
, FILE_OPEN
);
727 if (status
) return status
;
730 if (pipe2( fd
, O_CLOEXEC
) == -1)
735 status
= STATUS_TOO_MANY_OPENED_FILES
;
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 */
751 if (params
->ConsoleFlags
||
752 params
->ConsoleHandle
== (HANDLE
)1 /* KERNEL32_CONSOLE_ALLOC */ ||
753 (params
->hStdInput
== INVALID_HANDLE_VALUE
&& params
->hStdOutput
== INVALID_HANDLE_VALUE
))
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( ¶ms
->CommandLine
, 0 );
767 envp
= build_envp( params
->Environment
);
773 execve( unix_name
, argv
, envp
);
776 if (pid
<= 0) /* grandchild if exec failed or child if fork failed */
781 case EACCES
: status
= STATUS_ACCESS_DENIED
; break;
782 case ENOENT
: status
= STATUS_OBJECT_NAME_NOT_FOUND
; break;
784 case ENFILE
: status
= STATUS_TOO_MANY_OPENED_FILES
; break;
786 case EINVAL
: status
= STATUS_INVALID_IMAGE_FORMAT
; break;
787 default: status
= STATUS_NO_MEMORY
; break;
789 write( fd
[1], &status
, sizeof(status
) );
792 _exit(0); /* child if fork succeeded */
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
;
808 if (stdin_fd
!= -1) close( stdin_fd
);
809 if (stdout_fd
!= -1) close( stdout_fd
);
815 static NTSTATUS
alloc_handle_list( const PS_ATTRIBUTE
*handles_attr
, obj_handle_t
**handles
, data_size_t
*handles_len
)
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
)
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
;
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
;
873 case PS_ATTRIBUTE_DEBUG_PORT
:
874 debug
= attr
->Attributes
[i
].ValuePtr
;
876 case PS_ATTRIBUTE_IMAGE_NAME
:
877 path
.Length
= attr
->Attributes
[i
].Size
;
878 path
.Buffer
= attr
->Attributes
[i
].ValuePtr
;
880 case PS_ATTRIBUTE_TOKEN
:
881 token
= attr
->Attributes
[i
].ValuePtr
;
883 case PS_ATTRIBUTE_HANDLE_LIST
:
884 if (process_flags
& PROCESS_CREATE_FLAGS_INHERIT_HANDLES
)
885 handles_attr
= &attr
->Attributes
[i
];
888 if (attr
->Attributes
[i
].Attribute
& PS_ATTRIBUTE_INPUT
)
889 FIXME( "unhandled input attribute %lx\n", attr
->Attributes
[i
].Attribute
);
894 TRACE( "%s image %s cmdline %s parent %p\n", debugstr_us( &path
),
895 debugstr_us( ¶ms
->ImagePathName
), debugstr_us( ¶ms
->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
;
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
)))
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
;
932 setsockopt( socketfd
[0], SOL_SOCKET
, SO_PASSCRED
, &enable
, sizeof(enable
) );
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
);
972 case STATUS_INVALID_IMAGE_WIN_64
:
973 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_us(&path
) );
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
] );
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
);
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] );
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
;
1023 if (!status
) status
= STATUS_INTERNAL_ERROR
;
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
;
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
;
1053 case PS_ATTRIBUTE_TEB_ADDRESS
:
1055 if (!(attr
->Attributes
[i
].Attribute
& PS_ATTRIBUTE_INPUT
))
1056 FIXME( "unhandled output attribute %lx\n", attr
->Attributes
[i
].Attribute
);
1060 *process_handle_ptr
= process_handle
;
1061 *thread_handle_ptr
= thread_handle
;
1062 process_handle
= thread_handle
= 0;
1063 status
= STATUS_SUCCESS
;
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
);
1078 /******************************************************************************
1079 * NtTerminateProcess (NTDLL.@)
1081 NTSTATUS WINAPI
NtTerminateProcess( HANDLE handle
, LONG exit_code
)
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
);
1096 if (!handle
) process_exiting
= TRUE
;
1097 else if (process_exiting
) exit_process( exit_code
);
1098 else abort_process( exit_code
);
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
;
1124 #elif defined(linux)
1126 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1129 char line
[256], path
[26];
1130 unsigned long value
;
1133 strcpy( path
, "/proc/self/status" );
1135 sprintf( path
, "/proc/%u/status", unix_pid
);
1136 f
= fopen( path
, "r" );
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
;
1161 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1163 /* FIXME : real data */
1168 #define UNIMPLEMENTED_INFO_CLASS(c) \
1170 FIXME( "(process=%p) Unimplemented information class: " #c "\n", handle); \
1171 ret = STATUS_INVALID_INFO_CLASS; \
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
;
1183 TRACE( "(%p,0x%08x,%p,0x%08x,%p)\n", handle
, class, info
, size
, ret_len
);
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
;
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
;
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
;
1240 len
= sizeof(PROCESS_BASIC_INFORMATION
);
1241 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1246 case ProcessIoCounters
:
1250 if (size
>= sizeof(IO_COUNTERS
))
1252 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1253 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
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
;
1265 len
= sizeof(IO_COUNTERS
);
1266 ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
1281 memset(&pvmi
, 0, sizeof(pvmi
));
1282 if (handle
== GetCurrentProcess()) fill_vm_counters( &pvmi
, -1 );
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
;
1301 if (size
>= sizeof(VM_COUNTERS_EX
))
1302 pvmi
.PrivateUsage
= pvmi
.PagefileUsage
;
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
;
1313 ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
1328 long ticks
= sysconf(_SC_CLK_TCK
);
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
;
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
;
1356 len
= sizeof(KERNEL_USER_TIMES
);
1357 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1362 case ProcessDebugPort
:
1363 len
= sizeof(DWORD_PTR
);
1366 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
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
);
1378 if (ret
== STATUS_SUCCESS
)
1380 *(DWORD_PTR
*)info
= ~0ul;
1383 else if (ret
== STATUS_PORT_NOT_SET
)
1385 *(DWORD_PTR
*)info
= 0;
1386 ret
= STATUS_SUCCESS
;
1390 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1393 case ProcessDebugFlags
:
1394 len
= sizeof(DWORD
);
1397 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
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
;
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
;
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
;
1423 case ProcessDebugObjectHandle
:
1424 len
= sizeof(HANDLE
);
1427 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
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
);
1439 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1442 case ProcessHandleCount
:
1445 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1446 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1452 if (size
> 4) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1457 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1461 case ProcessAffinityMask
:
1462 len
= sizeof(ULONG_PTR
);
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
;
1475 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
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
);
1498 *(ULONG_PTR
*)info
= val
;
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);
1525 case ProcessExecuteFlags
:
1526 len
= sizeof(ULONG
);
1527 if (size
== len
) *(ULONG
*)info
= execute_flags
;
1528 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1531 case ProcessPriorityClass
:
1532 len
= sizeof(PROCESS_PRIORITY_CLASS
);
1535 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
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
;
1553 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
1567 case ProcessImageInformation
:
1568 len
= sizeof(SECTION_IMAGE_INFORMATION
);
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
);
1584 else ret
= STATUS_ACCESS_VIOLATION
;
1586 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
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
;
1596 if (ret_len
) *ret_len
= len
;
1601 /**********************************************************************
1602 * NtSetInformationProcess (NTDLL.@)
1604 NTSTATUS WINAPI
NtSetInformationProcess( HANDLE handle
, PROCESSINFOCLASS
class, void *info
, ULONG size
)
1606 NTSTATUS ret
= STATUS_SUCCESS
;
1610 case ProcessDefaultHardErrorMode
:
1611 if (size
!= sizeof(UINT
)) return STATUS_INVALID_PARAMETER
;
1612 process_error_mode
= *(UINT
*)info
;
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
);
1634 case ProcessPriorityClass
:
1635 if (size
!= sizeof(PROCESS_PRIORITY_CLASS
)) return STATUS_INVALID_PARAMETER
;
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
);
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
;
1658 switch (*(ULONG
*)info
& (MEM_EXECUTE_OPTION_ENABLE
|MEM_EXECUTE_OPTION_DISABLE
))
1660 case MEM_EXECUTE_OPTION_ENABLE
:
1663 case MEM_EXECUTE_OPTION_DISABLE
:
1667 return STATUS_INVALID_PARAMETER
;
1669 execute_flags
= *(ULONG
*)info
;
1670 virtual_set_force_exec( enable
);
1674 case ProcessThreadStackAllocation
:
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
);
1688 #ifdef VALGRIND_STACK_REGISTER
1689 VALGRIND_STACK_REGISTER( addr
, (char *)addr
+ reserve
);
1691 stack
->StackBase
= addr
;
1697 FIXME( "(%p,0x%08x,%p,0x%08x) stub\n", handle
, class, info
, size
);
1698 ret
= STATUS_NOT_IMPLEMENTED
;
1705 /**********************************************************************
1706 * NtOpenProcess (NTDLL.@)
1708 NTSTATUS WINAPI
NtOpenProcess( HANDLE
*handle
, ACCESS_MASK access
,
1709 const OBJECT_ATTRIBUTES
*attr
, const CLIENT_ID
*id
)
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
);
1726 /**********************************************************************
1727 * NtSuspendProcess (NTDLL.@)
1729 NTSTATUS WINAPI
NtSuspendProcess( HANDLE handle
)
1733 SERVER_START_REQ( suspend_process
)
1735 req
->handle
= wine_server_obj_handle( handle
);
1736 ret
= wine_server_call( req
);
1743 /**********************************************************************
1744 * NtResumeProcess (NTDLL.@)
1746 NTSTATUS WINAPI
NtResumeProcess( HANDLE handle
)
1750 SERVER_START_REQ( resume_process
)
1752 req
->handle
= wine_server_obj_handle( handle
);
1753 ret
= wine_server_call( req
);
1760 /**********************************************************************
1761 * NtDebugActiveProcess (NTDLL.@)
1763 NTSTATUS WINAPI
NtDebugActiveProcess( HANDLE process
, HANDLE debug
)
1767 SERVER_START_REQ( debug_process
)
1769 req
->handle
= wine_server_obj_handle( process
);
1770 req
->debug
= wine_server_obj_handle( debug
);
1772 ret
= wine_server_call( req
);
1779 /**********************************************************************
1780 * NtRemoveProcessDebug (NTDLL.@)
1782 NTSTATUS WINAPI
NtRemoveProcessDebug( HANDLE process
, HANDLE debug
)
1786 SERVER_START_REQ( debug_process
)
1788 req
->handle
= wine_server_obj_handle( process
);
1789 req
->debug
= wine_server_obj_handle( debug
);
1791 ret
= wine_server_call( req
);
1798 /**********************************************************************
1799 * NtDebugContinue (NTDLL.@)
1801 NTSTATUS WINAPI
NtDebugContinue( HANDLE handle
, CLIENT_ID
*client
, NTSTATUS status
)
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
);
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)
1828 SERVER_START_REQ( make_process_system
)
1830 if (!wine_server_call( req
)) ret
= wine_server_ptr_handle( reply
->event
);