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 "ddk/ntddk.h"
69 #include "unix_private.h"
70 #include "wine/condrv.h"
71 #include "wine/server.h"
72 #include "wine/debug.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(process
);
77 static ULONG execute_flags
= MEM_EXECUTE_OPTION_DISABLE
;
79 static UINT process_error_mode
;
81 static char **build_argv( const UNICODE_STRING
*cmdline
, int reserved
)
83 char **argv
, *arg
, *src
, *dst
;
84 int argc
, in_quotes
= 0, bcount
= 0, len
= cmdline
->Length
/ sizeof(WCHAR
);
86 if (!(src
= malloc( len
* 3 + 1 ))) return NULL
;
87 len
= ntdll_wcstoumbs( cmdline
->Buffer
, len
, src
, len
* 3, FALSE
);
90 argc
= reserved
+ 2 + len
/ 2;
91 argv
= malloc( argc
* sizeof(*argv
) + len
);
92 arg
= dst
= (char *)(argv
+ argc
);
96 if ((*src
== ' ' || *src
== '\t') && !in_quotes
)
98 /* skip the remaining spaces */
99 while (*src
== ' ' || *src
== '\t') src
++;
101 /* close the argument and copy it */
104 /* start with a new argument */
108 else if (*src
== '\\')
113 else if (*src
== '"')
115 if ((bcount
& 1) == 0)
117 /* Preceded by an even number of '\', this is half that
118 * number of '\', plus a '"' which we discard.
122 if (in_quotes
&& *src
== '"') *dst
++ = *src
++;
123 else in_quotes
= !in_quotes
;
127 /* Preceded by an odd number of '\', this is half that
128 * number of '\' followed by a '"'
130 dst
-= bcount
/ 2 + 1;
135 else /* a regular character */
148 /***********************************************************************
151 static BOOL
get_so_file_info( int fd
, pe_image_info_t
*info
)
157 unsigned char magic
[4];
160 unsigned char version
;
161 unsigned char ignored1
[9];
163 unsigned short machine
;
164 unsigned char ignored2
[8];
166 unsigned char ignored3
[12];
167 unsigned short phnum
;
171 unsigned char magic
[4];
174 unsigned char ignored1
[10];
176 unsigned short machine
;
177 unsigned char ignored2
[12];
178 unsigned __int64 phoff
;
179 unsigned char ignored3
[16];
180 unsigned short phnum
;
185 unsigned int cputype
;
186 unsigned int cpusubtype
;
187 unsigned int filetype
;
194 if (pread( fd
, &header
, sizeof(header
), 0 ) != sizeof(header
)) return FALSE
;
196 if (!memcmp( header
.elf
.magic
, "\177ELF", 4 ))
199 unsigned short phnum
;
201 if (header
.elf
.version
!= 1 /* EV_CURRENT */) return FALSE
;
202 #ifdef WORDS_BIGENDIAN
203 if (header
.elf
.data
!= 2 /* ELFDATA2MSB */) return FALSE
;
205 if (header
.elf
.data
!= 1 /* ELFDATA2LSB */) return FALSE
;
207 switch (header
.elf
.machine
)
209 case 3: info
->machine
= IMAGE_FILE_MACHINE_I386
; break;
210 case 40: info
->machine
= IMAGE_FILE_MACHINE_ARMNT
; break;
211 case 62: info
->machine
= IMAGE_FILE_MACHINE_AMD64
; break;
212 case 183: info
->machine
= IMAGE_FILE_MACHINE_ARM64
; break;
214 if (header
.elf
.type
!= 3 /* ET_DYN */) return FALSE
;
215 if (header
.elf
.class == 2 /* ELFCLASS64 */)
217 pos
= header
.elf64
.phoff
;
218 phnum
= header
.elf64
.phnum
;
222 pos
= header
.elf
.phoff
;
223 phnum
= header
.elf
.phnum
;
227 if (pread( fd
, &type
, sizeof(type
), pos
) != sizeof(type
)) return FALSE
;
228 if (type
== 3 /* PT_INTERP */) return FALSE
;
229 pos
+= (header
.elf
.class == 2) ? 56 : 32;
233 else if (header
.macho
.magic
== 0xfeedface || header
.macho
.magic
== 0xfeedfacf)
235 switch (header
.macho
.cputype
)
237 case 0x00000007: info
->machine
= IMAGE_FILE_MACHINE_I386
; break;
238 case 0x01000007: info
->machine
= IMAGE_FILE_MACHINE_AMD64
; break;
239 case 0x0000000c: info
->machine
= IMAGE_FILE_MACHINE_ARMNT
; break;
240 case 0x0100000c: info
->machine
= IMAGE_FILE_MACHINE_ARM64
; break;
242 if (header
.macho
.filetype
== 8) return TRUE
;
248 /***********************************************************************
251 static unsigned int get_pe_file_info( OBJECT_ATTRIBUTES
*attr
, HANDLE
*handle
, pe_image_info_t
*info
)
258 memset( info
, 0, sizeof(*info
) );
259 if (!(status
= nt_to_unix_file_name( attr
, &unix_name
, FILE_OPEN
)))
261 status
= open_unix_file( handle
, unix_name
, GENERIC_READ
, attr
, 0,
262 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
263 FILE_OPEN
, FILE_SYNCHRONOUS_IO_NONALERT
, NULL
, 0 );
268 if (is_builtin_path( attr
->ObjectName
, &info
->machine
))
270 TRACE( "assuming %04x builtin for %s\n", info
->machine
, debugstr_us(attr
->ObjectName
));
271 return STATUS_SUCCESS
;
276 if (!(status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
|
277 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
,
278 NULL
, NULL
, PAGE_EXECUTE_READ
, SEC_IMAGE
, *handle
)))
280 SERVER_START_REQ( get_mapping_info
)
282 req
->handle
= wine_server_obj_handle( mapping
);
283 req
->access
= SECTION_QUERY
;
284 wine_server_set_reply( req
, info
, sizeof(*info
) );
285 status
= wine_server_call( req
);
289 if (info
->image_charact
& IMAGE_FILE_DLL
) return STATUS_INVALID_IMAGE_FORMAT
;
291 else if (status
== STATUS_INVALID_IMAGE_NOT_MZ
)
293 int unix_fd
, needs_close
;
295 if (!server_get_unix_fd( *handle
, FILE_READ_DATA
, &unix_fd
, &needs_close
, NULL
, NULL
))
297 if (get_so_file_info( unix_fd
, info
)) status
= STATUS_SUCCESS
;
298 if (needs_close
) close( unix_fd
);
305 /***********************************************************************
308 static ULONG
get_env_size( const RTL_USER_PROCESS_PARAMETERS
*params
, char **winedebug
)
310 WCHAR
*ptr
= params
->Environment
;
314 static const WCHAR WINEDEBUG
[] = {'W','I','N','E','D','E','B','U','G','=',0};
315 if (!*winedebug
&& !wcsncmp( ptr
, WINEDEBUG
, ARRAY_SIZE( WINEDEBUG
) - 1 ))
317 DWORD len
= wcslen(ptr
) * 3 + 1;
318 if ((*winedebug
= malloc( len
)))
319 ntdll_wcstoumbs( ptr
, wcslen(ptr
) + 1, *winedebug
, len
, FALSE
);
321 ptr
+= wcslen(ptr
) + 1;
324 return (ptr
- params
->Environment
) * sizeof(WCHAR
);
328 /***********************************************************************
331 * Simplified version of RtlDosPathNameToNtPathName_U.
333 static WCHAR
*get_nt_pathname( const UNICODE_STRING
*str
)
335 static const WCHAR ntprefixW
[] = {'\\','?','?','\\',0};
336 static const WCHAR uncprefixW
[] = {'U','N','C','\\',0};
337 const WCHAR
*name
= str
->Buffer
;
340 if (!(ret
= malloc( str
->Length
+ 8 * sizeof(WCHAR
) ))) return NULL
;
342 wcscpy( ret
, ntprefixW
);
343 if (name
[0] == '\\' && name
[1] == '\\')
345 if ((name
[2] == '.' || name
[2] == '?') && name
[3] == '\\') name
+= 4;
348 wcscat( ret
, uncprefixW
);
357 /***********************************************************************
360 static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS
*params
)
362 UNICODE_STRING nt_name
, redir
;
363 OBJECT_ATTRIBUTES attr
;
369 if (!(nt_name
.Buffer
= get_nt_pathname( ¶ms
->CurrentDirectory
.DosPath
))) return -1;
370 nt_name
.Length
= wcslen( nt_name
.Buffer
) * sizeof(WCHAR
);
372 InitializeObjectAttributes( &attr
, &nt_name
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
373 get_redirect( &attr
, &redir
);
374 status
= nt_to_unix_file_name( &attr
, &unix_name
, FILE_OPEN
);
375 if (status
) goto done
;
376 status
= open_unix_file( &handle
, unix_name
, FILE_TRAVERSE
| SYNCHRONIZE
, &attr
, 0,
377 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
378 FILE_OPEN
, FILE_SYNCHRONOUS_IO_NONALERT
, NULL
, 0 );
380 if (status
) goto done
;
381 wine_server_handle_to_fd( handle
, FILE_TRAVERSE
, &fd
, NULL
);
385 free( nt_name
.Buffer
);
386 free( redir
.Buffer
);
391 /***********************************************************************
394 static void set_stdio_fd( int stdin_fd
, int stdout_fd
)
398 if (stdin_fd
== -1 || stdout_fd
== -1)
400 fd
= open( "/dev/null", O_RDWR
);
401 if (stdin_fd
== -1) stdin_fd
= fd
;
402 if (stdout_fd
== -1) stdout_fd
= fd
;
405 if (stdin_fd
!= 0) dup2( stdin_fd
, 0 );
406 if (stdout_fd
!= 1) dup2( stdout_fd
, 1 );
407 if (fd
!= -1) close( fd
);
411 /***********************************************************************
412 * is_unix_console_handle
414 static BOOL
is_unix_console_handle( HANDLE handle
)
416 return !sync_ioctl( handle
, IOCTL_CONDRV_IS_UNIX
, NULL
, 0, NULL
, 0 );
420 /***********************************************************************
423 static NTSTATUS
spawn_process( const RTL_USER_PROCESS_PARAMETERS
*params
, int socketfd
,
424 int unixdir
, char *winedebug
, const pe_image_info_t
*pe_info
)
426 NTSTATUS status
= STATUS_SUCCESS
;
427 int stdin_fd
= -1, stdout_fd
= -1;
431 if (wine_server_handle_to_fd( params
->hStdInput
, FILE_READ_DATA
, &stdin_fd
, NULL
) &&
432 isatty(0) && is_unix_console_handle( params
->hStdInput
))
435 if (wine_server_handle_to_fd( params
->hStdOutput
, FILE_WRITE_DATA
, &stdout_fd
, NULL
) &&
436 isatty(1) && is_unix_console_handle( params
->hStdOutput
))
439 if (!(pid
= fork())) /* child */
441 if (!(pid
= fork())) /* grandchild */
443 if ((peb
->ProcessParameters
&& params
->ProcessGroupId
!= peb
->ProcessParameters
->ProcessGroupId
) ||
444 params
->ConsoleHandle
== CONSOLE_HANDLE_ALLOC
||
445 params
->ConsoleHandle
== CONSOLE_HANDLE_ALLOC_NO_WINDOW
||
446 params
->ConsoleHandle
== NULL
)
449 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
451 else set_stdio_fd( stdin_fd
, stdout_fd
);
453 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
454 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
456 if (winedebug
) putenv( winedebug
);
462 argv
= build_argv( ¶ms
->CommandLine
, 2 );
464 exec_wineloader( argv
, socketfd
, pe_info
);
476 wret
= waitpid(pid
, NULL
, 0);
477 } while (wret
< 0 && errno
== EINTR
);
479 else status
= STATUS_NO_MEMORY
;
481 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
482 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
487 /***********************************************************************
488 * __wine_unix_spawnvp
490 NTSTATUS WINAPI
__wine_unix_spawnvp( char * const argv
[], int wait
)
493 int fd
[2], status
, err
;
496 if (pipe2( fd
, O_CLOEXEC
) == -1)
499 if (pipe(fd
) == -1) return STATUS_TOO_MANY_OPENED_FILES
;
500 fcntl( fd
[0], F_SETFD
, FD_CLOEXEC
);
501 fcntl( fd
[1], F_SETFD
, FD_CLOEXEC
);
508 signal( SIGPIPE
, SIG_DFL
);
511 if (!(pid
= fork())) execvp( argv
[0], argv
); /* in grandchild */
512 if (pid
> 0) _exit(0); /* exit child if fork succeeded */
514 else execvp( argv
[0], argv
);
516 err
= errno_to_status( errno
);
517 write( fd
[1], &err
, sizeof(err
) );
524 while (pid
!= (wret
= waitpid( pid
, &status
, 0 )))
525 if (wret
== -1 && errno
!= EINTR
) break;
527 if (read( fd
[0], &err
, sizeof(err
) ) <= 0) /* if we read something, exec or second fork failed */
529 if (pid
== wret
&& WIFEXITED(status
)) err
= WEXITSTATUS(status
);
530 else err
= 255; /* abnormal exit with an abort or an interrupt */
533 else err
= errno_to_status( errno
);
540 /***********************************************************************
541 * unixcall_wine_spawnvp
543 NTSTATUS
unixcall_wine_spawnvp( void *args
)
545 struct wine_spawnvp_params
*params
= args
;
547 return __wine_unix_spawnvp( params
->argv
, params
->wait
);
552 /***********************************************************************
555 NTSTATUS
wow64_wine_spawnvp( void *args
)
561 } const *params32
= args
;
563 ULONG
*argv32
= ULongToPtr( params32
->argv
);
564 unsigned int i
, count
= 0;
568 while (argv32
[count
]) count
++;
569 argv
= malloc( (count
+ 1) * sizeof(*argv
) );
570 for (i
= 0; i
< count
; i
++) argv
[i
] = ULongToPtr( argv32
[i
] );
572 ret
= __wine_unix_spawnvp( argv
, params32
->wait
);
578 /***********************************************************************
581 * Fork and exec a new Unix binary, checking for errors.
583 static NTSTATUS
fork_and_exec( OBJECT_ATTRIBUTES
*attr
, int unixdir
,
584 const RTL_USER_PROCESS_PARAMETERS
*params
)
587 int fd
[2], stdin_fd
= -1, stdout_fd
= -1;
592 status
= nt_to_unix_file_name( attr
, &unix_name
, FILE_OPEN
);
593 if (status
) return status
;
596 if (pipe2( fd
, O_CLOEXEC
) == -1)
601 status
= STATUS_TOO_MANY_OPENED_FILES
;
604 fcntl( fd
[0], F_SETFD
, FD_CLOEXEC
);
605 fcntl( fd
[1], F_SETFD
, FD_CLOEXEC
);
608 if (wine_server_handle_to_fd( params
->hStdInput
, FILE_READ_DATA
, &stdin_fd
, NULL
) &&
609 isatty(0) && is_unix_console_handle( params
->hStdInput
))
612 if (wine_server_handle_to_fd( params
->hStdOutput
, FILE_WRITE_DATA
, &stdout_fd
, NULL
) &&
613 isatty(1) && is_unix_console_handle( params
->hStdOutput
))
616 if (!(pid
= fork())) /* child */
618 if (!(pid
= fork())) /* grandchild */
622 if ((peb
->ProcessParameters
&& params
->ProcessGroupId
!= peb
->ProcessParameters
->ProcessGroupId
) ||
623 params
->ConsoleHandle
== CONSOLE_HANDLE_ALLOC
||
624 params
->ConsoleHandle
== CONSOLE_HANDLE_ALLOC_NO_WINDOW
||
625 params
->ConsoleHandle
== NULL
)
628 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
630 else set_stdio_fd( stdin_fd
, stdout_fd
);
632 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
633 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
635 /* Reset signals that we previously set to SIG_IGN */
636 signal( SIGPIPE
, SIG_DFL
);
638 argv
= build_argv( ¶ms
->CommandLine
, 0 );
639 envp
= build_envp( params
->Environment
);
645 execve( unix_name
, argv
, envp
);
648 if (pid
<= 0) /* grandchild if exec failed or child if fork failed */
653 case EACCES
: status
= STATUS_ACCESS_DENIED
; break;
654 case ENOENT
: status
= STATUS_OBJECT_NAME_NOT_FOUND
; break;
656 case ENFILE
: status
= STATUS_TOO_MANY_OPENED_FILES
; break;
658 case EINVAL
: status
= STATUS_INVALID_IMAGE_FORMAT
; break;
659 default: status
= STATUS_NO_MEMORY
; break;
661 write( fd
[1], &status
, sizeof(status
) );
664 _exit(0); /* child if fork succeeded */
673 wret
= waitpid(pid
, NULL
, 0);
674 } while (wret
< 0 && errno
== EINTR
);
675 read( fd
[0], &status
, sizeof(status
) ); /* if we read something, exec or second fork failed */
677 else status
= STATUS_NO_MEMORY
;
680 if (stdin_fd
!= -1 && stdin_fd
!= 0) close( stdin_fd
);
681 if (stdout_fd
!= -1 && stdout_fd
!= 1) close( stdout_fd
);
687 static NTSTATUS
alloc_handle_list( const PS_ATTRIBUTE
*handles_attr
, obj_handle_t
**handles
, data_size_t
*handles_len
)
695 if (!handles_attr
) return STATUS_SUCCESS
;
697 count
= handles_attr
->Size
/ sizeof(HANDLE
);
699 if (!(*handles
= calloc( sizeof(**handles
), count
))) return STATUS_NO_MEMORY
;
701 src
= handles_attr
->ValuePtr
;
702 for (i
= 0; i
< count
; ++i
)
703 (*handles
)[i
] = wine_server_obj_handle( src
[i
] );
705 *handles_len
= count
* sizeof(**handles
);
707 return STATUS_SUCCESS
;
710 /**********************************************************************
711 * NtCreateUserProcess (NTDLL.@)
713 NTSTATUS WINAPI
NtCreateUserProcess( HANDLE
*process_handle_ptr
, HANDLE
*thread_handle_ptr
,
714 ACCESS_MASK process_access
, ACCESS_MASK thread_access
,
715 OBJECT_ATTRIBUTES
*process_attr
, OBJECT_ATTRIBUTES
*thread_attr
,
716 ULONG process_flags
, ULONG thread_flags
,
717 RTL_USER_PROCESS_PARAMETERS
*params
, PS_CREATE_INFO
*info
,
718 PS_ATTRIBUTE_LIST
*ps_attr
)
721 BOOL success
= FALSE
;
722 HANDLE file_handle
, process_info
= 0, process_handle
= 0, thread_handle
= 0;
723 struct object_attributes
*objattr
;
724 data_size_t attr_len
;
725 char *winedebug
= NULL
;
726 startup_info_t
*startup_info
= NULL
;
727 ULONG startup_info_size
, env_size
;
728 int unixdir
, socketfd
[2] = { -1, -1 };
729 pe_image_info_t pe_info
;
732 HANDLE parent
= 0, debug
= 0, token
= 0;
733 UNICODE_STRING redir
, path
= {0};
734 OBJECT_ATTRIBUTES attr
, empty_attr
= { sizeof(empty_attr
) };
735 SIZE_T i
, attr_count
= (ps_attr
->TotalLength
- sizeof(ps_attr
->TotalLength
)) / sizeof(PS_ATTRIBUTE
);
736 const PS_ATTRIBUTE
*handles_attr
= NULL
, *jobs_attr
= NULL
;
737 data_size_t handles_size
, jobs_size
;
738 obj_handle_t
*handles
, *jobs
;
740 if (thread_flags
& THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER
)
742 WARN( "Invalid thread flags %#x.\n", (int)thread_flags
);
744 return STATUS_INVALID_PARAMETER
;
747 if (thread_flags
& ~THREAD_CREATE_FLAGS_CREATE_SUSPENDED
)
748 FIXME( "Unsupported thread flags %#x.\n", (int)thread_flags
);
750 for (i
= 0; i
< attr_count
; i
++)
752 switch (ps_attr
->Attributes
[i
].Attribute
)
754 case PS_ATTRIBUTE_PARENT_PROCESS
:
755 parent
= ps_attr
->Attributes
[i
].ValuePtr
;
757 case PS_ATTRIBUTE_DEBUG_PORT
:
758 debug
= ps_attr
->Attributes
[i
].ValuePtr
;
760 case PS_ATTRIBUTE_IMAGE_NAME
:
761 path
.Length
= ps_attr
->Attributes
[i
].Size
;
762 path
.Buffer
= ps_attr
->Attributes
[i
].ValuePtr
;
764 case PS_ATTRIBUTE_TOKEN
:
765 token
= ps_attr
->Attributes
[i
].ValuePtr
;
767 case PS_ATTRIBUTE_HANDLE_LIST
:
768 if (process_flags
& PROCESS_CREATE_FLAGS_INHERIT_HANDLES
)
769 handles_attr
= &ps_attr
->Attributes
[i
];
771 case PS_ATTRIBUTE_JOB_LIST
:
772 jobs_attr
= &ps_attr
->Attributes
[i
];
774 case PS_ATTRIBUTE_MACHINE_TYPE
:
775 machine
= ps_attr
->Attributes
[i
].Value
;
778 if (ps_attr
->Attributes
[i
].Attribute
& PS_ATTRIBUTE_INPUT
)
779 FIXME( "unhandled input attribute %lx\n", ps_attr
->Attributes
[i
].Attribute
);
783 if (!process_attr
) process_attr
= &empty_attr
;
785 TRACE( "%s image %s cmdline %s parent %p machine %x\n", debugstr_us( &path
),
786 debugstr_us( ¶ms
->ImagePathName
), debugstr_us( ¶ms
->CommandLine
), parent
, machine
);
788 unixdir
= get_unix_curdir( params
);
790 InitializeObjectAttributes( &attr
, &path
, OBJ_CASE_INSENSITIVE
, 0, 0 );
791 get_redirect( &attr
, &redir
);
793 if ((status
= get_pe_file_info( &attr
, &file_handle
, &pe_info
)))
795 if (status
== STATUS_INVALID_IMAGE_NOT_MZ
&& !fork_and_exec( &attr
, unixdir
, params
))
797 memset( info
, 0, sizeof(*info
) );
798 free( redir
.Buffer
);
799 return STATUS_SUCCESS
;
805 machine
= pe_info
.machine
;
806 if (is_arm64ec() && pe_info
.is_hybrid
&& machine
== IMAGE_FILE_MACHINE_ARM64
)
807 machine
= main_image_info
.Machine
;
809 if (!(startup_info
= create_startup_info( attr
.ObjectName
, process_flags
, params
, &pe_info
, &startup_info_size
)))
811 env_size
= get_env_size( params
, &winedebug
);
813 if ((status
= alloc_object_attributes( process_attr
, &objattr
, &attr_len
))) goto done
;
815 if ((status
= alloc_handle_list( handles_attr
, &handles
, &handles_size
)))
821 if ((status
= alloc_handle_list( jobs_attr
, &jobs
, &jobs_size
)))
828 /* create the socket for the new process */
830 if (socketpair( PF_UNIX
, SOCK_STREAM
, 0, socketfd
) == -1)
832 status
= STATUS_TOO_MANY_OPENED_FILES
;
842 setsockopt( socketfd
[0], SOL_SOCKET
, SO_PASSCRED
, &enable
, sizeof(enable
) );
846 wine_server_send_fd( socketfd
[1] );
848 /* create the process on the server side */
850 SERVER_START_REQ( new_process
)
852 req
->token
= wine_server_obj_handle( token
);
853 req
->debug
= wine_server_obj_handle( debug
);
854 req
->parent_process
= wine_server_obj_handle( parent
);
855 req
->flags
= process_flags
;
856 req
->socket_fd
= socketfd
[1];
857 req
->access
= process_access
;
858 req
->machine
= machine
;
859 req
->info_size
= startup_info_size
;
860 req
->handles_size
= handles_size
;
861 req
->jobs_size
= jobs_size
;
862 wine_server_add_data( req
, objattr
, attr_len
);
863 wine_server_add_data( req
, handles
, handles_size
);
864 wine_server_add_data( req
, jobs
, jobs_size
);
865 wine_server_add_data( req
, startup_info
, startup_info_size
);
866 wine_server_add_data( req
, params
->Environment
, env_size
);
867 if (!(status
= wine_server_call( req
)))
869 process_handle
= wine_server_ptr_handle( reply
->handle
);
870 id
.UniqueProcess
= ULongToHandle( reply
->pid
);
872 process_info
= wine_server_ptr_handle( reply
->info
);
875 close( socketfd
[1] );
884 case STATUS_INVALID_IMAGE_WIN_64
:
885 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_us(&path
) );
887 case STATUS_INVALID_IMAGE_FORMAT
:
888 ERR( "%s not supported on this installation (machine %04x)\n",
889 debugstr_us(&path
), pe_info
.machine
);
895 if ((status
= alloc_object_attributes( thread_attr
, &objattr
, &attr_len
))) goto done
;
897 SERVER_START_REQ( new_thread
)
899 req
->process
= wine_server_obj_handle( process_handle
);
900 req
->access
= thread_access
;
901 req
->flags
= thread_flags
;
902 req
->request_fd
= -1;
903 wine_server_add_data( req
, objattr
, attr_len
);
904 if (!(status
= wine_server_call( req
)))
906 thread_handle
= wine_server_ptr_handle( reply
->handle
);
907 id
.UniqueThread
= ULongToHandle( reply
->tid
);
912 if (status
) goto done
;
914 /* create the child process */
916 if ((status
= spawn_process( params
, socketfd
[0], unixdir
, winedebug
, &pe_info
))) goto done
;
918 close( socketfd
[0] );
921 /* wait for the new process info to be ready */
923 NtWaitForSingleObject( process_info
, FALSE
, NULL
);
924 SERVER_START_REQ( get_new_process_info
)
926 req
->info
= wine_server_obj_handle( process_info
);
927 wine_server_call( req
);
928 success
= reply
->success
;
929 status
= reply
->exit_code
;
935 if (!status
) status
= STATUS_INTERNAL_ERROR
;
939 TRACE( "%s pid %04x tid %04x handles %p/%p\n", debugstr_us(&path
),
940 (int)HandleToULong(id
.UniqueProcess
), (int)HandleToULong(id
.UniqueThread
),
941 process_handle
, thread_handle
);
943 /* update output attributes */
945 for (i
= 0; i
< attr_count
; i
++)
947 switch (ps_attr
->Attributes
[i
].Attribute
)
949 case PS_ATTRIBUTE_CLIENT_ID
:
951 SIZE_T size
= min( ps_attr
->Attributes
[i
].Size
, sizeof(id
) );
952 memcpy( ps_attr
->Attributes
[i
].ValuePtr
, &id
, size
);
953 if (ps_attr
->Attributes
[i
].ReturnLength
) *ps_attr
->Attributes
[i
].ReturnLength
= size
;
956 case PS_ATTRIBUTE_IMAGE_INFO
:
958 SECTION_IMAGE_INFORMATION info
;
959 SIZE_T size
= min( ps_attr
->Attributes
[i
].Size
, sizeof(info
) );
960 virtual_fill_image_information( &pe_info
, &info
);
961 memcpy( ps_attr
->Attributes
[i
].ValuePtr
, &info
, size
);
962 if (ps_attr
->Attributes
[i
].ReturnLength
) *ps_attr
->Attributes
[i
].ReturnLength
= size
;
965 case PS_ATTRIBUTE_TEB_ADDRESS
:
967 if (!(ps_attr
->Attributes
[i
].Attribute
& PS_ATTRIBUTE_INPUT
))
968 FIXME( "unhandled output attribute %lx\n", ps_attr
->Attributes
[i
].Attribute
);
972 *process_handle_ptr
= process_handle
;
973 *thread_handle_ptr
= thread_handle
;
974 process_handle
= thread_handle
= 0;
975 status
= STATUS_SUCCESS
;
978 if (file_handle
) NtClose( file_handle
);
979 if (process_info
) NtClose( process_info
);
980 if (process_handle
) NtClose( process_handle
);
981 if (thread_handle
) NtClose( thread_handle
);
982 if (socketfd
[0] != -1) close( socketfd
[0] );
983 if (unixdir
!= -1) close( unixdir
);
984 free( startup_info
);
986 free( redir
.Buffer
);
991 /******************************************************************************
992 * NtTerminateProcess (NTDLL.@)
994 NTSTATUS WINAPI
NtTerminateProcess( HANDLE handle
, LONG exit_code
)
999 SERVER_START_REQ( terminate_process
)
1001 req
->handle
= wine_server_obj_handle( handle
);
1002 req
->exit_code
= exit_code
;
1003 ret
= wine_server_call( req
);
1009 if (!handle
) process_exiting
= TRUE
;
1010 else if (process_exiting
) exit_process( exit_code
);
1011 else abort_process( exit_code
);
1017 #if defined(HAVE_MACH_MACH_H)
1019 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1021 #if defined(MACH_TASK_BASIC_INFO)
1022 struct mach_task_basic_info info
;
1023 mach_msg_type_number_t infoCount
;
1025 if (unix_pid
!= -1) return; /* FIXME: Retrieve information for other processes. */
1027 infoCount
= MACH_TASK_BASIC_INFO_COUNT
;
1028 if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO
, (task_info_t
)&info
, &infoCount
) == KERN_SUCCESS
)
1030 pvmi
->VirtualSize
= info
.resident_size
+ info
.virtual_size
;
1031 pvmi
->PagefileUsage
= info
.virtual_size
;
1032 pvmi
->WorkingSetSize
= info
.resident_size
;
1033 pvmi
->PeakWorkingSetSize
= info
.resident_size_max
;
1038 #elif defined(linux)
1040 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1043 char line
[256], path
[26];
1044 unsigned long value
;
1047 strcpy( path
, "/proc/self/status" );
1049 snprintf( path
, sizeof(path
), "/proc/%u/status", unix_pid
);
1050 f
= fopen( path
, "r" );
1053 while (fgets(line
, sizeof(line
), f
))
1055 if (sscanf(line
, "VmPeak: %lu", &value
))
1056 pvmi
->PeakVirtualSize
= (ULONG64
)value
* 1024;
1057 else if (sscanf(line
, "VmSize: %lu", &value
))
1058 pvmi
->VirtualSize
= (ULONG64
)value
* 1024;
1059 else if (sscanf(line
, "VmHWM: %lu", &value
))
1060 pvmi
->PeakWorkingSetSize
= (ULONG64
)value
* 1024;
1061 else if (sscanf(line
, "VmRSS: %lu", &value
))
1062 pvmi
->WorkingSetSize
= (ULONG64
)value
* 1024;
1063 else if (sscanf(line
, "RssAnon: %lu", &value
))
1064 pvmi
->PagefileUsage
+= (ULONG64
)value
* 1024;
1065 else if (sscanf(line
, "VmSwap: %lu", &value
))
1066 pvmi
->PagefileUsage
+= (ULONG64
)value
* 1024;
1068 pvmi
->PeakPagefileUsage
= pvmi
->PagefileUsage
;
1073 #elif defined(HAVE_LIBPROCSTAT)
1075 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1077 struct procstat
*pstat
;
1078 struct kinfo_proc
*kip
;
1079 unsigned int proc_count
;
1081 pstat
= procstat_open_sysctl();
1084 kip
= procstat_getprocs( pstat
, KERN_PROC_PID
, unix_pid
== -1 ? getpid() : unix_pid
, &proc_count
);
1087 pvmi
->VirtualSize
= kip
->ki_size
;
1088 pvmi
->PeakVirtualSize
= kip
->ki_size
;
1089 pvmi
->WorkingSetSize
= kip
->ki_rssize
<< PAGE_SHIFT
;
1090 pvmi
->PeakWorkingSetSize
= kip
->ki_rusage
.ru_maxrss
* 1024;
1091 procstat_freeprocs( pstat
, kip
);
1093 procstat_close( pstat
);
1099 void fill_vm_counters( VM_COUNTERS_EX
*pvmi
, int unix_pid
)
1101 /* FIXME : real data */
1106 #define UNIMPLEMENTED_INFO_CLASS(c) \
1108 FIXME( "(process=%p) Unimplemented information class: " #c "\n", handle); \
1109 ret = STATUS_INVALID_INFO_CLASS; \
1112 /**********************************************************************
1113 * NtQueryInformationProcess (NTDLL.@)
1115 NTSTATUS WINAPI
NtQueryInformationProcess( HANDLE handle
, PROCESSINFOCLASS
class, void *info
,
1116 ULONG size
, ULONG
*ret_len
)
1118 unsigned int ret
= STATUS_SUCCESS
;
1121 TRACE( "(%p,0x%08x,%p,0x%08x,%p)\n", handle
, class, info
, (int)size
, ret_len
);
1125 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority
);
1126 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority
);
1127 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort
);
1128 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken
);
1129 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation
);
1130 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize
);
1131 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers
);
1132 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits
);
1133 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch
);
1134 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL
);
1135 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup
);
1136 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information
);
1137 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost
);
1138 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap
);
1139 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation
);
1140 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled
);
1141 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination
);
1142 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing
);
1144 case ProcessBasicInformation
:
1146 PROCESS_BASIC_INFORMATION pbi
;
1147 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1149 if (size
>= sizeof(PROCESS_BASIC_INFORMATION
))
1151 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1154 SERVER_START_REQ(get_process_info
)
1156 req
->handle
= wine_server_obj_handle( handle
);
1157 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1159 pbi
.ExitStatus
= reply
->exit_code
;
1160 pbi
.PebBaseAddress
= wine_server_get_ptr( reply
->peb
);
1161 pbi
.AffinityMask
= reply
->affinity
& affinity_mask
;
1162 pbi
.BasePriority
= reply
->priority
;
1163 pbi
.UniqueProcessId
= reply
->pid
;
1164 pbi
.InheritedFromUniqueProcessId
= reply
->ppid
;
1167 if (reply
->machine
!= native_machine
)
1168 pbi
.PebBaseAddress
= (PEB
*)((char *)pbi
.PebBaseAddress
+ 0x1000);
1170 pbi
.PebBaseAddress
= NULL
;
1176 memcpy( info
, &pbi
, sizeof(PROCESS_BASIC_INFORMATION
) );
1177 len
= sizeof(PROCESS_BASIC_INFORMATION
);
1179 if (size
> sizeof(PROCESS_BASIC_INFORMATION
)) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1183 len
= sizeof(PROCESS_BASIC_INFORMATION
);
1184 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1189 case ProcessIoCounters
:
1193 if (size
>= sizeof(IO_COUNTERS
))
1195 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1196 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1199 /* FIXME : real data */
1200 memset(&pii
, 0 , sizeof(IO_COUNTERS
));
1201 memcpy(info
, &pii
, sizeof(IO_COUNTERS
));
1202 len
= sizeof(IO_COUNTERS
);
1204 if (size
> sizeof(IO_COUNTERS
)) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1208 len
= sizeof(IO_COUNTERS
);
1209 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1214 case ProcessVmCounters
:
1216 VM_COUNTERS_EX pvmi
;
1218 /* older Windows versions don't have the PrivateUsage field */
1219 if (size
>= sizeof(VM_COUNTERS
))
1221 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1224 memset(&pvmi
, 0, sizeof(pvmi
));
1225 if (handle
== GetCurrentProcess()) fill_vm_counters( &pvmi
, -1 );
1228 SERVER_START_REQ(get_process_vm_counters
)
1230 req
->handle
= wine_server_obj_handle( handle
);
1231 if (!(ret
= wine_server_call( req
)))
1233 pvmi
.PeakVirtualSize
= reply
->peak_virtual_size
;
1234 pvmi
.VirtualSize
= reply
->virtual_size
;
1235 pvmi
.PeakWorkingSetSize
= reply
->peak_working_set_size
;
1236 pvmi
.WorkingSetSize
= reply
->working_set_size
;
1237 pvmi
.PagefileUsage
= reply
->pagefile_usage
;
1238 pvmi
.PeakPagefileUsage
= reply
->peak_pagefile_usage
;
1244 if (size
>= sizeof(VM_COUNTERS_EX
))
1245 pvmi
.PrivateUsage
= pvmi
.PagefileUsage
;
1247 if (len
!= sizeof(VM_COUNTERS
)) len
= sizeof(VM_COUNTERS_EX
);
1248 memcpy(info
, &pvmi
, min(size
, sizeof(pvmi
)));
1250 if (size
!= sizeof(VM_COUNTERS
) && size
!= sizeof(VM_COUNTERS_EX
))
1251 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1256 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1263 KERNEL_USER_TIMES pti
= {{{0}}};
1265 if (size
>= sizeof(KERNEL_USER_TIMES
))
1267 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1268 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1271 long ticks
= sysconf(_SC_CLK_TCK
);
1274 /* FIXME: user/kernel times only work for current process */
1275 if (ticks
&& times( &tms
) != -1)
1277 pti
.UserTime
.QuadPart
= (ULONGLONG
)tms
.tms_utime
* 10000000 / ticks
;
1278 pti
.KernelTime
.QuadPart
= (ULONGLONG
)tms
.tms_stime
* 10000000 / ticks
;
1281 SERVER_START_REQ(get_process_info
)
1283 req
->handle
= wine_server_obj_handle( handle
);
1284 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1286 pti
.CreateTime
.QuadPart
= reply
->start_time
;
1287 pti
.ExitTime
.QuadPart
= reply
->end_time
;
1292 memcpy(info
, &pti
, sizeof(KERNEL_USER_TIMES
));
1293 len
= sizeof(KERNEL_USER_TIMES
);
1295 if (size
> sizeof(KERNEL_USER_TIMES
)) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1299 len
= sizeof(KERNEL_USER_TIMES
);
1300 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1305 case ProcessDebugPort
:
1306 len
= sizeof(DWORD_PTR
);
1307 if (size
!= len
) return STATUS_INFO_LENGTH_MISMATCH
;
1308 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1313 SERVER_START_REQ(get_process_debug_info
)
1315 req
->handle
= wine_server_obj_handle( handle
);
1316 ret
= wine_server_call( req
);
1317 debug
= wine_server_ptr_handle( reply
->debug
);
1320 if (ret
== STATUS_SUCCESS
)
1322 *(DWORD_PTR
*)info
= ~0ul;
1325 else if (ret
== STATUS_PORT_NOT_SET
)
1327 *(DWORD_PTR
*)info
= 0;
1328 ret
= STATUS_SUCCESS
;
1334 case ProcessDebugFlags
:
1335 len
= sizeof(DWORD
);
1338 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1343 SERVER_START_REQ(get_process_debug_info
)
1345 req
->handle
= wine_server_obj_handle( handle
);
1346 ret
= wine_server_call( req
);
1347 debug
= wine_server_ptr_handle( reply
->debug
);
1348 *(DWORD
*)info
= reply
->debug_children
;
1351 if (ret
== STATUS_SUCCESS
) NtClose( debug
);
1352 else if (ret
== STATUS_PORT_NOT_SET
) ret
= STATUS_SUCCESS
;
1355 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1358 case ProcessDefaultHardErrorMode
:
1359 len
= sizeof(process_error_mode
);
1360 if (size
== len
) memcpy(info
, &process_error_mode
, len
);
1361 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1364 case ProcessDebugObjectHandle
:
1365 len
= sizeof(HANDLE
);
1366 if (size
!= len
) return STATUS_INFO_LENGTH_MISMATCH
;
1367 SERVER_START_REQ(get_process_debug_info
)
1369 req
->handle
= wine_server_obj_handle( handle
);
1370 ret
= wine_server_call( req
);
1371 *(HANDLE
*)info
= wine_server_ptr_handle( reply
->debug
);
1376 case ProcessHandleCount
:
1379 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1380 else if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1383 FIXME( "ProcessHandleCount (%p,%p,0x%08x,%p) stub\n", handle
, info
, (int)size
, ret_len
);
1387 if (size
> 4) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1392 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1396 case ProcessHandleTable
:
1397 FIXME( "ProcessHandleTable (%p,%p,0x%08x,%p) stub\n", handle
, info
, (int)size
, ret_len
);
1401 case ProcessAffinityMask
:
1402 len
= sizeof(ULONG_PTR
);
1405 const ULONG_PTR system_mask
= get_system_affinity_mask();
1407 SERVER_START_REQ(get_process_info
)
1409 req
->handle
= wine_server_obj_handle( handle
);
1410 if (!(ret
= wine_server_call( req
)))
1411 *(ULONG_PTR
*)info
= reply
->affinity
& system_mask
;
1415 else return STATUS_INFO_LENGTH_MISMATCH
;
1418 case ProcessSessionInformation
:
1419 len
= sizeof(DWORD
);
1422 SERVER_START_REQ(get_process_info
)
1424 req
->handle
= wine_server_obj_handle( handle
);
1425 if (!(ret
= wine_server_call( req
)))
1426 *(DWORD
*)info
= reply
->session_id
;
1430 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1433 case ProcessWow64Information
:
1434 len
= sizeof(ULONG_PTR
);
1435 if (size
!= len
) return STATUS_INFO_LENGTH_MISMATCH
;
1436 if (handle
== GetCurrentProcess())
1437 *(ULONG_PTR
*)info
= is_old_wow64() ? (ULONG_PTR
)peb
: (ULONG_PTR
)wow_peb
;
1442 SERVER_START_REQ( get_process_info
)
1444 req
->handle
= wine_server_obj_handle( handle
);
1445 ret
= wine_server_call( req
);
1446 if (!ret
&& !is_machine_64bit( reply
->machine
) && is_machine_64bit( native_machine
))
1447 val
= reply
->peb
+ 0x1000;
1450 if (!ret
) *(ULONG_PTR
*)info
= val
;
1454 case ProcessImageFileName
:
1455 /* FIXME: Should return a device path */
1456 case ProcessImageFileNameWin32
:
1457 SERVER_START_REQ( get_process_image_name
)
1459 UNICODE_STRING
*str
= info
;
1461 req
->handle
= wine_server_obj_handle( handle
);
1462 req
->win32
= (class == ProcessImageFileNameWin32
);
1463 wine_server_set_reply( req
, str
? str
+ 1 : NULL
,
1464 size
> sizeof(UNICODE_STRING
) ? size
- sizeof(UNICODE_STRING
) : 0 );
1465 ret
= wine_server_call( req
);
1466 if (ret
== STATUS_BUFFER_TOO_SMALL
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1467 len
= sizeof(UNICODE_STRING
) + reply
->len
;
1468 if (ret
== STATUS_SUCCESS
)
1470 str
->MaximumLength
= str
->Length
= reply
->len
;
1471 str
->Buffer
= (PWSTR
)(str
+ 1);
1477 case ProcessExecuteFlags
:
1478 len
= sizeof(ULONG
);
1480 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1481 else if (is_win64
&& !is_wow64())
1482 *(ULONG
*)info
= MEM_EXECUTE_OPTION_DISABLE
|
1483 MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION
|
1484 MEM_EXECUTE_OPTION_PERMANENT
;
1486 *(ULONG
*)info
= execute_flags
;
1489 case ProcessPriorityClass
:
1490 len
= sizeof(PROCESS_PRIORITY_CLASS
);
1493 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1496 PROCESS_PRIORITY_CLASS
*priority
= info
;
1498 SERVER_START_REQ(get_process_info
)
1500 req
->handle
= wine_server_obj_handle( handle
);
1501 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1503 priority
->PriorityClass
= reply
->priority
;
1504 /* FIXME: Not yet supported by the wineserver */
1505 priority
->Foreground
= FALSE
;
1511 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1515 FIXME( "ProcessCookie (%p,%p,0x%08x,%p) stub\n", handle
, info
, (int)size
, ret_len
);
1516 if (handle
== NtCurrentProcess())
1518 len
= sizeof(ULONG
);
1519 if (size
== len
) *(ULONG
*)info
= 0;
1520 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1522 else ret
= STATUS_INVALID_PARAMETER
;
1525 case ProcessImageInformation
:
1526 len
= sizeof(SECTION_IMAGE_INFORMATION
);
1531 pe_image_info_t pe_info
;
1533 SERVER_START_REQ( get_process_info
)
1535 req
->handle
= wine_server_obj_handle( handle
);
1536 wine_server_set_reply( req
, &pe_info
, sizeof(pe_info
) );
1537 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
1538 virtual_fill_image_information( &pe_info
, info
);
1542 else ret
= STATUS_ACCESS_VIOLATION
;
1544 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1547 case ProcessCycleTime
:
1548 len
= sizeof(PROCESS_CYCLE_TIME_INFORMATION
);
1551 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1554 PROCESS_CYCLE_TIME_INFORMATION cycles
;
1556 FIXME( "ProcessCycleTime (%p,%p,0x%08x,%p) stub\n", handle
, info
, (int)size
, ret_len
);
1557 cycles
.AccumulatedCycles
= 0;
1558 cycles
.CurrentCycleCount
= 0;
1560 memcpy(info
, &cycles
, sizeof(PROCESS_CYCLE_TIME_INFORMATION
));
1563 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1566 case ProcessWineLdtCopy
:
1567 if (handle
== NtCurrentProcess())
1570 len
= sizeof(struct ldt_copy
*);
1571 if (size
== len
) *(struct ldt_copy
**)info
= &__wine_ldt_copy
;
1572 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1574 ret
= STATUS_NOT_IMPLEMENTED
;
1577 else ret
= STATUS_INVALID_PARAMETER
;
1580 case ProcessQuotaLimits
:
1582 QUOTA_LIMITS qlimits
;
1584 FIXME( "ProcessQuotaLimits (%p,%p,0x%08x,%p) stub\n", handle
, info
, (int)size
, ret_len
);
1586 len
= sizeof(QUOTA_LIMITS
);
1589 if (!handle
) ret
= STATUS_INVALID_HANDLE
;
1592 /* FIXME: SetProcessWorkingSetSize can also set the quota values.
1593 Quota Limits should be stored inside the process. */
1594 qlimits
.PagedPoolLimit
= (SIZE_T
)-1;
1595 qlimits
.NonPagedPoolLimit
= (SIZE_T
)-1;
1596 /* Default minimum working set size is 204800 bytes (50 Pages) */
1597 qlimits
.MinimumWorkingSetSize
= 204800;
1598 /* Default maximum working set size is 1413120 bytes (345 Pages) */
1599 qlimits
.MaximumWorkingSetSize
= 1413120;
1600 qlimits
.PagefileLimit
= (SIZE_T
)-1;
1601 qlimits
.TimeLimit
.QuadPart
= -1;
1602 memcpy(info
, &qlimits
, len
);
1605 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1610 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
1611 handle
, class, info
, (int)size
, ret_len
);
1612 ret
= STATUS_INVALID_INFO_CLASS
;
1616 if (ret_len
) *ret_len
= len
;
1621 /**********************************************************************
1622 * NtSetInformationProcess (NTDLL.@)
1624 NTSTATUS WINAPI
NtSetInformationProcess( HANDLE handle
, PROCESSINFOCLASS
class, void *info
, ULONG size
)
1626 unsigned int ret
= STATUS_SUCCESS
;
1630 case ProcessAccessToken
:
1632 const PROCESS_ACCESS_TOKEN
*token
= info
;
1634 if (size
!= sizeof(PROCESS_ACCESS_TOKEN
)) return STATUS_INFO_LENGTH_MISMATCH
;
1636 SERVER_START_REQ( set_process_info
)
1638 req
->handle
= wine_server_obj_handle( handle
);
1639 req
->token
= wine_server_obj_handle( token
->Token
);
1640 req
->mask
= SET_PROCESS_INFO_TOKEN
;
1641 ret
= wine_server_call( req
);
1647 case ProcessDefaultHardErrorMode
:
1648 if (size
!= sizeof(UINT
)) return STATUS_INVALID_PARAMETER
;
1649 process_error_mode
= *(UINT
*)info
;
1652 case ProcessAffinityMask
:
1654 const ULONG_PTR system_mask
= get_system_affinity_mask();
1656 if (size
!= sizeof(DWORD_PTR
)) return STATUS_INVALID_PARAMETER
;
1657 if (*(PDWORD_PTR
)info
& ~system_mask
)
1658 return STATUS_INVALID_PARAMETER
;
1659 if (!*(PDWORD_PTR
)info
)
1660 return STATUS_INVALID_PARAMETER
;
1661 SERVER_START_REQ( set_process_info
)
1663 req
->handle
= wine_server_obj_handle( handle
);
1664 req
->affinity
= *(PDWORD_PTR
)info
;
1665 req
->mask
= SET_PROCESS_INFO_AFFINITY
;
1666 ret
= wine_server_call( req
);
1671 case ProcessPriorityClass
:
1672 if (size
!= sizeof(PROCESS_PRIORITY_CLASS
)) return STATUS_INVALID_PARAMETER
;
1675 PROCESS_PRIORITY_CLASS
* ppc
= info
;
1677 SERVER_START_REQ( set_process_info
)
1679 req
->handle
= wine_server_obj_handle( handle
);
1680 /* FIXME Foreground isn't used */
1681 req
->priority
= ppc
->PriorityClass
;
1682 req
->mask
= SET_PROCESS_INFO_PRIORITY
;
1683 ret
= wine_server_call( req
);
1689 case ProcessExecuteFlags
:
1690 if ((is_win64
&& !is_wow64()) || size
!= sizeof(ULONG
)) return STATUS_INVALID_PARAMETER
;
1691 if (execute_flags
& MEM_EXECUTE_OPTION_PERMANENT
) return STATUS_ACCESS_DENIED
;
1695 switch (*(ULONG
*)info
& (MEM_EXECUTE_OPTION_ENABLE
|MEM_EXECUTE_OPTION_DISABLE
))
1697 case MEM_EXECUTE_OPTION_ENABLE
:
1700 case MEM_EXECUTE_OPTION_DISABLE
:
1704 return STATUS_INVALID_PARAMETER
;
1706 execute_flags
= *(ULONG
*)info
;
1707 virtual_set_force_exec( enable
);
1711 case ProcessInstrumentationCallback
:
1713 PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION
*instr
= info
;
1715 FIXME( "ProcessInstrumentationCallback stub.\n" );
1717 if (size
< sizeof(*instr
)) return STATUS_INFO_LENGTH_MISMATCH
;
1718 ret
= STATUS_SUCCESS
;
1722 case ProcessThreadStackAllocation
:
1726 PROCESS_STACK_ALLOCATION_INFORMATION
*stack
= info
;
1727 if (size
== sizeof(PROCESS_STACK_ALLOCATION_INFORMATION_EX
))
1728 stack
= &((PROCESS_STACK_ALLOCATION_INFORMATION_EX
*)info
)->AllocInfo
;
1729 else if (size
!= sizeof(*stack
)) return STATUS_INFO_LENGTH_MISMATCH
;
1731 reserve
= stack
->ReserveSize
;
1732 ret
= NtAllocateVirtualMemory( GetCurrentProcess(), &addr
, stack
->ZeroBits
, &reserve
,
1733 MEM_RESERVE
, PAGE_READWRITE
);
1736 #ifdef VALGRIND_STACK_REGISTER
1737 VALGRIND_STACK_REGISTER( addr
, (char *)addr
+ reserve
);
1739 stack
->StackBase
= addr
;
1744 case ProcessWineMakeProcessSystem
:
1745 if (size
!= sizeof(HANDLE
*)) return STATUS_INFO_LENGTH_MISMATCH
;
1746 SERVER_START_REQ( make_process_system
)
1748 req
->handle
= wine_server_obj_handle( handle
);
1749 if (!(ret
= wine_server_call( req
)))
1750 *(HANDLE
*)info
= wine_server_ptr_handle( reply
->event
);
1756 FIXME( "(%p,0x%08x,%p,0x%08x) stub\n", handle
, class, info
, (int)size
);
1757 ret
= STATUS_NOT_IMPLEMENTED
;
1764 /**********************************************************************
1765 * NtOpenProcess (NTDLL.@)
1767 NTSTATUS WINAPI
NtOpenProcess( HANDLE
*handle
, ACCESS_MASK access
,
1768 const OBJECT_ATTRIBUTES
*attr
, const CLIENT_ID
*id
)
1770 unsigned int status
;
1774 SERVER_START_REQ( open_process
)
1776 req
->pid
= HandleToULong( id
->UniqueProcess
);
1777 req
->access
= access
;
1778 req
->attributes
= attr
? attr
->Attributes
: 0;
1779 status
= wine_server_call( req
);
1780 if (!status
) *handle
= wine_server_ptr_handle( reply
->handle
);
1787 /**********************************************************************
1788 * NtSuspendProcess (NTDLL.@)
1790 NTSTATUS WINAPI
NtSuspendProcess( HANDLE handle
)
1794 SERVER_START_REQ( suspend_process
)
1796 req
->handle
= wine_server_obj_handle( handle
);
1797 ret
= wine_server_call( req
);
1804 /**********************************************************************
1805 * NtResumeProcess (NTDLL.@)
1807 NTSTATUS WINAPI
NtResumeProcess( HANDLE handle
)
1811 SERVER_START_REQ( resume_process
)
1813 req
->handle
= wine_server_obj_handle( handle
);
1814 ret
= wine_server_call( req
);
1821 /**********************************************************************
1822 * NtDebugActiveProcess (NTDLL.@)
1824 NTSTATUS WINAPI
NtDebugActiveProcess( HANDLE process
, HANDLE debug
)
1828 SERVER_START_REQ( debug_process
)
1830 req
->handle
= wine_server_obj_handle( process
);
1831 req
->debug
= wine_server_obj_handle( debug
);
1833 ret
= wine_server_call( req
);
1840 /**********************************************************************
1841 * NtRemoveProcessDebug (NTDLL.@)
1843 NTSTATUS WINAPI
NtRemoveProcessDebug( HANDLE process
, HANDLE debug
)
1847 SERVER_START_REQ( debug_process
)
1849 req
->handle
= wine_server_obj_handle( process
);
1850 req
->debug
= wine_server_obj_handle( debug
);
1852 ret
= wine_server_call( req
);
1859 /**********************************************************************
1860 * NtDebugContinue (NTDLL.@)
1862 NTSTATUS WINAPI
NtDebugContinue( HANDLE handle
, CLIENT_ID
*client
, NTSTATUS status
)
1866 SERVER_START_REQ( continue_debug_event
)
1868 req
->debug
= wine_server_obj_handle( handle
);
1869 req
->pid
= HandleToULong( client
->UniqueProcess
);
1870 req
->tid
= HandleToULong( client
->UniqueThread
);
1871 req
->status
= status
;
1872 ret
= wine_server_call( req
);