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
36 #include <sys/socket.h>
38 #ifdef HAVE_SYS_TIMES_H
39 # include <sys/times.h>
41 #include <sys/types.h>
43 #ifdef HAVE_SYS_SYSCTL_H
44 # include <sys/sysctl.h>
46 #ifdef HAVE_SYS_PARAM_H
47 # include <sys/param.h>
49 #ifdef HAVE_SYS_QUEUE_H
50 # include <sys/queue.h>
52 #ifdef HAVE_SYS_USER_H
53 # include <sys/user.h>
55 #ifdef HAVE_LIBPROCSTAT_H
56 # include <libprocstat.h>
59 #ifdef HAVE_MACH_MACH_H
60 # include <mach/mach.h>
64 #define WIN32_NO_STATUS
68 #include "unix_private.h"
69 #include "wine/condrv.h"
70 #include "wine/server.h"
71 #include "wine/debug.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(process
);
76 static ULONG execute_flags
= MEM_EXECUTE_OPTION_DISABLE
;
78 static UINT process_error_mode
;
80 static char **build_argv( const UNICODE_STRING
*cmdline
, int reserved
)
82 char **argv
, *arg
, *src
, *dst
;
83 int argc
, in_quotes
= 0, bcount
= 0, len
= cmdline
->Length
/ sizeof(WCHAR
);
85 if (!(src
= malloc( len
* 3 + 1 ))) return NULL
;
86 len
= ntdll_wcstoumbs( cmdline
->Buffer
, len
, src
, len
* 3, FALSE
);
89 argc
= reserved
+ 2 + len
/ 2;
90 argv
= malloc( argc
* sizeof(*argv
) + len
);
91 arg
= dst
= (char *)(argv
+ argc
);
95 if ((*src
== ' ' || *src
== '\t') && !in_quotes
)
97 /* skip the remaining spaces */
98 while (*src
== ' ' || *src
== '\t') src
++;
100 /* close the argument and copy it */
103 /* start with a new argument */
107 else if (*src
== '\\')
112 else if (*src
== '"')
114 if ((bcount
& 1) == 0)
116 /* Preceded by an even number of '\', this is half that
117 * number of '\', plus a '"' which we discard.
121 if (in_quotes
&& *src
== '"') *dst
++ = *src
++;
122 else in_quotes
= !in_quotes
;
126 /* Preceded by an odd number of '\', this is half that
127 * number of '\' followed by a '"'
129 dst
-= bcount
/ 2 + 1;
134 else /* a regular character */
147 /***********************************************************************
150 static BOOL
get_so_file_info( int fd
, pe_image_info_t
*info
)
156 unsigned char magic
[4];
159 unsigned char version
;
160 unsigned char ignored1
[9];
162 unsigned short machine
;
163 unsigned char ignored2
[8];
165 unsigned char ignored3
[12];
166 unsigned short phnum
;
170 unsigned char magic
[4];
173 unsigned char ignored1
[10];
175 unsigned short machine
;
176 unsigned char ignored2
[12];
177 unsigned __int64 phoff
;
178 unsigned char ignored3
[16];
179 unsigned short phnum
;
184 unsigned int cputype
;
185 unsigned int cpusubtype
;
186 unsigned int filetype
;
193 if (pread( fd
, &header
, sizeof(header
), 0 ) != sizeof(header
)) return FALSE
;
195 if (!memcmp( header
.elf
.magic
, "\177ELF", 4 ))
198 unsigned short phnum
;
200 if (header
.elf
.version
!= 1 /* EV_CURRENT */) return FALSE
;
201 #ifdef WORDS_BIGENDIAN
202 if (header
.elf
.data
!= 2 /* ELFDATA2MSB */) return FALSE
;
204 if (header
.elf
.data
!= 1 /* ELFDATA2LSB */) return FALSE
;
206 switch (header
.elf
.machine
)
208 case 3: info
->machine
= IMAGE_FILE_MACHINE_I386
; break;
209 case 40: info
->machine
= IMAGE_FILE_MACHINE_ARMNT
; break;
210 case 62: info
->machine
= IMAGE_FILE_MACHINE_AMD64
; break;
211 case 183: info
->machine
= IMAGE_FILE_MACHINE_ARM64
; break;
213 if (header
.elf
.type
!= 3 /* ET_DYN */) return FALSE
;
214 if (header
.elf
.class == 2 /* ELFCLASS64 */)
216 pos
= header
.elf64
.phoff
;
217 phnum
= header
.elf64
.phnum
;
221 pos
= header
.elf
.phoff
;
222 phnum
= header
.elf
.phnum
;
226 if (pread( fd
, &type
, sizeof(type
), pos
) != sizeof(type
)) return FALSE
;
227 if (type
== 3 /* PT_INTERP */) return FALSE
;
228 pos
+= (header
.elf
.class == 2) ? 56 : 32;
232 else if (header
.macho
.magic
== 0xfeedface || header
.macho
.magic
== 0xfeedfacf)
234 switch (header
.macho
.cputype
)
236 case 0x00000007: info
->machine
= IMAGE_FILE_MACHINE_I386
; break;
237 case 0x01000007: info
->machine
= IMAGE_FILE_MACHINE_AMD64
; break;
238 case 0x0000000c: info
->machine
= IMAGE_FILE_MACHINE_ARMNT
; break;
239 case 0x0100000c: info
->machine
= IMAGE_FILE_MACHINE_ARM64
; break;
241 if (header
.macho
.filetype
== 8) return TRUE
;
247 /***********************************************************************
250 static unsigned int get_pe_file_info( OBJECT_ATTRIBUTES
*attr
, HANDLE
*handle
, pe_image_info_t
*info
)
257 memset( info
, 0, sizeof(*info
) );
258 if (!(status
= nt_to_unix_file_name( attr
, &unix_name
, FILE_OPEN
)))
260 status
= open_unix_file( handle
, unix_name
, GENERIC_READ
, attr
, 0,
261 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
262 FILE_OPEN
, FILE_SYNCHRONOUS_IO_NONALERT
, NULL
, 0 );
267 if (is_builtin_path( attr
->ObjectName
, &info
->machine
))
269 TRACE( "assuming %04x builtin for %s\n", info
->machine
, debugstr_us(attr
->ObjectName
));
270 return STATUS_SUCCESS
;
275 if (!(status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
|
276 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
,
277 NULL
, NULL
, PAGE_EXECUTE_READ
, SEC_IMAGE
, *handle
)))
279 SERVER_START_REQ( get_mapping_info
)
281 req
->handle
= wine_server_obj_handle( mapping
);
282 req
->access
= SECTION_QUERY
;
283 wine_server_set_reply( req
, info
, sizeof(*info
) );
284 status
= wine_server_call( req
);
288 if (info
->image_charact
& IMAGE_FILE_DLL
) return STATUS_INVALID_IMAGE_FORMAT
;
290 else if (status
== STATUS_INVALID_IMAGE_NOT_MZ
)
292 int unix_fd
, needs_close
;
294 if (!server_get_unix_fd( *handle
, FILE_READ_DATA
, &unix_fd
, &needs_close
, NULL
, NULL
))
296 if (get_so_file_info( unix_fd
, info
)) status
= STATUS_SUCCESS
;
297 if (needs_close
) close( unix_fd
);
304 /***********************************************************************
307 static ULONG
get_env_size( const RTL_USER_PROCESS_PARAMETERS
*params
, char **winedebug
)
309 WCHAR
*ptr
= params
->Environment
;
313 static const WCHAR WINEDEBUG
[] = {'W','I','N','E','D','E','B','U','G','=',0};
314 if (!*winedebug
&& !wcsncmp( ptr
, WINEDEBUG
, ARRAY_SIZE( WINEDEBUG
) - 1 ))
316 DWORD len
= wcslen(ptr
) * 3 + 1;
317 if ((*winedebug
= malloc( len
)))
318 ntdll_wcstoumbs( ptr
, wcslen(ptr
) + 1, *winedebug
, len
, FALSE
);
320 ptr
+= wcslen(ptr
) + 1;
323 return (ptr
- params
->Environment
) * sizeof(WCHAR
);
327 /***********************************************************************
330 * Simplified version of RtlDosPathNameToNtPathName_U.
332 static WCHAR
*get_nt_pathname( const UNICODE_STRING
*str
)
334 static const WCHAR ntprefixW
[] = {'\\','?','?','\\',0};
335 static const WCHAR uncprefixW
[] = {'U','N','C','\\',0};
336 const WCHAR
*name
= str
->Buffer
;
339 if (!(ret
= malloc( str
->Length
+ 8 * sizeof(WCHAR
) ))) return NULL
;
341 wcscpy( ret
, ntprefixW
);
342 if (name
[0] == '\\' && name
[1] == '\\')
344 if ((name
[2] == '.' || name
[2] == '?') && name
[3] == '\\') name
+= 4;
347 wcscat( ret
, uncprefixW
);
356 /***********************************************************************
359 static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS
*params
)
361 UNICODE_STRING nt_name
, redir
;
362 OBJECT_ATTRIBUTES attr
;
368 if (!(nt_name
.Buffer
= get_nt_pathname( ¶ms
->CurrentDirectory
.DosPath
))) return -1;
369 nt_name
.Length
= wcslen( nt_name
.Buffer
) * sizeof(WCHAR
);
371 InitializeObjectAttributes( &attr
, &nt_name
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
372 get_redirect( &attr
, &redir
);
373 status
= nt_to_unix_file_name( &attr
, &unix_name
, FILE_OPEN
);
374 if (status
) goto done
;
375 status
= open_unix_file( &handle
, unix_name
, FILE_TRAVERSE
| SYNCHRONIZE
, &attr
, 0,
376 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
377 FILE_OPEN
, FILE_SYNCHRONOUS_IO_NONALERT
, NULL
, 0 );
379 if (status
) goto done
;
380 wine_server_handle_to_fd( handle
, FILE_TRAVERSE
, &fd
, NULL
);
384 free( nt_name
.Buffer
);
385 free( redir
.Buffer
);
390 /***********************************************************************
393 static void set_stdio_fd( int stdin_fd
, int stdout_fd
)
397 if (stdin_fd
== -1 || stdout_fd
== -1)
399 fd
= open( "/dev/null", O_RDWR
);
400 if (stdin_fd
== -1) stdin_fd
= fd
;
401 if (stdout_fd
== -1) stdout_fd
= fd
;
404 if (stdin_fd
!= 0) dup2( stdin_fd
, 0 );
405 if (stdout_fd
!= 1) dup2( stdout_fd
, 1 );
406 if (fd
!= -1) close( fd
);
410 /***********************************************************************
411 * is_unix_console_handle
413 static BOOL
is_unix_console_handle( HANDLE handle
)
415 IO_STATUS_BLOCK io
= {{0}};
416 return !NtDeviceIoControlFile( handle
, NULL
, NULL
, NULL
, &io
, IOCTL_CONDRV_IS_UNIX
,
421 /***********************************************************************
424 static NTSTATUS
spawn_process( const RTL_USER_PROCESS_PARAMETERS
*params
, int socketfd
,
425 int unixdir
, char *winedebug
, const pe_image_info_t
*pe_info
)
427 NTSTATUS status
= STATUS_SUCCESS
;
428 int stdin_fd
= -1, stdout_fd
= -1;
432 if (wine_server_handle_to_fd( params
->hStdInput
, FILE_READ_DATA
, &stdin_fd
, NULL
) &&
433 isatty(0) && is_unix_console_handle( params
->hStdInput
))
436 if (wine_server_handle_to_fd( params
->hStdOutput
, FILE_WRITE_DATA
, &stdout_fd
, NULL
) &&
437 isatty(1) && is_unix_console_handle( params
->hStdOutput
))
440 if (!(pid
= fork())) /* child */
442 if (!(pid
= fork())) /* grandchild */
444 if (params
->ConsoleFlags
||
445 params
->ConsoleHandle
== CONSOLE_HANDLE_ALLOC
||
446 params
->ConsoleHandle
== CONSOLE_HANDLE_ALLOC_NO_WINDOW
||
447 (params
->hStdInput
== INVALID_HANDLE_VALUE
&& params
->hStdOutput
== INVALID_HANDLE_VALUE
))
450 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
452 else set_stdio_fd( stdin_fd
, stdout_fd
);
454 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
455 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
457 if (winedebug
) putenv( winedebug
);
463 argv
= build_argv( ¶ms
->CommandLine
, 2 );
465 exec_wineloader( argv
, socketfd
, pe_info
);
477 wret
= waitpid(pid
, NULL
, 0);
478 } while (wret
< 0 && errno
== EINTR
);
480 else status
= STATUS_NO_MEMORY
;
482 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
483 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
488 /***********************************************************************
489 * __wine_unix_spawnvp
491 NTSTATUS WINAPI
__wine_unix_spawnvp( char * const argv
[], int wait
)
494 int fd
[2], status
, err
;
497 if (pipe2( fd
, O_CLOEXEC
) == -1)
500 if (pipe(fd
) == -1) return STATUS_TOO_MANY_OPENED_FILES
;
501 fcntl( fd
[0], F_SETFD
, FD_CLOEXEC
);
502 fcntl( fd
[1], F_SETFD
, FD_CLOEXEC
);
509 signal( SIGPIPE
, SIG_DFL
);
512 if (!(pid
= fork())) execvp( argv
[0], argv
); /* in grandchild */
513 if (pid
> 0) _exit(0); /* exit child if fork succeeded */
515 else execvp( argv
[0], argv
);
517 err
= errno_to_status( errno
);
518 write( fd
[1], &err
, sizeof(err
) );
525 while (pid
!= (wret
= waitpid( pid
, &status
, 0 )))
526 if (wret
== -1 && errno
!= EINTR
) break;
528 if (read( fd
[0], &err
, sizeof(err
) ) <= 0) /* if we read something, exec or second fork failed */
530 if (pid
== wret
&& WIFEXITED(status
)) err
= WEXITSTATUS(status
);
531 else err
= 255; /* abnormal exit with an abort or an interrupt */
534 else err
= errno_to_status( errno
);
541 /***********************************************************************
542 * unixcall_wine_spawnvp
544 NTSTATUS
unixcall_wine_spawnvp( void *args
)
546 struct wine_spawnvp_params
*params
= args
;
548 return __wine_unix_spawnvp( params
->argv
, params
->wait
);
553 /***********************************************************************
556 NTSTATUS
wow64_wine_spawnvp( void *args
)
562 } const *params32
= args
;
564 ULONG
*argv32
= ULongToPtr( params32
->argv
);
565 unsigned int i
, count
= 0;
569 while (argv32
[count
]) count
++;
570 argv
= malloc( (count
+ 1) * sizeof(*argv
) );
571 for (i
= 0; i
< count
; i
++) argv
[i
] = ULongToPtr( argv32
[i
] );
573 ret
= __wine_unix_spawnvp( argv
, params32
->wait
);
579 /***********************************************************************
582 * Fork and exec a new Unix binary, checking for errors.
584 static NTSTATUS
fork_and_exec( OBJECT_ATTRIBUTES
*attr
, int unixdir
,
585 const RTL_USER_PROCESS_PARAMETERS
*params
)
588 int fd
[2], stdin_fd
= -1, stdout_fd
= -1;
593 status
= nt_to_unix_file_name( attr
, &unix_name
, FILE_OPEN
);
594 if (status
) return status
;
597 if (pipe2( fd
, O_CLOEXEC
) == -1)
602 status
= STATUS_TOO_MANY_OPENED_FILES
;
605 fcntl( fd
[0], F_SETFD
, FD_CLOEXEC
);
606 fcntl( fd
[1], F_SETFD
, FD_CLOEXEC
);
609 if (wine_server_handle_to_fd( params
->hStdInput
, FILE_READ_DATA
, &stdin_fd
, NULL
) &&
610 isatty(0) && is_unix_console_handle( params
->hStdInput
))
613 if (wine_server_handle_to_fd( params
->hStdOutput
, FILE_WRITE_DATA
, &stdout_fd
, NULL
) &&
614 isatty(1) && is_unix_console_handle( params
->hStdOutput
))
617 if (!(pid
= fork())) /* child */
619 if (!(pid
= fork())) /* grandchild */
623 if (params
->ConsoleFlags
||
624 params
->ConsoleHandle
== CONSOLE_HANDLE_ALLOC
||
625 params
->ConsoleHandle
== CONSOLE_HANDLE_ALLOC_NO_WINDOW
||
626 (params
->hStdInput
== INVALID_HANDLE_VALUE
&& params
->hStdOutput
== INVALID_HANDLE_VALUE
))
629 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
631 else set_stdio_fd( stdin_fd
, stdout_fd
);
633 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
634 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
636 /* Reset signals that we previously set to SIG_IGN */
637 signal( SIGPIPE
, SIG_DFL
);
639 argv
= build_argv( ¶ms
->CommandLine
, 0 );
640 envp
= build_envp( params
->Environment
);
646 execve( unix_name
, argv
, envp
);
649 if (pid
<= 0) /* grandchild if exec failed or child if fork failed */
654 case EACCES
: status
= STATUS_ACCESS_DENIED
; break;
655 case ENOENT
: status
= STATUS_OBJECT_NAME_NOT_FOUND
; break;
657 case ENFILE
: status
= STATUS_TOO_MANY_OPENED_FILES
; break;
659 case EINVAL
: status
= STATUS_INVALID_IMAGE_FORMAT
; break;
660 default: status
= STATUS_NO_MEMORY
; break;
662 write( fd
[1], &status
, sizeof(status
) );
665 _exit(0); /* child if fork succeeded */
674 wret
= waitpid(pid
, NULL
, 0);
675 } while (wret
< 0 && errno
== EINTR
);
676 read( fd
[0], &status
, sizeof(status
) ); /* if we read something, exec or second fork failed */
678 else status
= STATUS_NO_MEMORY
;
681 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
682 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
688 static NTSTATUS
alloc_handle_list( const PS_ATTRIBUTE
*handles_attr
, obj_handle_t
**handles
, data_size_t
*handles_len
)
696 if (!handles_attr
) return STATUS_SUCCESS
;
698 count
= handles_attr
->Size
/ sizeof(HANDLE
);
700 if (!(*handles
= calloc( sizeof(**handles
), count
))) return STATUS_NO_MEMORY
;
702 src
= handles_attr
->ValuePtr
;
703 for (i
= 0; i
< count
; ++i
)
704 (*handles
)[i
] = wine_server_obj_handle( src
[i
] );
706 *handles_len
= count
* sizeof(**handles
);
708 return STATUS_SUCCESS
;
711 /**********************************************************************
712 * NtCreateUserProcess (NTDLL.@)
714 NTSTATUS WINAPI
NtCreateUserProcess( HANDLE
*process_handle_ptr
, HANDLE
*thread_handle_ptr
,
715 ACCESS_MASK process_access
, ACCESS_MASK thread_access
,
716 OBJECT_ATTRIBUTES
*process_attr
, OBJECT_ATTRIBUTES
*thread_attr
,
717 ULONG process_flags
, ULONG thread_flags
,
718 RTL_USER_PROCESS_PARAMETERS
*params
, PS_CREATE_INFO
*info
,
719 PS_ATTRIBUTE_LIST
*ps_attr
)
722 BOOL success
= FALSE
;
723 HANDLE file_handle
, process_info
= 0, process_handle
= 0, thread_handle
= 0;
724 struct object_attributes
*objattr
;
725 data_size_t attr_len
;
726 char *winedebug
= NULL
;
727 startup_info_t
*startup_info
= NULL
;
728 ULONG startup_info_size
, env_size
;
729 int unixdir
, socketfd
[2] = { -1, -1 };
730 pe_image_info_t pe_info
;
733 HANDLE parent
= 0, debug
= 0, token
= 0;
734 UNICODE_STRING redir
, path
= {0};
735 OBJECT_ATTRIBUTES attr
, empty_attr
= { sizeof(empty_attr
) };
736 SIZE_T i
, attr_count
= (ps_attr
->TotalLength
- sizeof(ps_attr
->TotalLength
)) / sizeof(PS_ATTRIBUTE
);
737 const PS_ATTRIBUTE
*handles_attr
= NULL
, *jobs_attr
= NULL
;
738 data_size_t handles_size
, jobs_size
;
739 obj_handle_t
*handles
, *jobs
;
741 if (thread_flags
& THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER
)
743 WARN( "Invalid thread flags %#x.\n", (int)thread_flags
);
745 return STATUS_INVALID_PARAMETER
;
748 if (thread_flags
& ~THREAD_CREATE_FLAGS_CREATE_SUSPENDED
)
749 FIXME( "Unsupported thread flags %#x.\n", (int)thread_flags
);
751 for (i
= 0; i
< attr_count
; i
++)
753 switch (ps_attr
->Attributes
[i
].Attribute
)
755 case PS_ATTRIBUTE_PARENT_PROCESS
:
756 parent
= ps_attr
->Attributes
[i
].ValuePtr
;
758 case PS_ATTRIBUTE_DEBUG_PORT
:
759 debug
= ps_attr
->Attributes
[i
].ValuePtr
;
761 case PS_ATTRIBUTE_IMAGE_NAME
:
762 path
.Length
= ps_attr
->Attributes
[i
].Size
;
763 path
.Buffer
= ps_attr
->Attributes
[i
].ValuePtr
;
765 case PS_ATTRIBUTE_TOKEN
:
766 token
= ps_attr
->Attributes
[i
].ValuePtr
;
768 case PS_ATTRIBUTE_HANDLE_LIST
:
769 if (process_flags
& PROCESS_CREATE_FLAGS_INHERIT_HANDLES
)
770 handles_attr
= &ps_attr
->Attributes
[i
];
772 case PS_ATTRIBUTE_JOB_LIST
:
773 jobs_attr
= &ps_attr
->Attributes
[i
];
775 case PS_ATTRIBUTE_MACHINE_TYPE
:
776 machine
= ps_attr
->Attributes
[i
].Value
;
779 if (ps_attr
->Attributes
[i
].Attribute
& PS_ATTRIBUTE_INPUT
)
780 FIXME( "unhandled input attribute %lx\n", ps_attr
->Attributes
[i
].Attribute
);
784 if (!process_attr
) process_attr
= &empty_attr
;
786 TRACE( "%s image %s cmdline %s parent %p machine %x\n", debugstr_us( &path
),
787 debugstr_us( ¶ms
->ImagePathName
), debugstr_us( ¶ms
->CommandLine
), parent
, machine
);
789 unixdir
= get_unix_curdir( params
);
791 InitializeObjectAttributes( &attr
, &path
, OBJ_CASE_INSENSITIVE
, 0, 0 );
792 get_redirect( &attr
, &redir
);
794 if ((status
= get_pe_file_info( &attr
, &file_handle
, &pe_info
)))
796 if (status
== STATUS_INVALID_IMAGE_NOT_MZ
&& !fork_and_exec( &attr
, unixdir
, params
))
798 memset( info
, 0, sizeof(*info
) );
799 free( redir
.Buffer
);
800 return STATUS_SUCCESS
;
804 if (!machine
) machine
= pe_info
.machine
;
805 if (!(startup_info
= create_startup_info( attr
.ObjectName
, params
, &startup_info_size
))) goto done
;
806 env_size
= get_env_size( params
, &winedebug
);
808 if ((status
= alloc_object_attributes( process_attr
, &objattr
, &attr_len
))) goto done
;
810 if ((status
= alloc_handle_list( handles_attr
, &handles
, &handles_size
)))
816 if ((status
= alloc_handle_list( jobs_attr
, &jobs
, &jobs_size
)))
823 /* create the socket for the new process */
825 if (socketpair( PF_UNIX
, SOCK_STREAM
, 0, socketfd
) == -1)
827 status
= STATUS_TOO_MANY_OPENED_FILES
;
837 setsockopt( socketfd
[0], SOL_SOCKET
, SO_PASSCRED
, &enable
, sizeof(enable
) );
841 wine_server_send_fd( socketfd
[1] );
842 close( socketfd
[1] );
844 /* create the process on the server side */
846 SERVER_START_REQ( new_process
)
848 req
->token
= wine_server_obj_handle( token
);
849 req
->debug
= wine_server_obj_handle( debug
);
850 req
->parent_process
= wine_server_obj_handle( parent
);
851 req
->flags
= process_flags
;
852 req
->socket_fd
= socketfd
[1];
853 req
->access
= process_access
;
854 req
->machine
= machine
;
855 req
->info_size
= startup_info_size
;
856 req
->handles_size
= handles_size
;
857 req
->jobs_size
= jobs_size
;
858 wine_server_add_data( req
, objattr
, attr_len
);
859 wine_server_add_data( req
, handles
, handles_size
);
860 wine_server_add_data( req
, jobs
, jobs_size
);
861 wine_server_add_data( req
, startup_info
, startup_info_size
);
862 wine_server_add_data( req
, params
->Environment
, env_size
);
863 if (!(status
= wine_server_call( req
)))
865 process_handle
= wine_server_ptr_handle( reply
->handle
);
866 id
.UniqueProcess
= ULongToHandle( reply
->pid
);
868 process_info
= wine_server_ptr_handle( reply
->info
);
879 case STATUS_INVALID_IMAGE_WIN_64
:
880 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_us(&path
) );
882 case STATUS_INVALID_IMAGE_FORMAT
:
883 ERR( "%s not supported on this installation (machine %04x)\n",
884 debugstr_us(&path
), pe_info
.machine
);
890 if ((status
= alloc_object_attributes( thread_attr
, &objattr
, &attr_len
))) goto done
;
892 SERVER_START_REQ( new_thread
)
894 req
->process
= wine_server_obj_handle( process_handle
);
895 req
->access
= thread_access
;
896 req
->flags
= thread_flags
;
897 req
->request_fd
= -1;
898 wine_server_add_data( req
, objattr
, attr_len
);
899 if (!(status
= wine_server_call( req
)))
901 thread_handle
= wine_server_ptr_handle( reply
->handle
);
902 id
.UniqueThread
= ULongToHandle( reply
->tid
);
907 if (status
) goto done
;
909 /* create the child process */
911 if ((status
= spawn_process( params
, socketfd
[0], unixdir
, winedebug
, &pe_info
))) goto done
;
913 close( socketfd
[0] );
916 /* wait for the new process info to be ready */
918 NtWaitForSingleObject( process_info
, FALSE
, NULL
);
919 SERVER_START_REQ( get_new_process_info
)
921 req
->info
= wine_server_obj_handle( process_info
);
922 wine_server_call( req
);
923 success
= reply
->success
;
924 status
= reply
->exit_code
;
930 if (!status
) status
= STATUS_INTERNAL_ERROR
;
934 TRACE( "%s pid %04x tid %04x handles %p/%p\n", debugstr_us(&path
),
935 (int)HandleToULong(id
.UniqueProcess
), (int)HandleToULong(id
.UniqueThread
),
936 process_handle
, thread_handle
);
938 /* update output attributes */
940 for (i
= 0; i
< attr_count
; i
++)
942 switch (ps_attr
->Attributes
[i
].Attribute
)
944 case PS_ATTRIBUTE_CLIENT_ID
:
946 SIZE_T size
= min( ps_attr
->Attributes
[i
].Size
, sizeof(id
) );
947 memcpy( ps_attr
->Attributes
[i
].ValuePtr
, &id
, size
);
948 if (ps_attr
->Attributes
[i
].ReturnLength
) *ps_attr
->Attributes
[i
].ReturnLength
= size
;
951 case PS_ATTRIBUTE_IMAGE_INFO
:
953 SECTION_IMAGE_INFORMATION info
;
954 SIZE_T size
= min( ps_attr
->Attributes
[i
].Size
, sizeof(info
) );
955 virtual_fill_image_information( &pe_info
, &info
);
956 memcpy( ps_attr
->Attributes
[i
].ValuePtr
, &info
, size
);
957 if (ps_attr
->Attributes
[i
].ReturnLength
) *ps_attr
->Attributes
[i
].ReturnLength
= size
;
960 case PS_ATTRIBUTE_TEB_ADDRESS
:
962 if (!(ps_attr
->Attributes
[i
].Attribute
& PS_ATTRIBUTE_INPUT
))
963 FIXME( "unhandled output attribute %lx\n", ps_attr
->Attributes
[i
].Attribute
);
967 *process_handle_ptr
= process_handle
;
968 *thread_handle_ptr
= thread_handle
;
969 process_handle
= thread_handle
= 0;
970 status
= STATUS_SUCCESS
;
973 if (file_handle
) NtClose( file_handle
);
974 if (process_info
) NtClose( process_info
);
975 if (process_handle
) NtClose( process_handle
);
976 if (thread_handle
) NtClose( thread_handle
);
977 if (socketfd
[0] != -1) close( socketfd
[0] );
978 if (unixdir
!= -1) close( unixdir
);
979 free( startup_info
);
981 free( redir
.Buffer
);
986 /******************************************************************************
987 * NtTerminateProcess (NTDLL.@)
989 NTSTATUS WINAPI
NtTerminateProcess( HANDLE handle
, LONG exit_code
)
994 SERVER_START_REQ( terminate_process
)
996 req
->handle
= wine_server_obj_handle( handle
);
997 req
->exit_code
= exit_code
;
998 ret
= wine_server_call( req
);
1004 if (!handle
) process_exiting
= TRUE
;
1005 else if (process_exiting
) exit_process( exit_code
);
1006 else abort_process( exit_code
);
1012 #if defined(HAVE_MACH_MACH_H)
1014 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1016 #if defined(MACH_TASK_BASIC_INFO)
1017 struct mach_task_basic_info info
;
1018 mach_msg_type_number_t infoCount
;
1020 if (unix_pid
!= -1) return; /* FIXME: Retrieve information for other processes. */
1022 infoCount
= MACH_TASK_BASIC_INFO_COUNT
;
1023 if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO
, (task_info_t
)&info
, &infoCount
) == KERN_SUCCESS
)
1025 pvmi
->VirtualSize
= info
.resident_size
+ info
.virtual_size
;
1026 pvmi
->PagefileUsage
= info
.virtual_size
;
1027 pvmi
->WorkingSetSize
= info
.resident_size
;
1028 pvmi
->PeakWorkingSetSize
= info
.resident_size_max
;
1033 #elif defined(linux)
1035 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1038 char line
[256], path
[26];
1039 unsigned long value
;
1042 strcpy( path
, "/proc/self/status" );
1044 sprintf( path
, "/proc/%u/status", unix_pid
);
1045 f
= fopen( path
, "r" );
1048 while (fgets(line
, sizeof(line
), f
))
1050 if (sscanf(line
, "VmPeak: %lu", &value
))
1051 pvmi
->PeakVirtualSize
= (ULONG64
)value
* 1024;
1052 else if (sscanf(line
, "VmSize: %lu", &value
))
1053 pvmi
->VirtualSize
= (ULONG64
)value
* 1024;
1054 else if (sscanf(line
, "VmHWM: %lu", &value
))
1055 pvmi
->PeakWorkingSetSize
= (ULONG64
)value
* 1024;
1056 else if (sscanf(line
, "VmRSS: %lu", &value
))
1057 pvmi
->WorkingSetSize
= (ULONG64
)value
* 1024;
1058 else if (sscanf(line
, "RssAnon: %lu", &value
))
1059 pvmi
->PagefileUsage
+= (ULONG64
)value
* 1024;
1060 else if (sscanf(line
, "VmSwap: %lu", &value
))
1061 pvmi
->PagefileUsage
+= (ULONG64
)value
* 1024;
1063 pvmi
->PeakPagefileUsage
= pvmi
->PagefileUsage
;
1068 #elif defined(HAVE_LIBPROCSTAT)
1070 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1072 struct procstat
*pstat
;
1073 struct kinfo_proc
*kip
;
1074 unsigned int proc_count
;
1076 pstat
= procstat_open_sysctl();
1079 kip
= procstat_getprocs( pstat
, KERN_PROC_PID
, unix_pid
== -1 ? getpid() : unix_pid
, &proc_count
);
1082 pvmi
->VirtualSize
= kip
->ki_size
;
1083 pvmi
->PeakVirtualSize
= kip
->ki_size
;
1084 pvmi
->WorkingSetSize
= kip
->ki_rssize
<< PAGE_SHIFT
;
1085 pvmi
->PeakWorkingSetSize
= kip
->ki_rusage
.ru_maxrss
* 1024;
1086 procstat_freeprocs( pstat
, kip
);
1088 procstat_close( pstat
);
1094 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1096 /* FIXME : real data */
1101 #define UNIMPLEMENTED_INFO_CLASS(c) \
1103 FIXME( "(process=%p) Unimplemented information class: " #c "\n", handle); \
1104 ret = STATUS_INVALID_INFO_CLASS; \
1107 /**********************************************************************
1108 * NtQueryInformationProcess (NTDLL.@)
1110 NTSTATUS WINAPI
NtQueryInformationProcess( HANDLE handle
, PROCESSINFOCLASS
class, void *info
,
1111 ULONG size
, ULONG
*ret_len
)
1113 unsigned int ret
= STATUS_SUCCESS
;
1116 TRACE( "(%p,0x%08x,%p,0x%08x,%p)\n", handle
, class, info
, (int)size
, ret_len
);
1120 UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits
);
1121 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority
);
1122 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority
);
1123 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort
);
1124 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken
);
1125 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation
);
1126 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize
);
1127 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers
);
1128 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits
);
1129 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch
);
1130 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL
);
1131 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup
);
1132 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information
);
1133 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost
);
1134 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap
);
1135 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation
);
1136 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled
);
1137 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination
);
1138 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing
);
1140 case ProcessBasicInformation
:
1142 PROCESS_BASIC_INFORMATION pbi
;
1143 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1145 if (size
>= sizeof(PROCESS_BASIC_INFORMATION
))
1147 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1150 SERVER_START_REQ(get_process_info
)
1152 req
->handle
= wine_server_obj_handle( handle
);
1153 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1155 pbi
.ExitStatus
= reply
->exit_code
;
1156 pbi
.PebBaseAddress
= wine_server_get_ptr( reply
->peb
);
1157 pbi
.AffinityMask
= reply
->affinity
& affinity_mask
;
1158 pbi
.BasePriority
= reply
->priority
;
1159 pbi
.UniqueProcessId
= reply
->pid
;
1160 pbi
.InheritedFromUniqueProcessId
= reply
->ppid
;
1163 if (reply
->machine
!= native_machine
)
1164 pbi
.PebBaseAddress
= (PEB
*)((char *)pbi
.PebBaseAddress
+ 0x1000);
1166 pbi
.PebBaseAddress
= NULL
;
1172 memcpy( info
, &pbi
, sizeof(PROCESS_BASIC_INFORMATION
) );
1173 len
= sizeof(PROCESS_BASIC_INFORMATION
);
1175 if (size
> sizeof(PROCESS_BASIC_INFORMATION
)) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1179 len
= sizeof(PROCESS_BASIC_INFORMATION
);
1180 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1185 case ProcessIoCounters
:
1189 if (size
>= sizeof(IO_COUNTERS
))
1191 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1192 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1195 /* FIXME : real data */
1196 memset(&pii
, 0 , sizeof(IO_COUNTERS
));
1197 memcpy(info
, &pii
, sizeof(IO_COUNTERS
));
1198 len
= sizeof(IO_COUNTERS
);
1200 if (size
> sizeof(IO_COUNTERS
)) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1204 len
= sizeof(IO_COUNTERS
);
1205 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1210 case ProcessVmCounters
:
1212 VM_COUNTERS_EX pvmi
;
1214 /* older Windows versions don't have the PrivateUsage field */
1215 if (size
>= sizeof(VM_COUNTERS
))
1217 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1220 memset(&pvmi
, 0, sizeof(pvmi
));
1221 if (handle
== GetCurrentProcess()) fill_vm_counters( &pvmi
, -1 );
1224 SERVER_START_REQ(get_process_vm_counters
)
1226 req
->handle
= wine_server_obj_handle( handle
);
1227 if (!(ret
= wine_server_call( req
)))
1229 pvmi
.PeakVirtualSize
= reply
->peak_virtual_size
;
1230 pvmi
.VirtualSize
= reply
->virtual_size
;
1231 pvmi
.PeakWorkingSetSize
= reply
->peak_working_set_size
;
1232 pvmi
.WorkingSetSize
= reply
->working_set_size
;
1233 pvmi
.PagefileUsage
= reply
->pagefile_usage
;
1234 pvmi
.PeakPagefileUsage
= reply
->peak_pagefile_usage
;
1240 if (size
>= sizeof(VM_COUNTERS_EX
))
1241 pvmi
.PrivateUsage
= pvmi
.PagefileUsage
;
1243 if (len
!= sizeof(VM_COUNTERS
)) len
= sizeof(VM_COUNTERS_EX
);
1244 memcpy(info
, &pvmi
, min(size
, sizeof(pvmi
)));
1246 if (size
!= sizeof(VM_COUNTERS
) && size
!= sizeof(VM_COUNTERS_EX
))
1247 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1252 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1259 KERNEL_USER_TIMES pti
= {{{0}}};
1261 if (size
>= sizeof(KERNEL_USER_TIMES
))
1263 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1264 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1267 long ticks
= sysconf(_SC_CLK_TCK
);
1270 /* FIXME: user/kernel times only work for current process */
1271 if (ticks
&& times( &tms
) != -1)
1273 pti
.UserTime
.QuadPart
= (ULONGLONG
)tms
.tms_utime
* 10000000 / ticks
;
1274 pti
.KernelTime
.QuadPart
= (ULONGLONG
)tms
.tms_stime
* 10000000 / ticks
;
1277 SERVER_START_REQ(get_process_info
)
1279 req
->handle
= wine_server_obj_handle( handle
);
1280 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1282 pti
.CreateTime
.QuadPart
= reply
->start_time
;
1283 pti
.ExitTime
.QuadPart
= reply
->end_time
;
1288 memcpy(info
, &pti
, sizeof(KERNEL_USER_TIMES
));
1289 len
= sizeof(KERNEL_USER_TIMES
);
1291 if (size
> sizeof(KERNEL_USER_TIMES
)) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1295 len
= sizeof(KERNEL_USER_TIMES
);
1296 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1301 case ProcessDebugPort
:
1302 len
= sizeof(DWORD_PTR
);
1305 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1310 SERVER_START_REQ(get_process_debug_info
)
1312 req
->handle
= wine_server_obj_handle( handle
);
1313 ret
= wine_server_call( req
);
1314 debug
= wine_server_ptr_handle( reply
->debug
);
1317 if (ret
== STATUS_SUCCESS
)
1319 *(DWORD_PTR
*)info
= ~0ul;
1322 else if (ret
== STATUS_PORT_NOT_SET
)
1324 *(DWORD_PTR
*)info
= 0;
1325 ret
= STATUS_SUCCESS
;
1329 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1332 case ProcessDebugFlags
:
1333 len
= sizeof(DWORD
);
1336 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1341 SERVER_START_REQ(get_process_debug_info
)
1343 req
->handle
= wine_server_obj_handle( handle
);
1344 ret
= wine_server_call( req
);
1345 debug
= wine_server_ptr_handle( reply
->debug
);
1346 *(DWORD
*)info
= reply
->debug_children
;
1349 if (ret
== STATUS_SUCCESS
) NtClose( debug
);
1350 else if (ret
== STATUS_PORT_NOT_SET
) ret
= STATUS_SUCCESS
;
1353 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1356 case ProcessDefaultHardErrorMode
:
1357 len
= sizeof(process_error_mode
);
1358 if (size
== len
) memcpy(info
, &process_error_mode
, len
);
1359 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1362 case ProcessDebugObjectHandle
:
1363 len
= sizeof(HANDLE
);
1366 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1369 SERVER_START_REQ(get_process_debug_info
)
1371 req
->handle
= wine_server_obj_handle( handle
);
1372 ret
= wine_server_call( req
);
1373 *(HANDLE
*)info
= wine_server_ptr_handle( reply
->debug
);
1378 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1381 case ProcessHandleCount
:
1384 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1385 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1388 FIXME( "ProcessHandleCount (%p,%p,0x%08x,%p) stub\n", handle
, info
, (int)size
, ret_len
);
1392 if (size
> 4) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1397 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1401 case ProcessHandleTable
:
1402 FIXME( "ProcessHandleTable (%p,%p,0x%08x,%p) stub\n", handle
, info
, (int)size
, ret_len
);
1406 case ProcessAffinityMask
:
1407 len
= sizeof(ULONG_PTR
);
1410 const ULONG_PTR system_mask
= get_system_affinity_mask();
1412 SERVER_START_REQ(get_process_info
)
1414 req
->handle
= wine_server_obj_handle( handle
);
1415 if (!(ret
= wine_server_call( req
)))
1416 *(ULONG_PTR
*)info
= reply
->affinity
& system_mask
;
1420 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1423 case ProcessSessionInformation
:
1424 len
= sizeof(DWORD
);
1427 SERVER_START_REQ(get_process_info
)
1429 req
->handle
= wine_server_obj_handle( handle
);
1430 if (!(ret
= wine_server_call( req
)))
1431 *(DWORD
*)info
= reply
->session_id
;
1435 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1438 case ProcessWow64Information
:
1439 len
= sizeof(ULONG_PTR
);
1440 if (size
!= len
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1441 else if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1442 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1443 else if (handle
== GetCurrentProcess()) *(ULONG_PTR
*)info
= is_wow64();
1448 SERVER_START_REQ( get_process_info
)
1450 req
->handle
= wine_server_obj_handle( handle
);
1451 if (!(ret
= wine_server_call( req
))) val
= (reply
->machine
!= native_machine
);
1454 *(ULONG_PTR
*)info
= val
;
1458 case ProcessImageFileName
:
1459 /* FIXME: Should return a device path */
1460 case ProcessImageFileNameWin32
:
1461 SERVER_START_REQ( get_process_image_name
)
1463 UNICODE_STRING
*str
= info
;
1465 req
->handle
= wine_server_obj_handle( handle
);
1466 req
->win32
= (class == ProcessImageFileNameWin32
);
1467 wine_server_set_reply( req
, str
? str
+ 1 : NULL
,
1468 size
> sizeof(UNICODE_STRING
) ? size
- sizeof(UNICODE_STRING
) : 0 );
1469 ret
= wine_server_call( req
);
1470 if (ret
== STATUS_BUFFER_TOO_SMALL
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1471 len
= sizeof(UNICODE_STRING
) + reply
->len
;
1472 if (ret
== STATUS_SUCCESS
)
1474 str
->MaximumLength
= str
->Length
= reply
->len
;
1475 str
->Buffer
= (PWSTR
)(str
+ 1);
1481 case ProcessExecuteFlags
:
1482 len
= sizeof(ULONG
);
1484 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1485 else if (is_win64
&& !is_wow64())
1486 *(ULONG
*)info
= MEM_EXECUTE_OPTION_DISABLE
|
1487 MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION
|
1488 MEM_EXECUTE_OPTION_PERMANENT
;
1490 *(ULONG
*)info
= execute_flags
;
1493 case ProcessPriorityClass
:
1494 len
= sizeof(PROCESS_PRIORITY_CLASS
);
1497 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1500 PROCESS_PRIORITY_CLASS
*priority
= info
;
1502 SERVER_START_REQ(get_process_info
)
1504 req
->handle
= wine_server_obj_handle( handle
);
1505 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1507 priority
->PriorityClass
= reply
->priority
;
1508 /* FIXME: Not yet supported by the wineserver */
1509 priority
->Foreground
= FALSE
;
1515 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1519 FIXME( "ProcessCookie (%p,%p,0x%08x,%p) stub\n", handle
, info
, (int)size
, ret_len
);
1520 if (handle
== NtCurrentProcess())
1522 len
= sizeof(ULONG
);
1523 if (size
== len
) *(ULONG
*)info
= 0;
1524 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1526 else ret
= STATUS_INVALID_PARAMETER
;
1529 case ProcessImageInformation
:
1530 len
= sizeof(SECTION_IMAGE_INFORMATION
);
1535 pe_image_info_t pe_info
;
1537 SERVER_START_REQ( get_process_info
)
1539 req
->handle
= wine_server_obj_handle( handle
);
1540 wine_server_set_reply( req
, &pe_info
, sizeof(pe_info
) );
1541 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1542 virtual_fill_image_information( &pe_info
, info
);
1546 else ret
= STATUS_ACCESS_VIOLATION
;
1548 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1551 case ProcessCycleTime
:
1552 len
= sizeof(PROCESS_CYCLE_TIME_INFORMATION
);
1555 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1558 PROCESS_CYCLE_TIME_INFORMATION cycles
;
1560 FIXME( "ProcessCycleTime (%p,%p,0x%08x,%p) stub\n", handle
, info
, (int)size
, ret_len
);
1561 cycles
.AccumulatedCycles
= 0;
1562 cycles
.CurrentCycleCount
= 0;
1564 memcpy(info
, &cycles
, sizeof(PROCESS_CYCLE_TIME_INFORMATION
));
1567 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1570 case ProcessWineLdtCopy
:
1571 if (handle
== NtCurrentProcess())
1574 len
= sizeof(struct ldt_copy
*);
1575 if (size
== len
) *(struct ldt_copy
**)info
= &__wine_ldt_copy
;
1576 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1578 ret
= STATUS_NOT_IMPLEMENTED
;
1581 else ret
= STATUS_INVALID_PARAMETER
;
1585 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
1586 handle
, class, info
, (int)size
, ret_len
);
1587 ret
= STATUS_INVALID_INFO_CLASS
;
1591 if (ret_len
) *ret_len
= len
;
1596 /**********************************************************************
1597 * NtSetInformationProcess (NTDLL.@)
1599 NTSTATUS WINAPI
NtSetInformationProcess( HANDLE handle
, PROCESSINFOCLASS
class, void *info
, ULONG size
)
1601 unsigned int ret
= STATUS_SUCCESS
;
1605 case ProcessDefaultHardErrorMode
:
1606 if (size
!= sizeof(UINT
)) return STATUS_INVALID_PARAMETER
;
1607 process_error_mode
= *(UINT
*)info
;
1610 case ProcessAffinityMask
:
1612 const ULONG_PTR system_mask
= get_system_affinity_mask();
1614 if (size
!= sizeof(DWORD_PTR
)) return STATUS_INVALID_PARAMETER
;
1615 if (*(PDWORD_PTR
)info
& ~system_mask
)
1616 return STATUS_INVALID_PARAMETER
;
1617 if (!*(PDWORD_PTR
)info
)
1618 return STATUS_INVALID_PARAMETER
;
1619 SERVER_START_REQ( set_process_info
)
1621 req
->handle
= wine_server_obj_handle( handle
);
1622 req
->affinity
= *(PDWORD_PTR
)info
;
1623 req
->mask
= SET_PROCESS_INFO_AFFINITY
;
1624 ret
= wine_server_call( req
);
1629 case ProcessPriorityClass
:
1630 if (size
!= sizeof(PROCESS_PRIORITY_CLASS
)) return STATUS_INVALID_PARAMETER
;
1633 PROCESS_PRIORITY_CLASS
* ppc
= info
;
1635 SERVER_START_REQ( set_process_info
)
1637 req
->handle
= wine_server_obj_handle( handle
);
1638 /* FIXME Foreground isn't used */
1639 req
->priority
= ppc
->PriorityClass
;
1640 req
->mask
= SET_PROCESS_INFO_PRIORITY
;
1641 ret
= wine_server_call( req
);
1647 case ProcessExecuteFlags
:
1648 if ((is_win64
&& !is_wow64()) || size
!= sizeof(ULONG
)) return STATUS_INVALID_PARAMETER
;
1649 if (execute_flags
& MEM_EXECUTE_OPTION_PERMANENT
) return STATUS_ACCESS_DENIED
;
1653 switch (*(ULONG
*)info
& (MEM_EXECUTE_OPTION_ENABLE
|MEM_EXECUTE_OPTION_DISABLE
))
1655 case MEM_EXECUTE_OPTION_ENABLE
:
1658 case MEM_EXECUTE_OPTION_DISABLE
:
1662 return STATUS_INVALID_PARAMETER
;
1664 execute_flags
= *(ULONG
*)info
;
1665 virtual_set_force_exec( enable
);
1669 case ProcessInstrumentationCallback
:
1671 PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION
*instr
= info
;
1673 FIXME( "ProcessInstrumentationCallback stub.\n" );
1675 if (size
< sizeof(*instr
)) return STATUS_INFO_LENGTH_MISMATCH
;
1676 ret
= STATUS_SUCCESS
;
1680 case ProcessThreadStackAllocation
:
1684 PROCESS_STACK_ALLOCATION_INFORMATION
*stack
= info
;
1685 if (size
== sizeof(PROCESS_STACK_ALLOCATION_INFORMATION_EX
))
1686 stack
= &((PROCESS_STACK_ALLOCATION_INFORMATION_EX
*)info
)->AllocInfo
;
1687 else if (size
!= sizeof(*stack
)) return STATUS_INFO_LENGTH_MISMATCH
;
1689 reserve
= stack
->ReserveSize
;
1690 ret
= NtAllocateVirtualMemory( GetCurrentProcess(), &addr
, stack
->ZeroBits
, &reserve
,
1691 MEM_RESERVE
, PAGE_READWRITE
);
1694 #ifdef VALGRIND_STACK_REGISTER
1695 VALGRIND_STACK_REGISTER( addr
, (char *)addr
+ reserve
);
1697 stack
->StackBase
= addr
;
1702 case ProcessWineMakeProcessSystem
:
1703 if (size
!= sizeof(HANDLE
*)) return STATUS_INFO_LENGTH_MISMATCH
;
1704 SERVER_START_REQ( make_process_system
)
1706 req
->handle
= wine_server_obj_handle( handle
);
1707 if (!(ret
= wine_server_call( req
)))
1708 *(HANDLE
*)info
= wine_server_ptr_handle( reply
->event
);
1714 FIXME( "(%p,0x%08x,%p,0x%08x) stub\n", handle
, class, info
, (int)size
);
1715 ret
= STATUS_NOT_IMPLEMENTED
;
1722 /**********************************************************************
1723 * NtOpenProcess (NTDLL.@)
1725 NTSTATUS WINAPI
NtOpenProcess( HANDLE
*handle
, ACCESS_MASK access
,
1726 const OBJECT_ATTRIBUTES
*attr
, const CLIENT_ID
*id
)
1728 unsigned int status
;
1732 SERVER_START_REQ( open_process
)
1734 req
->pid
= HandleToULong( id
->UniqueProcess
);
1735 req
->access
= access
;
1736 req
->attributes
= attr
? attr
->Attributes
: 0;
1737 status
= wine_server_call( req
);
1738 if (!status
) *handle
= wine_server_ptr_handle( reply
->handle
);
1745 /**********************************************************************
1746 * NtSuspendProcess (NTDLL.@)
1748 NTSTATUS WINAPI
NtSuspendProcess( HANDLE handle
)
1752 SERVER_START_REQ( suspend_process
)
1754 req
->handle
= wine_server_obj_handle( handle
);
1755 ret
= wine_server_call( req
);
1762 /**********************************************************************
1763 * NtResumeProcess (NTDLL.@)
1765 NTSTATUS WINAPI
NtResumeProcess( HANDLE handle
)
1769 SERVER_START_REQ( resume_process
)
1771 req
->handle
= wine_server_obj_handle( handle
);
1772 ret
= wine_server_call( req
);
1779 /**********************************************************************
1780 * NtDebugActiveProcess (NTDLL.@)
1782 NTSTATUS WINAPI
NtDebugActiveProcess( 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 * NtRemoveProcessDebug (NTDLL.@)
1801 NTSTATUS WINAPI
NtRemoveProcessDebug( HANDLE process
, HANDLE debug
)
1805 SERVER_START_REQ( debug_process
)
1807 req
->handle
= wine_server_obj_handle( process
);
1808 req
->debug
= wine_server_obj_handle( debug
);
1810 ret
= wine_server_call( req
);
1817 /**********************************************************************
1818 * NtDebugContinue (NTDLL.@)
1820 NTSTATUS WINAPI
NtDebugContinue( HANDLE handle
, CLIENT_ID
*client
, NTSTATUS status
)
1824 SERVER_START_REQ( continue_debug_event
)
1826 req
->debug
= wine_server_obj_handle( handle
);
1827 req
->pid
= HandleToULong( client
->UniqueProcess
);
1828 req
->tid
= HandleToULong( client
->UniqueThread
);
1829 req
->status
= status
;
1830 ret
= wine_server_call( req
);