include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / ntdll / unix / process.c
blob1815b46b0fc92d55bc59bd1de351d0901a2f1773
1 /*
2 * NT process handling
4 * Copyright 1996-1998 Marcus Meissner
5 * Copyright 2018, 2020 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #if 0
23 #pragma makedep unix
24 #endif
26 #include "config.h"
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <signal.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #ifdef HAVE_SYS_TIMES_H
39 # include <sys/times.h>
40 #endif
41 #include <sys/types.h>
42 #include <sys/wait.h>
43 #ifdef HAVE_SYS_SYSCTL_H
44 # include <sys/sysctl.h>
45 #endif
46 #ifdef HAVE_SYS_PARAM_H
47 # include <sys/param.h>
48 #endif
49 #ifdef HAVE_SYS_QUEUE_H
50 # include <sys/queue.h>
51 #endif
52 #ifdef HAVE_SYS_USER_H
53 # include <sys/user.h>
54 #endif
55 #ifdef HAVE_LIBPROCSTAT_H
56 # include <libprocstat.h>
57 #endif
58 #include <unistd.h>
59 #ifdef HAVE_MACH_MACH_H
60 # include <mach/mach.h>
61 #endif
63 #include "ntstatus.h"
64 #define WIN32_NO_STATUS
65 #include "windef.h"
66 #include "winternl.h"
67 #include "winioctl.h"
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 );
88 src[len++] = 0;
90 argc = reserved + 2 + len / 2;
91 argv = malloc( argc * sizeof(*argv) + len );
92 arg = dst = (char *)(argv + argc);
93 argc = reserved;
94 while (*src)
96 if ((*src == ' ' || *src == '\t') && !in_quotes)
98 /* skip the remaining spaces */
99 while (*src == ' ' || *src == '\t') src++;
100 if (!*src) break;
101 /* close the argument and copy it */
102 *dst++ = 0;
103 argv[argc++] = arg;
104 /* start with a new argument */
105 arg = dst;
106 bcount = 0;
108 else if (*src == '\\')
110 *dst++ = *src++;
111 bcount++;
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.
120 dst -= bcount / 2;
121 src++;
122 if (in_quotes && *src == '"') *dst++ = *src++;
123 else in_quotes = !in_quotes;
125 else
127 /* Preceded by an odd number of '\', this is half that
128 * number of '\' followed by a '"'
130 dst -= bcount / 2 + 1;
131 *dst++ = *src++;
133 bcount = 0;
135 else /* a regular character */
137 *dst++ = *src++;
138 bcount = 0;
141 *dst = 0;
142 argv[argc++] = arg;
143 argv[argc] = NULL;
144 return argv;
148 /***********************************************************************
149 * get_so_file_info
151 static BOOL get_so_file_info( int fd, pe_image_info_t *info )
153 union
155 struct
157 unsigned char magic[4];
158 unsigned char class;
159 unsigned char data;
160 unsigned char version;
161 unsigned char ignored1[9];
162 unsigned short type;
163 unsigned short machine;
164 unsigned char ignored2[8];
165 unsigned int phoff;
166 unsigned char ignored3[12];
167 unsigned short phnum;
168 } elf;
169 struct
171 unsigned char magic[4];
172 unsigned char class;
173 unsigned char data;
174 unsigned char ignored1[10];
175 unsigned short type;
176 unsigned short machine;
177 unsigned char ignored2[12];
178 unsigned __int64 phoff;
179 unsigned char ignored3[16];
180 unsigned short phnum;
181 } elf64;
182 struct
184 unsigned int magic;
185 unsigned int cputype;
186 unsigned int cpusubtype;
187 unsigned int filetype;
188 } macho;
189 IMAGE_DOS_HEADER mz;
190 } header;
192 off_t pos;
194 if (pread( fd, &header, sizeof(header), 0 ) != sizeof(header)) return FALSE;
196 if (!memcmp( header.elf.magic, "\177ELF", 4 ))
198 unsigned int type;
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;
204 #else
205 if (header.elf.data != 1 /* ELFDATA2LSB */) return FALSE;
206 #endif
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;
220 else
222 pos = header.elf.phoff;
223 phnum = header.elf.phnum;
225 while (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;
231 return TRUE;
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;
244 return FALSE;
248 /***********************************************************************
249 * get_pe_file_info
251 static unsigned int get_pe_file_info( OBJECT_ATTRIBUTES *attr, HANDLE *handle, pe_image_info_t *info )
253 unsigned int status;
254 HANDLE mapping;
255 char *unix_name;
257 *handle = 0;
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 );
264 free( unix_name );
266 if (status)
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;
273 return status;
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 );
287 SERVER_END_REQ;
288 NtClose( mapping );
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 );
301 return status;
305 /***********************************************************************
306 * get_env_size
308 static ULONG get_env_size( const RTL_USER_PROCESS_PARAMETERS *params, char **winedebug )
310 WCHAR *ptr = params->Environment;
312 while (*ptr)
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;
323 ptr++;
324 return (ptr - params->Environment) * sizeof(WCHAR);
328 /***********************************************************************
329 * get_nt_pathname
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;
338 WCHAR *ret;
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;
346 else
348 wcscat( ret, uncprefixW );
349 name += 2;
352 wcscat( ret, name );
353 return ret;
357 /***********************************************************************
358 * get_unix_curdir
360 static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params )
362 UNICODE_STRING nt_name, redir;
363 OBJECT_ATTRIBUTES attr;
364 NTSTATUS status;
365 HANDLE handle;
366 int fd = -1;
367 char *unix_name;
369 if (!(nt_name.Buffer = get_nt_pathname( &params->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 );
379 free( unix_name );
380 if (status) goto done;
381 wine_server_handle_to_fd( handle, FILE_TRAVERSE, &fd, NULL );
382 NtClose( handle );
384 done:
385 free( nt_name.Buffer );
386 free( redir.Buffer );
387 return fd;
391 /***********************************************************************
392 * set_stdio_fd
394 static void set_stdio_fd( int stdin_fd, int stdout_fd )
396 int fd = -1;
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 /***********************************************************************
421 * spawn_process
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;
428 pid_t pid;
429 char **argv;
431 if (wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL ) &&
432 isatty(0) && is_unix_console_handle( params->hStdInput ))
433 stdin_fd = 0;
435 if (wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ) &&
436 isatty(1) && is_unix_console_handle( params->hStdOutput ))
437 stdout_fd = 1;
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)
448 setsid();
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 );
457 if (unixdir != -1)
459 fchdir( unixdir );
460 close( unixdir );
462 argv = build_argv( &params->CommandLine, 2 );
464 exec_wineloader( argv, socketfd, pe_info );
465 _exit(1);
468 _exit(pid == -1);
471 if (pid != -1)
473 /* reap child */
474 pid_t wret;
475 do {
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 );
483 return status;
487 /***********************************************************************
488 * __wine_unix_spawnvp
490 NTSTATUS WINAPI __wine_unix_spawnvp( char * const argv[], int wait )
492 pid_t pid, wret;
493 int fd[2], status, err;
495 #ifdef HAVE_PIPE2
496 if (pipe2( fd, O_CLOEXEC ) == -1)
497 #endif
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 );
504 if (!(pid = fork()))
506 /* in child */
507 close( fd[0] );
508 signal( SIGPIPE, SIG_DFL );
509 if (!wait)
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) );
518 _exit(1);
520 close( fd[1] );
522 if (pid != -1)
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 );
535 close( fd[0] );
536 return err;
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 );
551 #ifdef _WIN64
552 /***********************************************************************
553 * wow64_wine_spawnvp
555 NTSTATUS wow64_wine_spawnvp( void *args )
557 struct
559 ULONG argv;
560 int wait;
561 } const *params32 = args;
563 ULONG *argv32 = ULongToPtr( params32->argv );
564 unsigned int i, count = 0;
565 char **argv;
566 NTSTATUS ret;
568 while (argv32[count]) count++;
569 argv = malloc( (count + 1) * sizeof(*argv) );
570 for (i = 0; i < count; i++) argv[i] = ULongToPtr( argv32[i] );
571 argv[count] = NULL;
572 ret = __wine_unix_spawnvp( argv, params32->wait );
573 free( argv );
574 return ret;
576 #endif
578 /***********************************************************************
579 * fork_and_exec
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 )
586 pid_t pid;
587 int fd[2], stdin_fd = -1, stdout_fd = -1;
588 char **argv, **envp;
589 char *unix_name;
590 NTSTATUS status;
592 status = nt_to_unix_file_name( attr, &unix_name, FILE_OPEN );
593 if (status) return status;
595 #ifdef HAVE_PIPE2
596 if (pipe2( fd, O_CLOEXEC ) == -1)
597 #endif
599 if (pipe(fd) == -1)
601 status = STATUS_TOO_MANY_OPENED_FILES;
602 goto done;
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 ))
610 stdin_fd = 0;
612 if (wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ) &&
613 isatty(1) && is_unix_console_handle( params->hStdOutput ))
614 stdout_fd = 1;
616 if (!(pid = fork())) /* child */
618 if (!(pid = fork())) /* grandchild */
620 close( fd[0] );
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)
627 setsid();
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( &params->CommandLine, 0 );
639 envp = build_envp( params->Environment );
640 if (unixdir != -1)
642 fchdir( unixdir );
643 close( unixdir );
645 execve( unix_name, argv, envp );
648 if (pid <= 0) /* grandchild if exec failed or child if fork failed */
650 switch (errno)
652 case EPERM:
653 case EACCES: status = STATUS_ACCESS_DENIED; break;
654 case ENOENT: status = STATUS_OBJECT_NAME_NOT_FOUND; break;
655 case EMFILE:
656 case ENFILE: status = STATUS_TOO_MANY_OPENED_FILES; break;
657 case ENOEXEC:
658 case EINVAL: status = STATUS_INVALID_IMAGE_FORMAT; break;
659 default: status = STATUS_NO_MEMORY; break;
661 write( fd[1], &status, sizeof(status) );
662 _exit(1);
664 _exit(0); /* child if fork succeeded */
666 close( fd[1] );
668 if (pid != -1)
670 /* reap child */
671 pid_t wret;
672 do {
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;
679 close( fd[0] );
680 if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd );
681 if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd );
682 done:
683 free( unix_name );
684 return status;
687 static NTSTATUS alloc_handle_list( const PS_ATTRIBUTE *handles_attr, obj_handle_t **handles, data_size_t *handles_len )
689 SIZE_T count, i;
690 HANDLE *src;
692 *handles = NULL;
693 *handles_len = 0;
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 )
720 unsigned int status;
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;
730 CLIENT_ID id;
731 USHORT machine = 0;
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;
756 break;
757 case PS_ATTRIBUTE_DEBUG_PORT:
758 debug = ps_attr->Attributes[i].ValuePtr;
759 break;
760 case PS_ATTRIBUTE_IMAGE_NAME:
761 path.Length = ps_attr->Attributes[i].Size;
762 path.Buffer = ps_attr->Attributes[i].ValuePtr;
763 break;
764 case PS_ATTRIBUTE_TOKEN:
765 token = ps_attr->Attributes[i].ValuePtr;
766 break;
767 case PS_ATTRIBUTE_HANDLE_LIST:
768 if (process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES)
769 handles_attr = &ps_attr->Attributes[i];
770 break;
771 case PS_ATTRIBUTE_JOB_LIST:
772 jobs_attr = &ps_attr->Attributes[i];
773 break;
774 case PS_ATTRIBUTE_MACHINE_TYPE:
775 machine = ps_attr->Attributes[i].Value;
776 break;
777 default:
778 if (ps_attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT)
779 FIXME( "unhandled input attribute %lx\n", ps_attr->Attributes[i].Attribute );
780 break;
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( &params->ImagePathName ), debugstr_us( &params->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;
801 goto done;
803 if (!machine)
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 )))
810 goto done;
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 )))
817 free( objattr );
818 goto done;
821 if ((status = alloc_handle_list( jobs_attr, &jobs, &jobs_size )))
823 free( objattr );
824 free( handles );
825 goto done;
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;
833 free( objattr );
834 free( handles );
835 free( jobs );
836 goto done;
838 #ifdef SO_PASSCRED
839 else
841 int enable = 1;
842 setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
844 #endif
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 );
874 SERVER_END_REQ;
875 close( socketfd[1] );
876 free( objattr );
877 free( handles );
878 free( jobs );
880 if (status)
882 switch (status)
884 case STATUS_INVALID_IMAGE_WIN_64:
885 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_us(&path) );
886 break;
887 case STATUS_INVALID_IMAGE_FORMAT:
888 ERR( "%s not supported on this installation (machine %04x)\n",
889 debugstr_us(&path), pe_info.machine );
890 break;
892 goto done;
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 );
910 SERVER_END_REQ;
911 free( objattr );
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] );
919 socketfd[0] = -1;
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;
931 SERVER_END_REQ;
933 if (!success)
935 if (!status) status = STATUS_INTERNAL_ERROR;
936 goto done;
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;
954 break;
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;
963 break;
965 case PS_ATTRIBUTE_TEB_ADDRESS:
966 default:
967 if (!(ps_attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT))
968 FIXME( "unhandled output attribute %lx\n", ps_attr->Attributes[i].Attribute );
969 break;
972 *process_handle_ptr = process_handle;
973 *thread_handle_ptr = thread_handle;
974 process_handle = thread_handle = 0;
975 status = STATUS_SUCCESS;
977 done:
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 );
985 free( winedebug );
986 free( redir.Buffer );
987 return status;
991 /******************************************************************************
992 * NtTerminateProcess (NTDLL.@)
994 NTSTATUS WINAPI NtTerminateProcess( HANDLE handle, LONG exit_code )
996 unsigned int ret;
997 BOOL self;
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 );
1004 self = reply->self;
1006 SERVER_END_REQ;
1007 if (self)
1009 if (!handle) process_exiting = TRUE;
1010 else if (process_exiting) exit_process( exit_code );
1011 else abort_process( exit_code );
1013 return ret;
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;
1035 #endif
1038 #elif defined(linux)
1040 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1042 FILE *f;
1043 char line[256], path[26];
1044 unsigned long value;
1046 if (unix_pid == -1)
1047 strcpy( path, "/proc/self/status" );
1048 else
1049 snprintf( path, sizeof(path), "/proc/%u/status", unix_pid);
1050 f = fopen( path, "r" );
1051 if (!f) return;
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;
1070 fclose(f);
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();
1082 if (pstat)
1084 kip = procstat_getprocs( pstat, KERN_PROC_PID, unix_pid == -1 ? getpid() : unix_pid, &proc_count );
1085 if (kip)
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 );
1097 #else
1099 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1101 /* FIXME : real data */
1104 #endif
1106 #define UNIMPLEMENTED_INFO_CLASS(c) \
1107 case c: \
1108 FIXME( "(process=%p) Unimplemented information class: " #c "\n", handle); \
1109 ret = STATUS_INVALID_INFO_CLASS; \
1110 break
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;
1119 ULONG len = 0;
1121 TRACE( "(%p,0x%08x,%p,0x%08x,%p)\n", handle, class, info, (int)size, ret_len );
1123 switch (class)
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;
1152 else
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;
1165 if (is_old_wow64())
1167 if (reply->machine != native_machine)
1168 pbi.PebBaseAddress = (PEB *)((char *)pbi.PebBaseAddress + 0x1000);
1169 else
1170 pbi.PebBaseAddress = NULL;
1174 SERVER_END_REQ;
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;
1181 else
1183 len = sizeof(PROCESS_BASIC_INFORMATION);
1184 ret = STATUS_INFO_LENGTH_MISMATCH;
1187 break;
1189 case ProcessIoCounters:
1191 IO_COUNTERS pii;
1193 if (size >= sizeof(IO_COUNTERS))
1195 if (!info) ret = STATUS_ACCESS_VIOLATION;
1196 else if (!handle) ret = STATUS_INVALID_HANDLE;
1197 else
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;
1206 else
1208 len = sizeof(IO_COUNTERS);
1209 ret = STATUS_INFO_LENGTH_MISMATCH;
1212 break;
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;
1222 else
1224 memset(&pvmi, 0, sizeof(pvmi));
1225 if (handle == GetCurrentProcess()) fill_vm_counters( &pvmi, -1 );
1226 else
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;
1241 SERVER_END_REQ;
1242 if (ret) break;
1244 if (size >= sizeof(VM_COUNTERS_EX))
1245 pvmi.PrivateUsage = pvmi.PagefileUsage;
1246 len = size;
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;
1253 else
1255 len = sizeof(pvmi);
1256 ret = STATUS_INFO_LENGTH_MISMATCH;
1259 break;
1261 case ProcessTimes:
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;
1269 else
1271 long ticks = sysconf(_SC_CLK_TCK);
1272 struct tms tms;
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;
1290 SERVER_END_REQ;
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;
1297 else
1299 len = sizeof(KERNEL_USER_TIMES);
1300 ret = STATUS_INFO_LENGTH_MISMATCH;
1303 break;
1305 case ProcessDebugPort:
1306 len = sizeof(DWORD_PTR);
1307 if (size != len) return STATUS_INFO_LENGTH_MISMATCH;
1308 if (!info) ret = STATUS_ACCESS_VIOLATION;
1309 else
1311 HANDLE debug;
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 );
1319 SERVER_END_REQ;
1320 if (ret == STATUS_SUCCESS)
1322 *(DWORD_PTR *)info = ~0ul;
1323 NtClose( debug );
1325 else if (ret == STATUS_PORT_NOT_SET)
1327 *(DWORD_PTR *)info = 0;
1328 ret = STATUS_SUCCESS;
1330 else return ret;
1332 break;
1334 case ProcessDebugFlags:
1335 len = sizeof(DWORD);
1336 if (size == len)
1338 if (!info) ret = STATUS_ACCESS_VIOLATION;
1339 else
1341 HANDLE debug;
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;
1350 SERVER_END_REQ;
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;
1356 break;
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;
1362 break;
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 );
1373 SERVER_END_REQ;
1374 break;
1376 case ProcessHandleCount:
1377 if (size >= 4)
1379 if (!info) ret = STATUS_ACCESS_VIOLATION;
1380 else if (!handle) ret = STATUS_INVALID_HANDLE;
1381 else
1383 FIXME( "ProcessHandleCount (%p,%p,0x%08x,%p) stub\n", handle, info, (int)size, ret_len );
1384 memset(info, 0, 4);
1385 len = 4;
1387 if (size > 4) ret = STATUS_INFO_LENGTH_MISMATCH;
1389 else
1391 len = 4;
1392 ret = STATUS_INFO_LENGTH_MISMATCH;
1394 break;
1396 case ProcessHandleTable:
1397 FIXME( "ProcessHandleTable (%p,%p,0x%08x,%p) stub\n", handle, info, (int)size, ret_len );
1398 len = 0;
1399 break;
1401 case ProcessAffinityMask:
1402 len = sizeof(ULONG_PTR);
1403 if (size == len)
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;
1413 SERVER_END_REQ;
1415 else return STATUS_INFO_LENGTH_MISMATCH;
1416 break;
1418 case ProcessSessionInformation:
1419 len = sizeof(DWORD);
1420 if (size == len)
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;
1428 SERVER_END_REQ;
1430 else ret = STATUS_INFO_LENGTH_MISMATCH;
1431 break;
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;
1438 else
1440 ULONG_PTR val = 0;
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;
1449 SERVER_END_REQ;
1450 if (!ret) *(ULONG_PTR *)info = val;
1452 break;
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);
1474 SERVER_END_REQ;
1475 break;
1477 case ProcessExecuteFlags:
1478 len = sizeof(ULONG);
1479 if (size != len)
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;
1485 else
1486 *(ULONG *)info = execute_flags;
1487 break;
1489 case ProcessPriorityClass:
1490 len = sizeof(PROCESS_PRIORITY_CLASS);
1491 if (size == len)
1493 if (!info) ret = STATUS_ACCESS_VIOLATION;
1494 else
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;
1508 SERVER_END_REQ;
1511 else ret = STATUS_INFO_LENGTH_MISMATCH;
1512 break;
1514 case ProcessCookie:
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;
1523 break;
1525 case ProcessImageInformation:
1526 len = sizeof(SECTION_IMAGE_INFORMATION);
1527 if (size == len)
1529 if (info)
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 );
1540 SERVER_END_REQ;
1542 else ret = STATUS_ACCESS_VIOLATION;
1544 else ret = STATUS_INFO_LENGTH_MISMATCH;
1545 break;
1547 case ProcessCycleTime:
1548 len = sizeof(PROCESS_CYCLE_TIME_INFORMATION);
1549 if (size == len)
1551 if (!info) ret = STATUS_ACCESS_VIOLATION;
1552 else
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;
1564 break;
1566 case ProcessWineLdtCopy:
1567 if (handle == NtCurrentProcess())
1569 #ifdef __i386__
1570 len = sizeof(struct ldt_copy *);
1571 if (size == len) *(struct ldt_copy **)info = &__wine_ldt_copy;
1572 else ret = STATUS_INFO_LENGTH_MISMATCH;
1573 #else
1574 ret = STATUS_NOT_IMPLEMENTED;
1575 #endif
1577 else ret = STATUS_INVALID_PARAMETER;
1578 break;
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);
1587 if (size == len)
1589 if (!handle) ret = STATUS_INVALID_HANDLE;
1590 else
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;
1606 break;
1609 default:
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;
1613 break;
1616 if (ret_len) *ret_len = len;
1617 return ret;
1621 /**********************************************************************
1622 * NtSetInformationProcess (NTDLL.@)
1624 NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class, void *info, ULONG size )
1626 unsigned int ret = STATUS_SUCCESS;
1628 switch (class)
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 );
1643 SERVER_END_REQ;
1644 break;
1647 case ProcessDefaultHardErrorMode:
1648 if (size != sizeof(UINT)) return STATUS_INVALID_PARAMETER;
1649 process_error_mode = *(UINT *)info;
1650 break;
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 );
1668 SERVER_END_REQ;
1669 break;
1671 case ProcessPriorityClass:
1672 if (size != sizeof(PROCESS_PRIORITY_CLASS)) return STATUS_INVALID_PARAMETER;
1673 else
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 );
1685 SERVER_END_REQ;
1687 break;
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;
1692 else
1694 BOOL enable;
1695 switch (*(ULONG *)info & (MEM_EXECUTE_OPTION_ENABLE|MEM_EXECUTE_OPTION_DISABLE))
1697 case MEM_EXECUTE_OPTION_ENABLE:
1698 enable = TRUE;
1699 break;
1700 case MEM_EXECUTE_OPTION_DISABLE:
1701 enable = FALSE;
1702 break;
1703 default:
1704 return STATUS_INVALID_PARAMETER;
1706 execute_flags = *(ULONG *)info;
1707 virtual_set_force_exec( enable );
1709 break;
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;
1719 break;
1722 case ProcessThreadStackAllocation:
1724 void *addr = NULL;
1725 SIZE_T reserve;
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 );
1734 if (!ret)
1736 #ifdef VALGRIND_STACK_REGISTER
1737 VALGRIND_STACK_REGISTER( addr, (char *)addr + reserve );
1738 #endif
1739 stack->StackBase = addr;
1741 break;
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 );
1752 SERVER_END_REQ;
1753 return ret;
1755 default:
1756 FIXME( "(%p,0x%08x,%p,0x%08x) stub\n", handle, class, info, (int)size );
1757 ret = STATUS_NOT_IMPLEMENTED;
1758 break;
1760 return ret;
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;
1772 *handle = 0;
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 );
1782 SERVER_END_REQ;
1783 return status;
1787 /**********************************************************************
1788 * NtSuspendProcess (NTDLL.@)
1790 NTSTATUS WINAPI NtSuspendProcess( HANDLE handle )
1792 unsigned int ret;
1794 SERVER_START_REQ( suspend_process )
1796 req->handle = wine_server_obj_handle( handle );
1797 ret = wine_server_call( req );
1799 SERVER_END_REQ;
1800 return ret;
1804 /**********************************************************************
1805 * NtResumeProcess (NTDLL.@)
1807 NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
1809 unsigned int ret;
1811 SERVER_START_REQ( resume_process )
1813 req->handle = wine_server_obj_handle( handle );
1814 ret = wine_server_call( req );
1816 SERVER_END_REQ;
1817 return ret;
1821 /**********************************************************************
1822 * NtDebugActiveProcess (NTDLL.@)
1824 NTSTATUS WINAPI NtDebugActiveProcess( HANDLE process, HANDLE debug )
1826 unsigned int ret;
1828 SERVER_START_REQ( debug_process )
1830 req->handle = wine_server_obj_handle( process );
1831 req->debug = wine_server_obj_handle( debug );
1832 req->attach = 1;
1833 ret = wine_server_call( req );
1835 SERVER_END_REQ;
1836 return ret;
1840 /**********************************************************************
1841 * NtRemoveProcessDebug (NTDLL.@)
1843 NTSTATUS WINAPI NtRemoveProcessDebug( HANDLE process, HANDLE debug )
1845 unsigned int ret;
1847 SERVER_START_REQ( debug_process )
1849 req->handle = wine_server_obj_handle( process );
1850 req->debug = wine_server_obj_handle( debug );
1851 req->attach = 0;
1852 ret = wine_server_call( req );
1854 SERVER_END_REQ;
1855 return ret;
1859 /**********************************************************************
1860 * NtDebugContinue (NTDLL.@)
1862 NTSTATUS WINAPI NtDebugContinue( HANDLE handle, CLIENT_ID *client, NTSTATUS status )
1864 unsigned int ret;
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 );
1874 SERVER_END_REQ;
1875 return ret;