iphlpapi: Add GetPerTcpConnectionEStats stub.
[wine.git] / dlls / ntdll / unix / process.c
blobfa8022d9968ca184c5261510079cf0484c14d2be
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 "unix_private.h"
69 #include "wine/condrv.h"
70 #include "wine/server.h"
71 #include "wine/debug.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(process);
76 static ULONG execute_flags = MEM_EXECUTE_OPTION_DISABLE;
78 static UINT process_error_mode;
80 static char **build_argv( const UNICODE_STRING *cmdline, int reserved )
82 char **argv, *arg, *src, *dst;
83 int argc, in_quotes = 0, bcount = 0, len = cmdline->Length / sizeof(WCHAR);
85 if (!(src = malloc( len * 3 + 1 ))) return NULL;
86 len = ntdll_wcstoumbs( cmdline->Buffer, len, src, len * 3, FALSE );
87 src[len++] = 0;
89 argc = reserved + 2 + len / 2;
90 argv = malloc( argc * sizeof(*argv) + len );
91 arg = dst = (char *)(argv + argc);
92 argc = reserved;
93 while (*src)
95 if ((*src == ' ' || *src == '\t') && !in_quotes)
97 /* skip the remaining spaces */
98 while (*src == ' ' || *src == '\t') src++;
99 if (!*src) break;
100 /* close the argument and copy it */
101 *dst++ = 0;
102 argv[argc++] = arg;
103 /* start with a new argument */
104 arg = dst;
105 bcount = 0;
107 else if (*src == '\\')
109 *dst++ = *src++;
110 bcount++;
112 else if (*src == '"')
114 if ((bcount & 1) == 0)
116 /* Preceded by an even number of '\', this is half that
117 * number of '\', plus a '"' which we discard.
119 dst -= bcount / 2;
120 src++;
121 if (in_quotes && *src == '"') *dst++ = *src++;
122 else in_quotes = !in_quotes;
124 else
126 /* Preceded by an odd number of '\', this is half that
127 * number of '\' followed by a '"'
129 dst -= bcount / 2 + 1;
130 *dst++ = *src++;
132 bcount = 0;
134 else /* a regular character */
136 *dst++ = *src++;
137 bcount = 0;
140 *dst = 0;
141 argv[argc++] = arg;
142 argv[argc] = NULL;
143 return argv;
147 /***********************************************************************
148 * get_so_file_info
150 static BOOL get_so_file_info( int fd, pe_image_info_t *info )
152 union
154 struct
156 unsigned char magic[4];
157 unsigned char class;
158 unsigned char data;
159 unsigned char version;
160 unsigned char ignored1[9];
161 unsigned short type;
162 unsigned short machine;
163 unsigned char ignored2[8];
164 unsigned int phoff;
165 unsigned char ignored3[12];
166 unsigned short phnum;
167 } elf;
168 struct
170 unsigned char magic[4];
171 unsigned char class;
172 unsigned char data;
173 unsigned char ignored1[10];
174 unsigned short type;
175 unsigned short machine;
176 unsigned char ignored2[12];
177 unsigned __int64 phoff;
178 unsigned char ignored3[16];
179 unsigned short phnum;
180 } elf64;
181 struct
183 unsigned int magic;
184 unsigned int cputype;
185 unsigned int cpusubtype;
186 unsigned int filetype;
187 } macho;
188 IMAGE_DOS_HEADER mz;
189 } header;
191 off_t pos;
193 if (pread( fd, &header, sizeof(header), 0 ) != sizeof(header)) return FALSE;
195 if (!memcmp( header.elf.magic, "\177ELF", 4 ))
197 unsigned int type;
198 unsigned short phnum;
200 if (header.elf.version != 1 /* EV_CURRENT */) return FALSE;
201 #ifdef WORDS_BIGENDIAN
202 if (header.elf.data != 2 /* ELFDATA2MSB */) return FALSE;
203 #else
204 if (header.elf.data != 1 /* ELFDATA2LSB */) return FALSE;
205 #endif
206 switch (header.elf.machine)
208 case 3: info->machine = IMAGE_FILE_MACHINE_I386; break;
209 case 40: info->machine = IMAGE_FILE_MACHINE_ARMNT; break;
210 case 62: info->machine = IMAGE_FILE_MACHINE_AMD64; break;
211 case 183: info->machine = IMAGE_FILE_MACHINE_ARM64; break;
213 if (header.elf.type != 3 /* ET_DYN */) return FALSE;
214 if (header.elf.class == 2 /* ELFCLASS64 */)
216 pos = header.elf64.phoff;
217 phnum = header.elf64.phnum;
219 else
221 pos = header.elf.phoff;
222 phnum = header.elf.phnum;
224 while (phnum--)
226 if (pread( fd, &type, sizeof(type), pos ) != sizeof(type)) return FALSE;
227 if (type == 3 /* PT_INTERP */) return FALSE;
228 pos += (header.elf.class == 2) ? 56 : 32;
230 return TRUE;
232 else if (header.macho.magic == 0xfeedface || header.macho.magic == 0xfeedfacf)
234 switch (header.macho.cputype)
236 case 0x00000007: info->machine = IMAGE_FILE_MACHINE_I386; break;
237 case 0x01000007: info->machine = IMAGE_FILE_MACHINE_AMD64; break;
238 case 0x0000000c: info->machine = IMAGE_FILE_MACHINE_ARMNT; break;
239 case 0x0100000c: info->machine = IMAGE_FILE_MACHINE_ARM64; break;
241 if (header.macho.filetype == 8) return TRUE;
243 return FALSE;
247 /***********************************************************************
248 * get_pe_file_info
250 static unsigned int get_pe_file_info( OBJECT_ATTRIBUTES *attr, HANDLE *handle, pe_image_info_t *info )
252 unsigned int status;
253 HANDLE mapping;
254 char *unix_name;
256 *handle = 0;
257 memset( info, 0, sizeof(*info) );
258 if (!(status = nt_to_unix_file_name( attr, &unix_name, FILE_OPEN )))
260 status = open_unix_file( handle, unix_name, GENERIC_READ, attr, 0,
261 FILE_SHARE_READ | FILE_SHARE_DELETE,
262 FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
263 free( unix_name );
265 if (status)
267 if (is_builtin_path( attr->ObjectName, &info->machine ))
269 TRACE( "assuming %04x builtin for %s\n", info->machine, debugstr_us(attr->ObjectName));
270 return STATUS_SUCCESS;
272 return status;
275 if (!(status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
276 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
277 NULL, NULL, PAGE_EXECUTE_READ, SEC_IMAGE, *handle )))
279 SERVER_START_REQ( get_mapping_info )
281 req->handle = wine_server_obj_handle( mapping );
282 req->access = SECTION_QUERY;
283 wine_server_set_reply( req, info, sizeof(*info) );
284 status = wine_server_call( req );
286 SERVER_END_REQ;
287 NtClose( mapping );
288 if (info->image_charact & IMAGE_FILE_DLL) return STATUS_INVALID_IMAGE_FORMAT;
290 else if (status == STATUS_INVALID_IMAGE_NOT_MZ)
292 int unix_fd, needs_close;
294 if (!server_get_unix_fd( *handle, FILE_READ_DATA, &unix_fd, &needs_close, NULL, NULL ))
296 if (get_so_file_info( unix_fd, info )) status = STATUS_SUCCESS;
297 if (needs_close) close( unix_fd );
300 return status;
304 /***********************************************************************
305 * get_env_size
307 static ULONG get_env_size( const RTL_USER_PROCESS_PARAMETERS *params, char **winedebug )
309 WCHAR *ptr = params->Environment;
311 while (*ptr)
313 static const WCHAR WINEDEBUG[] = {'W','I','N','E','D','E','B','U','G','=',0};
314 if (!*winedebug && !wcsncmp( ptr, WINEDEBUG, ARRAY_SIZE( WINEDEBUG ) - 1 ))
316 DWORD len = wcslen(ptr) * 3 + 1;
317 if ((*winedebug = malloc( len )))
318 ntdll_wcstoumbs( ptr, wcslen(ptr) + 1, *winedebug, len, FALSE );
320 ptr += wcslen(ptr) + 1;
322 ptr++;
323 return (ptr - params->Environment) * sizeof(WCHAR);
327 /***********************************************************************
328 * get_nt_pathname
330 * Simplified version of RtlDosPathNameToNtPathName_U.
332 static WCHAR *get_nt_pathname( const UNICODE_STRING *str )
334 static const WCHAR ntprefixW[] = {'\\','?','?','\\',0};
335 static const WCHAR uncprefixW[] = {'U','N','C','\\',0};
336 const WCHAR *name = str->Buffer;
337 WCHAR *ret;
339 if (!(ret = malloc( str->Length + 8 * sizeof(WCHAR) ))) return NULL;
341 wcscpy( ret, ntprefixW );
342 if (name[0] == '\\' && name[1] == '\\')
344 if ((name[2] == '.' || name[2] == '?') && name[3] == '\\') name += 4;
345 else
347 wcscat( ret, uncprefixW );
348 name += 2;
351 wcscat( ret, name );
352 return ret;
356 /***********************************************************************
357 * get_unix_curdir
359 static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params )
361 UNICODE_STRING nt_name, redir;
362 OBJECT_ATTRIBUTES attr;
363 NTSTATUS status;
364 HANDLE handle;
365 int fd = -1;
366 char *unix_name;
368 if (!(nt_name.Buffer = get_nt_pathname( &params->CurrentDirectory.DosPath ))) return -1;
369 nt_name.Length = wcslen( nt_name.Buffer ) * sizeof(WCHAR);
371 InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
372 get_redirect( &attr, &redir );
373 status = nt_to_unix_file_name( &attr, &unix_name, FILE_OPEN );
374 if (status) goto done;
375 status = open_unix_file( &handle, unix_name, FILE_TRAVERSE | SYNCHRONIZE, &attr, 0,
376 FILE_SHARE_READ | FILE_SHARE_DELETE,
377 FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
378 free( unix_name );
379 if (status) goto done;
380 wine_server_handle_to_fd( handle, FILE_TRAVERSE, &fd, NULL );
381 NtClose( handle );
383 done:
384 free( nt_name.Buffer );
385 free( redir.Buffer );
386 return fd;
390 /***********************************************************************
391 * set_stdio_fd
393 static void set_stdio_fd( int stdin_fd, int stdout_fd )
395 int fd = -1;
397 if (stdin_fd == -1 || stdout_fd == -1)
399 fd = open( "/dev/null", O_RDWR );
400 if (stdin_fd == -1) stdin_fd = fd;
401 if (stdout_fd == -1) stdout_fd = fd;
404 if (stdin_fd != 0) dup2( stdin_fd, 0 );
405 if (stdout_fd != 1) dup2( stdout_fd, 1 );
406 if (fd != -1) close( fd );
410 /***********************************************************************
411 * is_unix_console_handle
413 static BOOL is_unix_console_handle( HANDLE handle )
415 IO_STATUS_BLOCK io = {{0}};
416 return !NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io, IOCTL_CONDRV_IS_UNIX,
417 NULL, 0, NULL, 0 );
421 /***********************************************************************
422 * spawn_process
424 static NTSTATUS spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd,
425 int unixdir, char *winedebug, const pe_image_info_t *pe_info )
427 NTSTATUS status = STATUS_SUCCESS;
428 int stdin_fd = -1, stdout_fd = -1;
429 pid_t pid;
430 char **argv;
432 if (wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL ) &&
433 isatty(0) && is_unix_console_handle( params->hStdInput ))
434 stdin_fd = 0;
436 if (wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ) &&
437 isatty(1) && is_unix_console_handle( params->hStdOutput ))
438 stdout_fd = 1;
440 if (!(pid = fork())) /* child */
442 if (!(pid = fork())) /* grandchild */
444 if (params->ConsoleFlags ||
445 params->ConsoleHandle == CONSOLE_HANDLE_ALLOC ||
446 params->ConsoleHandle == CONSOLE_HANDLE_ALLOC_NO_WINDOW ||
447 (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
449 setsid();
450 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
452 else set_stdio_fd( stdin_fd, stdout_fd );
454 if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd );
455 if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd );
457 if (winedebug) putenv( winedebug );
458 if (unixdir != -1)
460 fchdir( unixdir );
461 close( unixdir );
463 argv = build_argv( &params->CommandLine, 2 );
465 exec_wineloader( argv, socketfd, pe_info );
466 _exit(1);
469 _exit(pid == -1);
472 if (pid != -1)
474 /* reap child */
475 pid_t wret;
476 do {
477 wret = waitpid(pid, NULL, 0);
478 } while (wret < 0 && errno == EINTR);
480 else status = STATUS_NO_MEMORY;
482 if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd );
483 if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd );
484 return status;
488 /***********************************************************************
489 * __wine_unix_spawnvp
491 NTSTATUS WINAPI __wine_unix_spawnvp( char * const argv[], int wait )
493 pid_t pid, wret;
494 int fd[2], status, err;
496 #ifdef HAVE_PIPE2
497 if (pipe2( fd, O_CLOEXEC ) == -1)
498 #endif
500 if (pipe(fd) == -1) return STATUS_TOO_MANY_OPENED_FILES;
501 fcntl( fd[0], F_SETFD, FD_CLOEXEC );
502 fcntl( fd[1], F_SETFD, FD_CLOEXEC );
505 if (!(pid = fork()))
507 /* in child */
508 close( fd[0] );
509 signal( SIGPIPE, SIG_DFL );
510 if (!wait)
512 if (!(pid = fork())) execvp( argv[0], argv ); /* in grandchild */
513 if (pid > 0) _exit(0); /* exit child if fork succeeded */
515 else execvp( argv[0], argv );
517 err = errno_to_status( errno );
518 write( fd[1], &err, sizeof(err) );
519 _exit(1);
521 close( fd[1] );
523 if (pid != -1)
525 while (pid != (wret = waitpid( pid, &status, 0 )))
526 if (wret == -1 && errno != EINTR) break;
528 if (read( fd[0], &err, sizeof(err) ) <= 0) /* if we read something, exec or second fork failed */
530 if (pid == wret && WIFEXITED(status)) err = WEXITSTATUS(status);
531 else err = 255; /* abnormal exit with an abort or an interrupt */
534 else err = errno_to_status( errno );
536 close( fd[0] );
537 return err;
541 /***********************************************************************
542 * unixcall_wine_spawnvp
544 NTSTATUS unixcall_wine_spawnvp( void *args )
546 struct wine_spawnvp_params *params = args;
548 return __wine_unix_spawnvp( params->argv, params->wait );
552 #ifdef _WIN64
553 /***********************************************************************
554 * wow64_wine_spawnvp
556 NTSTATUS wow64_wine_spawnvp( void *args )
558 struct
560 ULONG argv;
561 int wait;
562 } const *params32 = args;
564 ULONG *argv32 = ULongToPtr( params32->argv );
565 unsigned int i, count = 0;
566 char **argv;
567 NTSTATUS ret;
569 while (argv32[count]) count++;
570 argv = malloc( (count + 1) * sizeof(*argv) );
571 for (i = 0; i < count; i++) argv[i] = ULongToPtr( argv32[i] );
572 argv[count] = NULL;
573 ret = __wine_unix_spawnvp( argv, params32->wait );
574 free( argv );
575 return ret;
577 #endif
579 /***********************************************************************
580 * fork_and_exec
582 * Fork and exec a new Unix binary, checking for errors.
584 static NTSTATUS fork_and_exec( OBJECT_ATTRIBUTES *attr, int unixdir,
585 const RTL_USER_PROCESS_PARAMETERS *params )
587 pid_t pid;
588 int fd[2], stdin_fd = -1, stdout_fd = -1;
589 char **argv, **envp;
590 char *unix_name;
591 NTSTATUS status;
593 status = nt_to_unix_file_name( attr, &unix_name, FILE_OPEN );
594 if (status) return status;
596 #ifdef HAVE_PIPE2
597 if (pipe2( fd, O_CLOEXEC ) == -1)
598 #endif
600 if (pipe(fd) == -1)
602 status = STATUS_TOO_MANY_OPENED_FILES;
603 goto done;
605 fcntl( fd[0], F_SETFD, FD_CLOEXEC );
606 fcntl( fd[1], F_SETFD, FD_CLOEXEC );
609 if (wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL ) &&
610 isatty(0) && is_unix_console_handle( params->hStdInput ))
611 stdin_fd = 0;
613 if (wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ) &&
614 isatty(1) && is_unix_console_handle( params->hStdOutput ))
615 stdout_fd = 1;
617 if (!(pid = fork())) /* child */
619 if (!(pid = fork())) /* grandchild */
621 close( fd[0] );
623 if (params->ConsoleFlags ||
624 params->ConsoleHandle == CONSOLE_HANDLE_ALLOC ||
625 params->ConsoleHandle == CONSOLE_HANDLE_ALLOC_NO_WINDOW ||
626 (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
628 setsid();
629 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
631 else set_stdio_fd( stdin_fd, stdout_fd );
633 if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd );
634 if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd );
636 /* Reset signals that we previously set to SIG_IGN */
637 signal( SIGPIPE, SIG_DFL );
639 argv = build_argv( &params->CommandLine, 0 );
640 envp = build_envp( params->Environment );
641 if (unixdir != -1)
643 fchdir( unixdir );
644 close( unixdir );
646 execve( unix_name, argv, envp );
649 if (pid <= 0) /* grandchild if exec failed or child if fork failed */
651 switch (errno)
653 case EPERM:
654 case EACCES: status = STATUS_ACCESS_DENIED; break;
655 case ENOENT: status = STATUS_OBJECT_NAME_NOT_FOUND; break;
656 case EMFILE:
657 case ENFILE: status = STATUS_TOO_MANY_OPENED_FILES; break;
658 case ENOEXEC:
659 case EINVAL: status = STATUS_INVALID_IMAGE_FORMAT; break;
660 default: status = STATUS_NO_MEMORY; break;
662 write( fd[1], &status, sizeof(status) );
663 _exit(1);
665 _exit(0); /* child if fork succeeded */
667 close( fd[1] );
669 if (pid != -1)
671 /* reap child */
672 pid_t wret;
673 do {
674 wret = waitpid(pid, NULL, 0);
675 } while (wret < 0 && errno == EINTR);
676 read( fd[0], &status, sizeof(status) ); /* if we read something, exec or second fork failed */
678 else status = STATUS_NO_MEMORY;
680 close( fd[0] );
681 if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd );
682 if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd );
683 done:
684 free( unix_name );
685 return status;
688 static NTSTATUS alloc_handle_list( const PS_ATTRIBUTE *handles_attr, obj_handle_t **handles, data_size_t *handles_len )
690 SIZE_T count, i;
691 HANDLE *src;
693 *handles = NULL;
694 *handles_len = 0;
696 if (!handles_attr) return STATUS_SUCCESS;
698 count = handles_attr->Size / sizeof(HANDLE);
700 if (!(*handles = calloc( sizeof(**handles), count ))) return STATUS_NO_MEMORY;
702 src = handles_attr->ValuePtr;
703 for (i = 0; i < count; ++i)
704 (*handles)[i] = wine_server_obj_handle( src[i] );
706 *handles_len = count * sizeof(**handles);
708 return STATUS_SUCCESS;
711 /**********************************************************************
712 * NtCreateUserProcess (NTDLL.@)
714 NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_handle_ptr,
715 ACCESS_MASK process_access, ACCESS_MASK thread_access,
716 OBJECT_ATTRIBUTES *process_attr, OBJECT_ATTRIBUTES *thread_attr,
717 ULONG process_flags, ULONG thread_flags,
718 RTL_USER_PROCESS_PARAMETERS *params, PS_CREATE_INFO *info,
719 PS_ATTRIBUTE_LIST *ps_attr )
721 unsigned int status;
722 BOOL success = FALSE;
723 HANDLE file_handle, process_info = 0, process_handle = 0, thread_handle = 0;
724 struct object_attributes *objattr;
725 data_size_t attr_len;
726 char *winedebug = NULL;
727 startup_info_t *startup_info = NULL;
728 ULONG startup_info_size, env_size;
729 int unixdir, socketfd[2] = { -1, -1 };
730 pe_image_info_t pe_info;
731 CLIENT_ID id;
732 USHORT machine = 0;
733 HANDLE parent = 0, debug = 0, token = 0;
734 UNICODE_STRING redir, path = {0};
735 OBJECT_ATTRIBUTES attr, empty_attr = { sizeof(empty_attr) };
736 SIZE_T i, attr_count = (ps_attr->TotalLength - sizeof(ps_attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
737 const PS_ATTRIBUTE *handles_attr = NULL, *jobs_attr = NULL;
738 data_size_t handles_size, jobs_size;
739 obj_handle_t *handles, *jobs;
741 if (thread_flags & THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER)
743 WARN( "Invalid thread flags %#x.\n", (int)thread_flags );
745 return STATUS_INVALID_PARAMETER;
748 if (thread_flags & ~THREAD_CREATE_FLAGS_CREATE_SUSPENDED)
749 FIXME( "Unsupported thread flags %#x.\n", (int)thread_flags );
751 for (i = 0; i < attr_count; i++)
753 switch (ps_attr->Attributes[i].Attribute)
755 case PS_ATTRIBUTE_PARENT_PROCESS:
756 parent = ps_attr->Attributes[i].ValuePtr;
757 break;
758 case PS_ATTRIBUTE_DEBUG_PORT:
759 debug = ps_attr->Attributes[i].ValuePtr;
760 break;
761 case PS_ATTRIBUTE_IMAGE_NAME:
762 path.Length = ps_attr->Attributes[i].Size;
763 path.Buffer = ps_attr->Attributes[i].ValuePtr;
764 break;
765 case PS_ATTRIBUTE_TOKEN:
766 token = ps_attr->Attributes[i].ValuePtr;
767 break;
768 case PS_ATTRIBUTE_HANDLE_LIST:
769 if (process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES)
770 handles_attr = &ps_attr->Attributes[i];
771 break;
772 case PS_ATTRIBUTE_JOB_LIST:
773 jobs_attr = &ps_attr->Attributes[i];
774 break;
775 case PS_ATTRIBUTE_MACHINE_TYPE:
776 machine = ps_attr->Attributes[i].Value;
777 break;
778 default:
779 if (ps_attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT)
780 FIXME( "unhandled input attribute %lx\n", ps_attr->Attributes[i].Attribute );
781 break;
784 if (!process_attr) process_attr = &empty_attr;
786 TRACE( "%s image %s cmdline %s parent %p machine %x\n", debugstr_us( &path ),
787 debugstr_us( &params->ImagePathName ), debugstr_us( &params->CommandLine ), parent, machine );
789 unixdir = get_unix_curdir( params );
791 InitializeObjectAttributes( &attr, &path, OBJ_CASE_INSENSITIVE, 0, 0 );
792 get_redirect( &attr, &redir );
794 if ((status = get_pe_file_info( &attr, &file_handle, &pe_info )))
796 if (status == STATUS_INVALID_IMAGE_NOT_MZ && !fork_and_exec( &attr, unixdir, params ))
798 memset( info, 0, sizeof(*info) );
799 free( redir.Buffer );
800 return STATUS_SUCCESS;
802 goto done;
804 if (!machine) machine = pe_info.machine;
805 if (!(startup_info = create_startup_info( attr.ObjectName, params, &startup_info_size ))) goto done;
806 env_size = get_env_size( params, &winedebug );
808 if ((status = alloc_object_attributes( process_attr, &objattr, &attr_len ))) goto done;
810 if ((status = alloc_handle_list( handles_attr, &handles, &handles_size )))
812 free( objattr );
813 goto done;
816 if ((status = alloc_handle_list( jobs_attr, &jobs, &jobs_size )))
818 free( objattr );
819 free( handles );
820 goto done;
823 /* create the socket for the new process */
825 if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
827 status = STATUS_TOO_MANY_OPENED_FILES;
828 free( objattr );
829 free( handles );
830 free( jobs );
831 goto done;
833 #ifdef SO_PASSCRED
834 else
836 int enable = 1;
837 setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
839 #endif
841 wine_server_send_fd( socketfd[1] );
842 close( socketfd[1] );
844 /* create the process on the server side */
846 SERVER_START_REQ( new_process )
848 req->token = wine_server_obj_handle( token );
849 req->debug = wine_server_obj_handle( debug );
850 req->parent_process = wine_server_obj_handle( parent );
851 req->flags = process_flags;
852 req->socket_fd = socketfd[1];
853 req->access = process_access;
854 req->machine = machine;
855 req->info_size = startup_info_size;
856 req->handles_size = handles_size;
857 req->jobs_size = jobs_size;
858 wine_server_add_data( req, objattr, attr_len );
859 wine_server_add_data( req, handles, handles_size );
860 wine_server_add_data( req, jobs, jobs_size );
861 wine_server_add_data( req, startup_info, startup_info_size );
862 wine_server_add_data( req, params->Environment, env_size );
863 if (!(status = wine_server_call( req )))
865 process_handle = wine_server_ptr_handle( reply->handle );
866 id.UniqueProcess = ULongToHandle( reply->pid );
868 process_info = wine_server_ptr_handle( reply->info );
870 SERVER_END_REQ;
871 free( objattr );
872 free( handles );
873 free( jobs );
875 if (status)
877 switch (status)
879 case STATUS_INVALID_IMAGE_WIN_64:
880 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_us(&path) );
881 break;
882 case STATUS_INVALID_IMAGE_FORMAT:
883 ERR( "%s not supported on this installation (machine %04x)\n",
884 debugstr_us(&path), pe_info.machine );
885 break;
887 goto done;
890 if ((status = alloc_object_attributes( thread_attr, &objattr, &attr_len ))) goto done;
892 SERVER_START_REQ( new_thread )
894 req->process = wine_server_obj_handle( process_handle );
895 req->access = thread_access;
896 req->flags = thread_flags;
897 req->request_fd = -1;
898 wine_server_add_data( req, objattr, attr_len );
899 if (!(status = wine_server_call( req )))
901 thread_handle = wine_server_ptr_handle( reply->handle );
902 id.UniqueThread = ULongToHandle( reply->tid );
905 SERVER_END_REQ;
906 free( objattr );
907 if (status) goto done;
909 /* create the child process */
911 if ((status = spawn_process( params, socketfd[0], unixdir, winedebug, &pe_info ))) goto done;
913 close( socketfd[0] );
914 socketfd[0] = -1;
916 /* wait for the new process info to be ready */
918 NtWaitForSingleObject( process_info, FALSE, NULL );
919 SERVER_START_REQ( get_new_process_info )
921 req->info = wine_server_obj_handle( process_info );
922 wine_server_call( req );
923 success = reply->success;
924 status = reply->exit_code;
926 SERVER_END_REQ;
928 if (!success)
930 if (!status) status = STATUS_INTERNAL_ERROR;
931 goto done;
934 TRACE( "%s pid %04x tid %04x handles %p/%p\n", debugstr_us(&path),
935 (int)HandleToULong(id.UniqueProcess), (int)HandleToULong(id.UniqueThread),
936 process_handle, thread_handle );
938 /* update output attributes */
940 for (i = 0; i < attr_count; i++)
942 switch (ps_attr->Attributes[i].Attribute)
944 case PS_ATTRIBUTE_CLIENT_ID:
946 SIZE_T size = min( ps_attr->Attributes[i].Size, sizeof(id) );
947 memcpy( ps_attr->Attributes[i].ValuePtr, &id, size );
948 if (ps_attr->Attributes[i].ReturnLength) *ps_attr->Attributes[i].ReturnLength = size;
949 break;
951 case PS_ATTRIBUTE_IMAGE_INFO:
953 SECTION_IMAGE_INFORMATION info;
954 SIZE_T size = min( ps_attr->Attributes[i].Size, sizeof(info) );
955 virtual_fill_image_information( &pe_info, &info );
956 memcpy( ps_attr->Attributes[i].ValuePtr, &info, size );
957 if (ps_attr->Attributes[i].ReturnLength) *ps_attr->Attributes[i].ReturnLength = size;
958 break;
960 case PS_ATTRIBUTE_TEB_ADDRESS:
961 default:
962 if (!(ps_attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT))
963 FIXME( "unhandled output attribute %lx\n", ps_attr->Attributes[i].Attribute );
964 break;
967 *process_handle_ptr = process_handle;
968 *thread_handle_ptr = thread_handle;
969 process_handle = thread_handle = 0;
970 status = STATUS_SUCCESS;
972 done:
973 if (file_handle) NtClose( file_handle );
974 if (process_info) NtClose( process_info );
975 if (process_handle) NtClose( process_handle );
976 if (thread_handle) NtClose( thread_handle );
977 if (socketfd[0] != -1) close( socketfd[0] );
978 if (unixdir != -1) close( unixdir );
979 free( startup_info );
980 free( winedebug );
981 free( redir.Buffer );
982 return status;
986 /******************************************************************************
987 * NtTerminateProcess (NTDLL.@)
989 NTSTATUS WINAPI NtTerminateProcess( HANDLE handle, LONG exit_code )
991 unsigned int ret;
992 BOOL self;
994 SERVER_START_REQ( terminate_process )
996 req->handle = wine_server_obj_handle( handle );
997 req->exit_code = exit_code;
998 ret = wine_server_call( req );
999 self = reply->self;
1001 SERVER_END_REQ;
1002 if (self)
1004 if (!handle) process_exiting = TRUE;
1005 else if (process_exiting) exit_process( exit_code );
1006 else abort_process( exit_code );
1008 return ret;
1012 #if defined(HAVE_MACH_MACH_H)
1014 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1016 #if defined(MACH_TASK_BASIC_INFO)
1017 struct mach_task_basic_info info;
1018 mach_msg_type_number_t infoCount;
1020 if (unix_pid != -1) return; /* FIXME: Retrieve information for other processes. */
1022 infoCount = MACH_TASK_BASIC_INFO_COUNT;
1023 if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS)
1025 pvmi->VirtualSize = info.resident_size + info.virtual_size;
1026 pvmi->PagefileUsage = info.virtual_size;
1027 pvmi->WorkingSetSize = info.resident_size;
1028 pvmi->PeakWorkingSetSize = info.resident_size_max;
1030 #endif
1033 #elif defined(linux)
1035 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1037 FILE *f;
1038 char line[256], path[26];
1039 unsigned long value;
1041 if (unix_pid == -1)
1042 strcpy( path, "/proc/self/status" );
1043 else
1044 sprintf( path, "/proc/%u/status", unix_pid);
1045 f = fopen( path, "r" );
1046 if (!f) return;
1048 while (fgets(line, sizeof(line), f))
1050 if (sscanf(line, "VmPeak: %lu", &value))
1051 pvmi->PeakVirtualSize = (ULONG64)value * 1024;
1052 else if (sscanf(line, "VmSize: %lu", &value))
1053 pvmi->VirtualSize = (ULONG64)value * 1024;
1054 else if (sscanf(line, "VmHWM: %lu", &value))
1055 pvmi->PeakWorkingSetSize = (ULONG64)value * 1024;
1056 else if (sscanf(line, "VmRSS: %lu", &value))
1057 pvmi->WorkingSetSize = (ULONG64)value * 1024;
1058 else if (sscanf(line, "RssAnon: %lu", &value))
1059 pvmi->PagefileUsage += (ULONG64)value * 1024;
1060 else if (sscanf(line, "VmSwap: %lu", &value))
1061 pvmi->PagefileUsage += (ULONG64)value * 1024;
1063 pvmi->PeakPagefileUsage = pvmi->PagefileUsage;
1065 fclose(f);
1068 #elif defined(HAVE_LIBPROCSTAT)
1070 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1072 struct procstat *pstat;
1073 struct kinfo_proc *kip;
1074 unsigned int proc_count;
1076 pstat = procstat_open_sysctl();
1077 if (pstat)
1079 kip = procstat_getprocs( pstat, KERN_PROC_PID, unix_pid == -1 ? getpid() : unix_pid, &proc_count );
1080 if (kip)
1082 pvmi->VirtualSize = kip->ki_size;
1083 pvmi->PeakVirtualSize = kip->ki_size;
1084 pvmi->WorkingSetSize = kip->ki_rssize << PAGE_SHIFT;
1085 pvmi->PeakWorkingSetSize = kip->ki_rusage.ru_maxrss * 1024;
1086 procstat_freeprocs( pstat, kip );
1088 procstat_close( pstat );
1092 #else
1094 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
1096 /* FIXME : real data */
1099 #endif
1101 #define UNIMPLEMENTED_INFO_CLASS(c) \
1102 case c: \
1103 FIXME( "(process=%p) Unimplemented information class: " #c "\n", handle); \
1104 ret = STATUS_INVALID_INFO_CLASS; \
1105 break
1107 /**********************************************************************
1108 * NtQueryInformationProcess (NTDLL.@)
1110 NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class, void *info,
1111 ULONG size, ULONG *ret_len )
1113 unsigned int ret = STATUS_SUCCESS;
1114 ULONG len = 0;
1116 TRACE( "(%p,0x%08x,%p,0x%08x,%p)\n", handle, class, info, (int)size, ret_len );
1118 switch (class)
1120 UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits);
1121 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority);
1122 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority);
1123 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort);
1124 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken);
1125 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation);
1126 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize);
1127 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers);
1128 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits);
1129 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch);
1130 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL);
1131 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup);
1132 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information);
1133 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost);
1134 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap);
1135 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation);
1136 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled);
1137 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination);
1138 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing);
1140 case ProcessBasicInformation:
1142 PROCESS_BASIC_INFORMATION pbi;
1143 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1145 if (size >= sizeof(PROCESS_BASIC_INFORMATION))
1147 if (!info) ret = STATUS_ACCESS_VIOLATION;
1148 else
1150 SERVER_START_REQ(get_process_info)
1152 req->handle = wine_server_obj_handle( handle );
1153 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1155 pbi.ExitStatus = reply->exit_code;
1156 pbi.PebBaseAddress = wine_server_get_ptr( reply->peb );
1157 pbi.AffinityMask = reply->affinity & affinity_mask;
1158 pbi.BasePriority = reply->priority;
1159 pbi.UniqueProcessId = reply->pid;
1160 pbi.InheritedFromUniqueProcessId = reply->ppid;
1161 if (is_old_wow64())
1163 if (reply->machine != native_machine)
1164 pbi.PebBaseAddress = (PEB *)((char *)pbi.PebBaseAddress + 0x1000);
1165 else
1166 pbi.PebBaseAddress = NULL;
1170 SERVER_END_REQ;
1172 memcpy( info, &pbi, sizeof(PROCESS_BASIC_INFORMATION) );
1173 len = sizeof(PROCESS_BASIC_INFORMATION);
1175 if (size > sizeof(PROCESS_BASIC_INFORMATION)) ret = STATUS_INFO_LENGTH_MISMATCH;
1177 else
1179 len = sizeof(PROCESS_BASIC_INFORMATION);
1180 ret = STATUS_INFO_LENGTH_MISMATCH;
1183 break;
1185 case ProcessIoCounters:
1187 IO_COUNTERS pii;
1189 if (size >= sizeof(IO_COUNTERS))
1191 if (!info) ret = STATUS_ACCESS_VIOLATION;
1192 else if (!handle) ret = STATUS_INVALID_HANDLE;
1193 else
1195 /* FIXME : real data */
1196 memset(&pii, 0 , sizeof(IO_COUNTERS));
1197 memcpy(info, &pii, sizeof(IO_COUNTERS));
1198 len = sizeof(IO_COUNTERS);
1200 if (size > sizeof(IO_COUNTERS)) ret = STATUS_INFO_LENGTH_MISMATCH;
1202 else
1204 len = sizeof(IO_COUNTERS);
1205 ret = STATUS_INFO_LENGTH_MISMATCH;
1208 break;
1210 case ProcessVmCounters:
1212 VM_COUNTERS_EX pvmi;
1214 /* older Windows versions don't have the PrivateUsage field */
1215 if (size >= sizeof(VM_COUNTERS))
1217 if (!info) ret = STATUS_ACCESS_VIOLATION;
1218 else
1220 memset(&pvmi, 0, sizeof(pvmi));
1221 if (handle == GetCurrentProcess()) fill_vm_counters( &pvmi, -1 );
1222 else
1224 SERVER_START_REQ(get_process_vm_counters)
1226 req->handle = wine_server_obj_handle( handle );
1227 if (!(ret = wine_server_call( req )))
1229 pvmi.PeakVirtualSize = reply->peak_virtual_size;
1230 pvmi.VirtualSize = reply->virtual_size;
1231 pvmi.PeakWorkingSetSize = reply->peak_working_set_size;
1232 pvmi.WorkingSetSize = reply->working_set_size;
1233 pvmi.PagefileUsage = reply->pagefile_usage;
1234 pvmi.PeakPagefileUsage = reply->peak_pagefile_usage;
1237 SERVER_END_REQ;
1238 if (ret) break;
1240 if (size >= sizeof(VM_COUNTERS_EX))
1241 pvmi.PrivateUsage = pvmi.PagefileUsage;
1242 len = size;
1243 if (len != sizeof(VM_COUNTERS)) len = sizeof(VM_COUNTERS_EX);
1244 memcpy(info, &pvmi, min(size, sizeof(pvmi)));
1246 if (size != sizeof(VM_COUNTERS) && size != sizeof(VM_COUNTERS_EX))
1247 ret = STATUS_INFO_LENGTH_MISMATCH;
1249 else
1251 len = sizeof(pvmi);
1252 ret = STATUS_INFO_LENGTH_MISMATCH;
1255 break;
1257 case ProcessTimes:
1259 KERNEL_USER_TIMES pti = {{{0}}};
1261 if (size >= sizeof(KERNEL_USER_TIMES))
1263 if (!info) ret = STATUS_ACCESS_VIOLATION;
1264 else if (!handle) ret = STATUS_INVALID_HANDLE;
1265 else
1267 long ticks = sysconf(_SC_CLK_TCK);
1268 struct tms tms;
1270 /* FIXME: user/kernel times only work for current process */
1271 if (ticks && times( &tms ) != -1)
1273 pti.UserTime.QuadPart = (ULONGLONG)tms.tms_utime * 10000000 / ticks;
1274 pti.KernelTime.QuadPart = (ULONGLONG)tms.tms_stime * 10000000 / ticks;
1277 SERVER_START_REQ(get_process_info)
1279 req->handle = wine_server_obj_handle( handle );
1280 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1282 pti.CreateTime.QuadPart = reply->start_time;
1283 pti.ExitTime.QuadPart = reply->end_time;
1286 SERVER_END_REQ;
1288 memcpy(info, &pti, sizeof(KERNEL_USER_TIMES));
1289 len = sizeof(KERNEL_USER_TIMES);
1291 if (size > sizeof(KERNEL_USER_TIMES)) ret = STATUS_INFO_LENGTH_MISMATCH;
1293 else
1295 len = sizeof(KERNEL_USER_TIMES);
1296 ret = STATUS_INFO_LENGTH_MISMATCH;
1299 break;
1301 case ProcessDebugPort:
1302 len = sizeof(DWORD_PTR);
1303 if (size == len)
1305 if (!info) ret = STATUS_ACCESS_VIOLATION;
1306 else
1308 HANDLE debug;
1310 SERVER_START_REQ(get_process_debug_info)
1312 req->handle = wine_server_obj_handle( handle );
1313 ret = wine_server_call( req );
1314 debug = wine_server_ptr_handle( reply->debug );
1316 SERVER_END_REQ;
1317 if (ret == STATUS_SUCCESS)
1319 *(DWORD_PTR *)info = ~0ul;
1320 NtClose( debug );
1322 else if (ret == STATUS_PORT_NOT_SET)
1324 *(DWORD_PTR *)info = 0;
1325 ret = STATUS_SUCCESS;
1329 else ret = STATUS_INFO_LENGTH_MISMATCH;
1330 break;
1332 case ProcessDebugFlags:
1333 len = sizeof(DWORD);
1334 if (size == len)
1336 if (!info) ret = STATUS_ACCESS_VIOLATION;
1337 else
1339 HANDLE debug;
1341 SERVER_START_REQ(get_process_debug_info)
1343 req->handle = wine_server_obj_handle( handle );
1344 ret = wine_server_call( req );
1345 debug = wine_server_ptr_handle( reply->debug );
1346 *(DWORD *)info = reply->debug_children;
1348 SERVER_END_REQ;
1349 if (ret == STATUS_SUCCESS) NtClose( debug );
1350 else if (ret == STATUS_PORT_NOT_SET) ret = STATUS_SUCCESS;
1353 else ret = STATUS_INFO_LENGTH_MISMATCH;
1354 break;
1356 case ProcessDefaultHardErrorMode:
1357 len = sizeof(process_error_mode);
1358 if (size == len) memcpy(info, &process_error_mode, len);
1359 else ret = STATUS_INFO_LENGTH_MISMATCH;
1360 break;
1362 case ProcessDebugObjectHandle:
1363 len = sizeof(HANDLE);
1364 if (size == len)
1366 if (!info) ret = STATUS_ACCESS_VIOLATION;
1367 else
1369 SERVER_START_REQ(get_process_debug_info)
1371 req->handle = wine_server_obj_handle( handle );
1372 ret = wine_server_call( req );
1373 *(HANDLE *)info = wine_server_ptr_handle( reply->debug );
1375 SERVER_END_REQ;
1378 else ret = STATUS_INFO_LENGTH_MISMATCH;
1379 break;
1381 case ProcessHandleCount:
1382 if (size >= 4)
1384 if (!info) ret = STATUS_ACCESS_VIOLATION;
1385 else if (!handle) ret = STATUS_INVALID_HANDLE;
1386 else
1388 FIXME( "ProcessHandleCount (%p,%p,0x%08x,%p) stub\n", handle, info, (int)size, ret_len );
1389 memset(info, 0, 4);
1390 len = 4;
1392 if (size > 4) ret = STATUS_INFO_LENGTH_MISMATCH;
1394 else
1396 len = 4;
1397 ret = STATUS_INFO_LENGTH_MISMATCH;
1399 break;
1401 case ProcessHandleTable:
1402 FIXME( "ProcessHandleTable (%p,%p,0x%08x,%p) stub\n", handle, info, (int)size, ret_len );
1403 len = 0;
1404 break;
1406 case ProcessAffinityMask:
1407 len = sizeof(ULONG_PTR);
1408 if (size == len)
1410 const ULONG_PTR system_mask = get_system_affinity_mask();
1412 SERVER_START_REQ(get_process_info)
1414 req->handle = wine_server_obj_handle( handle );
1415 if (!(ret = wine_server_call( req )))
1416 *(ULONG_PTR *)info = reply->affinity & system_mask;
1418 SERVER_END_REQ;
1420 else ret = STATUS_INFO_LENGTH_MISMATCH;
1421 break;
1423 case ProcessSessionInformation:
1424 len = sizeof(DWORD);
1425 if (size == len)
1427 SERVER_START_REQ(get_process_info)
1429 req->handle = wine_server_obj_handle( handle );
1430 if (!(ret = wine_server_call( req )))
1431 *(DWORD *)info = reply->session_id;
1433 SERVER_END_REQ;
1435 else ret = STATUS_INFO_LENGTH_MISMATCH;
1436 break;
1438 case ProcessWow64Information:
1439 len = sizeof(ULONG_PTR);
1440 if (size != len) ret = STATUS_INFO_LENGTH_MISMATCH;
1441 else if (!info) ret = STATUS_ACCESS_VIOLATION;
1442 else if (!handle) ret = STATUS_INVALID_HANDLE;
1443 else if (handle == GetCurrentProcess()) *(ULONG_PTR *)info = is_wow64();
1444 else
1446 ULONG_PTR val = 0;
1448 SERVER_START_REQ( get_process_info )
1450 req->handle = wine_server_obj_handle( handle );
1451 if (!(ret = wine_server_call( req ))) val = (reply->machine != native_machine);
1453 SERVER_END_REQ;
1454 *(ULONG_PTR *)info = val;
1456 break;
1458 case ProcessImageFileName:
1459 /* FIXME: Should return a device path */
1460 case ProcessImageFileNameWin32:
1461 SERVER_START_REQ( get_process_image_name )
1463 UNICODE_STRING *str = info;
1465 req->handle = wine_server_obj_handle( handle );
1466 req->win32 = (class == ProcessImageFileNameWin32);
1467 wine_server_set_reply( req, str ? str + 1 : NULL,
1468 size > sizeof(UNICODE_STRING) ? size - sizeof(UNICODE_STRING) : 0 );
1469 ret = wine_server_call( req );
1470 if (ret == STATUS_BUFFER_TOO_SMALL) ret = STATUS_INFO_LENGTH_MISMATCH;
1471 len = sizeof(UNICODE_STRING) + reply->len;
1472 if (ret == STATUS_SUCCESS)
1474 str->MaximumLength = str->Length = reply->len;
1475 str->Buffer = (PWSTR)(str + 1);
1478 SERVER_END_REQ;
1479 break;
1481 case ProcessExecuteFlags:
1482 len = sizeof(ULONG);
1483 if (size != len)
1484 ret = STATUS_INFO_LENGTH_MISMATCH;
1485 else if (is_win64 && !is_wow64())
1486 *(ULONG *)info = MEM_EXECUTE_OPTION_DISABLE |
1487 MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION |
1488 MEM_EXECUTE_OPTION_PERMANENT;
1489 else
1490 *(ULONG *)info = execute_flags;
1491 break;
1493 case ProcessPriorityClass:
1494 len = sizeof(PROCESS_PRIORITY_CLASS);
1495 if (size == len)
1497 if (!info) ret = STATUS_ACCESS_VIOLATION;
1498 else
1500 PROCESS_PRIORITY_CLASS *priority = info;
1502 SERVER_START_REQ(get_process_info)
1504 req->handle = wine_server_obj_handle( handle );
1505 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1507 priority->PriorityClass = reply->priority;
1508 /* FIXME: Not yet supported by the wineserver */
1509 priority->Foreground = FALSE;
1512 SERVER_END_REQ;
1515 else ret = STATUS_INFO_LENGTH_MISMATCH;
1516 break;
1518 case ProcessCookie:
1519 FIXME( "ProcessCookie (%p,%p,0x%08x,%p) stub\n", handle, info, (int)size, ret_len );
1520 if (handle == NtCurrentProcess())
1522 len = sizeof(ULONG);
1523 if (size == len) *(ULONG *)info = 0;
1524 else ret = STATUS_INFO_LENGTH_MISMATCH;
1526 else ret = STATUS_INVALID_PARAMETER;
1527 break;
1529 case ProcessImageInformation:
1530 len = sizeof(SECTION_IMAGE_INFORMATION);
1531 if (size == len)
1533 if (info)
1535 pe_image_info_t pe_info;
1537 SERVER_START_REQ( get_process_info )
1539 req->handle = wine_server_obj_handle( handle );
1540 wine_server_set_reply( req, &pe_info, sizeof(pe_info) );
1541 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1542 virtual_fill_image_information( &pe_info, info );
1544 SERVER_END_REQ;
1546 else ret = STATUS_ACCESS_VIOLATION;
1548 else ret = STATUS_INFO_LENGTH_MISMATCH;
1549 break;
1551 case ProcessCycleTime:
1552 len = sizeof(PROCESS_CYCLE_TIME_INFORMATION);
1553 if (size == len)
1555 if (!info) ret = STATUS_ACCESS_VIOLATION;
1556 else
1558 PROCESS_CYCLE_TIME_INFORMATION cycles;
1560 FIXME( "ProcessCycleTime (%p,%p,0x%08x,%p) stub\n", handle, info, (int)size, ret_len );
1561 cycles.AccumulatedCycles = 0;
1562 cycles.CurrentCycleCount = 0;
1564 memcpy(info, &cycles, sizeof(PROCESS_CYCLE_TIME_INFORMATION));
1567 else ret = STATUS_INFO_LENGTH_MISMATCH;
1568 break;
1570 case ProcessWineLdtCopy:
1571 if (handle == NtCurrentProcess())
1573 #ifdef __i386__
1574 len = sizeof(struct ldt_copy *);
1575 if (size == len) *(struct ldt_copy **)info = &__wine_ldt_copy;
1576 else ret = STATUS_INFO_LENGTH_MISMATCH;
1577 #else
1578 ret = STATUS_NOT_IMPLEMENTED;
1579 #endif
1581 else ret = STATUS_INVALID_PARAMETER;
1582 break;
1584 default:
1585 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
1586 handle, class, info, (int)size, ret_len );
1587 ret = STATUS_INVALID_INFO_CLASS;
1588 break;
1591 if (ret_len) *ret_len = len;
1592 return ret;
1596 /**********************************************************************
1597 * NtSetInformationProcess (NTDLL.@)
1599 NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class, void *info, ULONG size )
1601 unsigned int ret = STATUS_SUCCESS;
1603 switch (class)
1605 case ProcessDefaultHardErrorMode:
1606 if (size != sizeof(UINT)) return STATUS_INVALID_PARAMETER;
1607 process_error_mode = *(UINT *)info;
1608 break;
1610 case ProcessAffinityMask:
1612 const ULONG_PTR system_mask = get_system_affinity_mask();
1614 if (size != sizeof(DWORD_PTR)) return STATUS_INVALID_PARAMETER;
1615 if (*(PDWORD_PTR)info & ~system_mask)
1616 return STATUS_INVALID_PARAMETER;
1617 if (!*(PDWORD_PTR)info)
1618 return STATUS_INVALID_PARAMETER;
1619 SERVER_START_REQ( set_process_info )
1621 req->handle = wine_server_obj_handle( handle );
1622 req->affinity = *(PDWORD_PTR)info;
1623 req->mask = SET_PROCESS_INFO_AFFINITY;
1624 ret = wine_server_call( req );
1626 SERVER_END_REQ;
1627 break;
1629 case ProcessPriorityClass:
1630 if (size != sizeof(PROCESS_PRIORITY_CLASS)) return STATUS_INVALID_PARAMETER;
1631 else
1633 PROCESS_PRIORITY_CLASS* ppc = info;
1635 SERVER_START_REQ( set_process_info )
1637 req->handle = wine_server_obj_handle( handle );
1638 /* FIXME Foreground isn't used */
1639 req->priority = ppc->PriorityClass;
1640 req->mask = SET_PROCESS_INFO_PRIORITY;
1641 ret = wine_server_call( req );
1643 SERVER_END_REQ;
1645 break;
1647 case ProcessExecuteFlags:
1648 if ((is_win64 && !is_wow64()) || size != sizeof(ULONG)) return STATUS_INVALID_PARAMETER;
1649 if (execute_flags & MEM_EXECUTE_OPTION_PERMANENT) return STATUS_ACCESS_DENIED;
1650 else
1652 BOOL enable;
1653 switch (*(ULONG *)info & (MEM_EXECUTE_OPTION_ENABLE|MEM_EXECUTE_OPTION_DISABLE))
1655 case MEM_EXECUTE_OPTION_ENABLE:
1656 enable = TRUE;
1657 break;
1658 case MEM_EXECUTE_OPTION_DISABLE:
1659 enable = FALSE;
1660 break;
1661 default:
1662 return STATUS_INVALID_PARAMETER;
1664 execute_flags = *(ULONG *)info;
1665 virtual_set_force_exec( enable );
1667 break;
1669 case ProcessInstrumentationCallback:
1671 PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION *instr = info;
1673 FIXME( "ProcessInstrumentationCallback stub.\n" );
1675 if (size < sizeof(*instr)) return STATUS_INFO_LENGTH_MISMATCH;
1676 ret = STATUS_SUCCESS;
1677 break;
1680 case ProcessThreadStackAllocation:
1682 void *addr = NULL;
1683 SIZE_T reserve;
1684 PROCESS_STACK_ALLOCATION_INFORMATION *stack = info;
1685 if (size == sizeof(PROCESS_STACK_ALLOCATION_INFORMATION_EX))
1686 stack = &((PROCESS_STACK_ALLOCATION_INFORMATION_EX *)info)->AllocInfo;
1687 else if (size != sizeof(*stack)) return STATUS_INFO_LENGTH_MISMATCH;
1689 reserve = stack->ReserveSize;
1690 ret = NtAllocateVirtualMemory( GetCurrentProcess(), &addr, stack->ZeroBits, &reserve,
1691 MEM_RESERVE, PAGE_READWRITE );
1692 if (!ret)
1694 #ifdef VALGRIND_STACK_REGISTER
1695 VALGRIND_STACK_REGISTER( addr, (char *)addr + reserve );
1696 #endif
1697 stack->StackBase = addr;
1699 break;
1702 case ProcessWineMakeProcessSystem:
1703 if (size != sizeof(HANDLE *)) return STATUS_INFO_LENGTH_MISMATCH;
1704 SERVER_START_REQ( make_process_system )
1706 req->handle = wine_server_obj_handle( handle );
1707 if (!(ret = wine_server_call( req )))
1708 *(HANDLE *)info = wine_server_ptr_handle( reply->event );
1710 SERVER_END_REQ;
1711 return ret;
1713 default:
1714 FIXME( "(%p,0x%08x,%p,0x%08x) stub\n", handle, class, info, (int)size );
1715 ret = STATUS_NOT_IMPLEMENTED;
1716 break;
1718 return ret;
1722 /**********************************************************************
1723 * NtOpenProcess (NTDLL.@)
1725 NTSTATUS WINAPI NtOpenProcess( HANDLE *handle, ACCESS_MASK access,
1726 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
1728 unsigned int status;
1730 *handle = 0;
1732 SERVER_START_REQ( open_process )
1734 req->pid = HandleToULong( id->UniqueProcess );
1735 req->access = access;
1736 req->attributes = attr ? attr->Attributes : 0;
1737 status = wine_server_call( req );
1738 if (!status) *handle = wine_server_ptr_handle( reply->handle );
1740 SERVER_END_REQ;
1741 return status;
1745 /**********************************************************************
1746 * NtSuspendProcess (NTDLL.@)
1748 NTSTATUS WINAPI NtSuspendProcess( HANDLE handle )
1750 unsigned int ret;
1752 SERVER_START_REQ( suspend_process )
1754 req->handle = wine_server_obj_handle( handle );
1755 ret = wine_server_call( req );
1757 SERVER_END_REQ;
1758 return ret;
1762 /**********************************************************************
1763 * NtResumeProcess (NTDLL.@)
1765 NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
1767 unsigned int ret;
1769 SERVER_START_REQ( resume_process )
1771 req->handle = wine_server_obj_handle( handle );
1772 ret = wine_server_call( req );
1774 SERVER_END_REQ;
1775 return ret;
1779 /**********************************************************************
1780 * NtDebugActiveProcess (NTDLL.@)
1782 NTSTATUS WINAPI NtDebugActiveProcess( HANDLE process, HANDLE debug )
1784 unsigned int ret;
1786 SERVER_START_REQ( debug_process )
1788 req->handle = wine_server_obj_handle( process );
1789 req->debug = wine_server_obj_handle( debug );
1790 req->attach = 1;
1791 ret = wine_server_call( req );
1793 SERVER_END_REQ;
1794 return ret;
1798 /**********************************************************************
1799 * NtRemoveProcessDebug (NTDLL.@)
1801 NTSTATUS WINAPI NtRemoveProcessDebug( HANDLE process, HANDLE debug )
1803 unsigned int ret;
1805 SERVER_START_REQ( debug_process )
1807 req->handle = wine_server_obj_handle( process );
1808 req->debug = wine_server_obj_handle( debug );
1809 req->attach = 0;
1810 ret = wine_server_call( req );
1812 SERVER_END_REQ;
1813 return ret;
1817 /**********************************************************************
1818 * NtDebugContinue (NTDLL.@)
1820 NTSTATUS WINAPI NtDebugContinue( HANDLE handle, CLIENT_ID *client, NTSTATUS status )
1822 unsigned int ret;
1824 SERVER_START_REQ( continue_debug_event )
1826 req->debug = wine_server_obj_handle( handle );
1827 req->pid = HandleToULong( client->UniqueProcess );
1828 req->tid = HandleToULong( client->UniqueThread );
1829 req->status = status;
1830 ret = wine_server_call( req );
1832 SERVER_END_REQ;
1833 return ret;