usp10/tests: A spelling fix in an ok() message.
[wine.git] / dlls / ntdll / process.c
blobe3c2ba5ccbf3637d5268acffbbb0107807b07d8d
1 /*
2 * NT process handling
4 * Copyright 1996-1998 Marcus Meissner
5 * Copyright 2018 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 #include "config.h"
23 #include "wine/port.h"
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
34 #endif
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_WAIT_H
37 # include <sys/wait.h>
38 #endif
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
43 #include "ntstatus.h"
44 #define WIN32_NO_STATUS
45 #include "wine/debug.h"
46 #include "windef.h"
47 #include "winternl.h"
48 #include "ntdll_misc.h"
49 #include "wine/library.h"
50 #include "wine/server.h"
51 #include "wine/unicode.h"
53 #ifdef HAVE_MACH_MACH_H
54 #include <mach/mach.h>
55 #endif
57 WINE_DEFAULT_DEBUG_CHANNEL(process);
59 static ULONG execute_flags = MEM_EXECUTE_OPTION_DISABLE;
61 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
63 static const char * const cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" };
65 static inline BOOL is_64bit_arch( client_cpu_t cpu )
67 return (cpu == CPU_x86_64 || cpu == CPU_ARM64);
71 * Process object
74 /******************************************************************************
75 * NtTerminateProcess [NTDLL.@]
77 * Native applications must kill themselves when done
79 NTSTATUS WINAPI NtTerminateProcess( HANDLE handle, LONG exit_code )
81 NTSTATUS ret;
82 BOOL self;
83 SERVER_START_REQ( terminate_process )
85 req->handle = wine_server_obj_handle( handle );
86 req->exit_code = exit_code;
87 ret = wine_server_call( req );
88 self = !ret && reply->self;
90 SERVER_END_REQ;
91 if (self && handle) _exit( get_unix_exit_code( exit_code ));
92 return ret;
95 /******************************************************************************
96 * RtlGetCurrentPeb [NTDLL.@]
99 PEB * WINAPI RtlGetCurrentPeb(void)
101 return NtCurrentTeb()->Peb;
104 /***********************************************************************
105 * __wine_make_process_system (NTDLL.@)
107 * Mark the current process as a system process.
108 * Returns the event that is signaled when all non-system processes have exited.
110 HANDLE CDECL __wine_make_process_system(void)
112 HANDLE ret = 0;
113 SERVER_START_REQ( make_process_system )
115 if (!wine_server_call( req )) ret = wine_server_ptr_handle( reply->event );
117 SERVER_END_REQ;
118 return ret;
121 static UINT process_error_mode;
123 #define UNIMPLEMENTED_INFO_CLASS(c) \
124 case c: \
125 FIXME("(process=%p) Unimplemented information class: " #c "\n", ProcessHandle); \
126 ret = STATUS_INVALID_INFO_CLASS; \
127 break
129 ULONG_PTR get_system_affinity_mask(void)
131 ULONG num_cpus = NtCurrentTeb()->Peb->NumberOfProcessors;
132 if (num_cpus >= sizeof(ULONG_PTR) * 8) return ~(ULONG_PTR)0;
133 return ((ULONG_PTR)1 << num_cpus) - 1;
136 #if defined(HAVE_MACH_MACH_H)
138 static void fill_VM_COUNTERS(VM_COUNTERS* pvmi)
140 #if defined(MACH_TASK_BASIC_INFO)
141 struct mach_task_basic_info info;
142 mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
143 if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS)
145 pvmi->VirtualSize = info.resident_size + info.virtual_size;
146 pvmi->PagefileUsage = info.virtual_size;
147 pvmi->WorkingSetSize = info.resident_size;
148 pvmi->PeakWorkingSetSize = info.resident_size_max;
150 #endif
153 #elif defined(linux)
155 static void fill_VM_COUNTERS(VM_COUNTERS* pvmi)
157 FILE *f;
158 char line[256];
159 unsigned long value;
161 f = fopen("/proc/self/status", "r");
162 if (!f) return;
164 while (fgets(line, sizeof(line), f))
166 if (sscanf(line, "VmPeak: %lu", &value))
167 pvmi->PeakVirtualSize = (ULONG64)value * 1024;
168 else if (sscanf(line, "VmSize: %lu", &value))
169 pvmi->VirtualSize = (ULONG64)value * 1024;
170 else if (sscanf(line, "VmHWM: %lu", &value))
171 pvmi->PeakWorkingSetSize = (ULONG64)value * 1024;
172 else if (sscanf(line, "VmRSS: %lu", &value))
173 pvmi->WorkingSetSize = (ULONG64)value * 1024;
174 else if (sscanf(line, "RssAnon: %lu", &value))
175 pvmi->PagefileUsage += (ULONG64)value * 1024;
176 else if (sscanf(line, "VmSwap: %lu", &value))
177 pvmi->PagefileUsage += (ULONG64)value * 1024;
179 pvmi->PeakPagefileUsage = pvmi->PagefileUsage;
181 fclose(f);
184 #else
186 static void fill_VM_COUNTERS(VM_COUNTERS* pvmi)
188 /* FIXME : real data */
191 #endif
193 /******************************************************************************
194 * NtQueryInformationProcess [NTDLL.@]
195 * ZwQueryInformationProcess [NTDLL.@]
198 NTSTATUS WINAPI NtQueryInformationProcess(
199 IN HANDLE ProcessHandle,
200 IN PROCESSINFOCLASS ProcessInformationClass,
201 OUT PVOID ProcessInformation,
202 IN ULONG ProcessInformationLength,
203 OUT PULONG ReturnLength)
205 NTSTATUS ret = STATUS_SUCCESS;
206 ULONG len = 0;
208 TRACE("(%p,0x%08x,%p,0x%08x,%p)\n",
209 ProcessHandle,ProcessInformationClass,
210 ProcessInformation,ProcessInformationLength,
211 ReturnLength);
213 switch (ProcessInformationClass)
215 UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits);
216 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority);
217 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority);
218 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort);
219 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken);
220 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation);
221 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize);
222 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers);
223 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits);
224 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch);
225 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL);
226 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup);
227 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information);
228 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost);
229 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap);
230 UNIMPLEMENTED_INFO_CLASS(ProcessSessionInformation);
231 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation);
232 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled);
233 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination);
234 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing);
236 case ProcessBasicInformation:
238 PROCESS_BASIC_INFORMATION pbi;
239 const ULONG_PTR affinity_mask = get_system_affinity_mask();
241 if (ProcessInformationLength >= sizeof(PROCESS_BASIC_INFORMATION))
243 if (!ProcessInformation)
244 ret = STATUS_ACCESS_VIOLATION;
245 else if (!ProcessHandle)
246 ret = STATUS_INVALID_HANDLE;
247 else
249 SERVER_START_REQ(get_process_info)
251 req->handle = wine_server_obj_handle( ProcessHandle );
252 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
254 pbi.ExitStatus = reply->exit_code;
255 pbi.PebBaseAddress = wine_server_get_ptr( reply->peb );
256 pbi.AffinityMask = reply->affinity & affinity_mask;
257 pbi.BasePriority = reply->priority;
258 pbi.UniqueProcessId = reply->pid;
259 pbi.InheritedFromUniqueProcessId = reply->ppid;
262 SERVER_END_REQ;
264 memcpy(ProcessInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION));
266 len = sizeof(PROCESS_BASIC_INFORMATION);
269 if (ProcessInformationLength > sizeof(PROCESS_BASIC_INFORMATION))
270 ret = STATUS_INFO_LENGTH_MISMATCH;
272 else
274 len = sizeof(PROCESS_BASIC_INFORMATION);
275 ret = STATUS_INFO_LENGTH_MISMATCH;
278 break;
279 case ProcessIoCounters:
281 IO_COUNTERS pii;
283 if (ProcessInformationLength >= sizeof(IO_COUNTERS))
285 if (!ProcessInformation)
286 ret = STATUS_ACCESS_VIOLATION;
287 else if (!ProcessHandle)
288 ret = STATUS_INVALID_HANDLE;
289 else
291 /* FIXME : real data */
292 memset(&pii, 0 , sizeof(IO_COUNTERS));
294 memcpy(ProcessInformation, &pii, sizeof(IO_COUNTERS));
296 len = sizeof(IO_COUNTERS);
299 if (ProcessInformationLength > sizeof(IO_COUNTERS))
300 ret = STATUS_INFO_LENGTH_MISMATCH;
302 else
304 len = sizeof(IO_COUNTERS);
305 ret = STATUS_INFO_LENGTH_MISMATCH;
308 break;
309 case ProcessVmCounters:
311 VM_COUNTERS pvmi;
313 /* older Windows versions don't have the PrivatePageCount field */
314 if (ProcessInformationLength >= FIELD_OFFSET(VM_COUNTERS,PrivatePageCount))
316 if (!ProcessInformation)
317 ret = STATUS_ACCESS_VIOLATION;
318 else
320 memset(&pvmi, 0 , sizeof(VM_COUNTERS));
321 if (ProcessHandle == GetCurrentProcess())
322 fill_VM_COUNTERS(&pvmi);
323 else
325 SERVER_START_REQ(get_process_vm_counters)
327 req->handle = wine_server_obj_handle( ProcessHandle );
328 if (!(ret = wine_server_call( req )))
330 pvmi.PeakVirtualSize = reply->peak_virtual_size;
331 pvmi.VirtualSize = reply->virtual_size;
332 pvmi.PeakWorkingSetSize = reply->peak_working_set_size;
333 pvmi.WorkingSetSize = reply->working_set_size;
334 pvmi.PagefileUsage = reply->pagefile_usage;
335 pvmi.PeakPagefileUsage = reply->peak_pagefile_usage;
338 SERVER_END_REQ;
339 if (ret) break;
342 len = ProcessInformationLength;
343 if (len != FIELD_OFFSET(VM_COUNTERS,PrivatePageCount)) len = sizeof(VM_COUNTERS);
345 memcpy(ProcessInformation, &pvmi, min(ProcessInformationLength,sizeof(VM_COUNTERS)));
348 if (ProcessInformationLength != FIELD_OFFSET(VM_COUNTERS,PrivatePageCount) &&
349 ProcessInformationLength != sizeof(VM_COUNTERS))
350 ret = STATUS_INFO_LENGTH_MISMATCH;
352 else
354 len = sizeof(pvmi);
355 ret = STATUS_INFO_LENGTH_MISMATCH;
358 break;
359 case ProcessTimes:
361 KERNEL_USER_TIMES pti;
363 if (ProcessInformationLength >= sizeof(KERNEL_USER_TIMES))
365 if (!ProcessInformation)
366 ret = STATUS_ACCESS_VIOLATION;
367 else if (!ProcessHandle)
368 ret = STATUS_INVALID_HANDLE;
369 else
371 /* FIXME : User- and KernelTime have to be implemented */
372 memset(&pti, 0, sizeof(KERNEL_USER_TIMES));
374 SERVER_START_REQ(get_process_info)
376 req->handle = wine_server_obj_handle( ProcessHandle );
377 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
379 pti.CreateTime.QuadPart = reply->start_time;
380 pti.ExitTime.QuadPart = reply->end_time;
383 SERVER_END_REQ;
385 memcpy(ProcessInformation, &pti, sizeof(KERNEL_USER_TIMES));
386 len = sizeof(KERNEL_USER_TIMES);
389 if (ProcessInformationLength > sizeof(KERNEL_USER_TIMES))
390 ret = STATUS_INFO_LENGTH_MISMATCH;
392 else
394 len = sizeof(KERNEL_USER_TIMES);
395 ret = STATUS_INFO_LENGTH_MISMATCH;
398 break;
399 case ProcessDebugPort:
400 len = sizeof(DWORD_PTR);
401 if (ProcessInformationLength == len)
403 if (!ProcessInformation)
404 ret = STATUS_ACCESS_VIOLATION;
405 else if (!ProcessHandle)
406 ret = STATUS_INVALID_HANDLE;
407 else
409 SERVER_START_REQ(get_process_info)
411 req->handle = wine_server_obj_handle( ProcessHandle );
412 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
414 *(DWORD_PTR *)ProcessInformation = reply->debugger_present ? ~(DWORD_PTR)0 : 0;
417 SERVER_END_REQ;
420 else
421 ret = STATUS_INFO_LENGTH_MISMATCH;
422 break;
423 case ProcessDebugFlags:
424 len = sizeof(DWORD);
425 if (ProcessInformationLength == len)
427 if (!ProcessInformation)
428 ret = STATUS_ACCESS_VIOLATION;
429 else if (!ProcessHandle)
430 ret = STATUS_INVALID_HANDLE;
431 else
433 SERVER_START_REQ(get_process_info)
435 req->handle = wine_server_obj_handle( ProcessHandle );
436 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
438 *(DWORD *)ProcessInformation = reply->debug_children;
441 SERVER_END_REQ;
444 else
445 ret = STATUS_INFO_LENGTH_MISMATCH;
446 break;
447 case ProcessDefaultHardErrorMode:
448 len = sizeof(process_error_mode);
449 if (ProcessInformationLength == len)
450 memcpy(ProcessInformation, &process_error_mode, len);
451 else
452 ret = STATUS_INFO_LENGTH_MISMATCH;
453 break;
454 case ProcessDebugObjectHandle:
455 /* "These are not the debuggers you are looking for." *
456 * set it to 0 aka "no debugger" to satisfy copy protections */
457 len = sizeof(HANDLE);
458 if (ProcessInformationLength == len)
460 if (!ProcessInformation)
461 ret = STATUS_ACCESS_VIOLATION;
462 else if (!ProcessHandle)
463 ret = STATUS_INVALID_HANDLE;
464 else
466 memset(ProcessInformation, 0, ProcessInformationLength);
467 ret = STATUS_PORT_NOT_SET;
470 else
471 ret = STATUS_INFO_LENGTH_MISMATCH;
472 break;
473 case ProcessHandleCount:
474 if (ProcessInformationLength >= 4)
476 if (!ProcessInformation)
477 ret = STATUS_ACCESS_VIOLATION;
478 else if (!ProcessHandle)
479 ret = STATUS_INVALID_HANDLE;
480 else
482 memset(ProcessInformation, 0, 4);
483 len = 4;
486 if (ProcessInformationLength > 4)
487 ret = STATUS_INFO_LENGTH_MISMATCH;
489 else
491 len = 4;
492 ret = STATUS_INFO_LENGTH_MISMATCH;
494 break;
496 case ProcessAffinityMask:
497 len = sizeof(ULONG_PTR);
498 if (ProcessInformationLength == len)
500 const ULONG_PTR system_mask = get_system_affinity_mask();
502 SERVER_START_REQ(get_process_info)
504 req->handle = wine_server_obj_handle( ProcessHandle );
505 if (!(ret = wine_server_call( req )))
506 *(ULONG_PTR *)ProcessInformation = reply->affinity & system_mask;
508 SERVER_END_REQ;
510 else ret = STATUS_INFO_LENGTH_MISMATCH;
511 break;
513 case ProcessWow64Information:
514 len = sizeof(ULONG_PTR);
515 if (ProcessInformationLength != len) ret = STATUS_INFO_LENGTH_MISMATCH;
516 else if (!ProcessInformation) ret = STATUS_ACCESS_VIOLATION;
517 else if(!ProcessHandle) ret = STATUS_INVALID_HANDLE;
518 else
520 ULONG_PTR val = 0;
522 if (ProcessHandle == GetCurrentProcess()) val = is_wow64;
523 else if (server_cpus & ((1 << CPU_x86_64) | (1 << CPU_ARM64)))
525 SERVER_START_REQ( get_process_info )
527 req->handle = wine_server_obj_handle( ProcessHandle );
528 if (!(ret = wine_server_call( req )))
529 val = (reply->cpu != CPU_x86_64 && reply->cpu != CPU_ARM64);
531 SERVER_END_REQ;
533 *(ULONG_PTR *)ProcessInformation = val;
535 break;
536 case ProcessImageFileName:
537 /* FIXME: Should return a device path */
538 case ProcessImageFileNameWin32:
539 SERVER_START_REQ(get_dll_info)
541 UNICODE_STRING *image_file_name_str = ProcessInformation;
543 req->handle = wine_server_obj_handle( ProcessHandle );
544 req->base_address = 0; /* main module */
545 wine_server_set_reply( req, image_file_name_str ? image_file_name_str + 1 : NULL,
546 ProcessInformationLength > sizeof(UNICODE_STRING) ? ProcessInformationLength - sizeof(UNICODE_STRING) : 0 );
547 ret = wine_server_call( req );
548 if (ret == STATUS_BUFFER_TOO_SMALL) ret = STATUS_INFO_LENGTH_MISMATCH;
550 len = sizeof(UNICODE_STRING) + reply->filename_len;
551 if (ret == STATUS_SUCCESS)
553 image_file_name_str->MaximumLength = image_file_name_str->Length = reply->filename_len;
554 image_file_name_str->Buffer = (PWSTR)(image_file_name_str + 1);
557 SERVER_END_REQ;
558 break;
559 case ProcessExecuteFlags:
560 len = sizeof(ULONG);
561 if (ProcessInformationLength == len)
562 *(ULONG *)ProcessInformation = execute_flags;
563 else
564 ret = STATUS_INFO_LENGTH_MISMATCH;
565 break;
566 case ProcessPriorityClass:
567 len = sizeof(PROCESS_PRIORITY_CLASS);
568 if (ProcessInformationLength == len)
570 if (!ProcessInformation)
571 ret = STATUS_ACCESS_VIOLATION;
572 else if (!ProcessHandle)
573 ret = STATUS_INVALID_HANDLE;
574 else
576 PROCESS_PRIORITY_CLASS *priority = ProcessInformation;
578 SERVER_START_REQ(get_process_info)
580 req->handle = wine_server_obj_handle( ProcessHandle );
581 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
583 priority->PriorityClass = reply->priority;
584 /* FIXME: Not yet supported by the wineserver */
585 priority->Foreground = FALSE;
588 SERVER_END_REQ;
591 else
592 ret = STATUS_INFO_LENGTH_MISMATCH;
593 break;
594 case ProcessCookie:
595 FIXME("ProcessCookie (%p,%p,0x%08x,%p) stub\n",
596 ProcessHandle,ProcessInformation,
597 ProcessInformationLength,ReturnLength);
599 if(ProcessHandle == NtCurrentProcess())
601 len = sizeof(ULONG);
602 if (ProcessInformationLength == len)
603 *(ULONG *)ProcessInformation = 0;
604 else
605 ret = STATUS_INFO_LENGTH_MISMATCH;
607 else
608 ret = STATUS_INVALID_PARAMETER;
609 break;
610 default:
611 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
612 ProcessHandle,ProcessInformationClass,
613 ProcessInformation,ProcessInformationLength,
614 ReturnLength);
615 ret = STATUS_INVALID_INFO_CLASS;
616 break;
619 if (ReturnLength) *ReturnLength = len;
621 return ret;
624 /******************************************************************************
625 * NtSetInformationProcess [NTDLL.@]
626 * ZwSetInformationProcess [NTDLL.@]
628 NTSTATUS WINAPI NtSetInformationProcess(
629 IN HANDLE ProcessHandle,
630 IN PROCESSINFOCLASS ProcessInformationClass,
631 IN PVOID ProcessInformation,
632 IN ULONG ProcessInformationLength)
634 NTSTATUS ret = STATUS_SUCCESS;
636 switch (ProcessInformationClass)
638 case ProcessDefaultHardErrorMode:
639 if (ProcessInformationLength != sizeof(UINT)) return STATUS_INVALID_PARAMETER;
640 process_error_mode = *(UINT *)ProcessInformation;
641 break;
642 case ProcessAffinityMask:
644 const ULONG_PTR system_mask = get_system_affinity_mask();
646 if (ProcessInformationLength != sizeof(DWORD_PTR)) return STATUS_INVALID_PARAMETER;
647 if (*(PDWORD_PTR)ProcessInformation & ~system_mask)
648 return STATUS_INVALID_PARAMETER;
649 if (!*(PDWORD_PTR)ProcessInformation)
650 return STATUS_INVALID_PARAMETER;
651 SERVER_START_REQ( set_process_info )
653 req->handle = wine_server_obj_handle( ProcessHandle );
654 req->affinity = *(PDWORD_PTR)ProcessInformation;
655 req->mask = SET_PROCESS_INFO_AFFINITY;
656 ret = wine_server_call( req );
658 SERVER_END_REQ;
659 break;
661 case ProcessPriorityClass:
662 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
663 return STATUS_INVALID_PARAMETER;
664 else
666 PROCESS_PRIORITY_CLASS* ppc = ProcessInformation;
668 SERVER_START_REQ( set_process_info )
670 req->handle = wine_server_obj_handle( ProcessHandle );
671 /* FIXME Foreground isn't used */
672 req->priority = ppc->PriorityClass;
673 req->mask = SET_PROCESS_INFO_PRIORITY;
674 ret = wine_server_call( req );
676 SERVER_END_REQ;
678 break;
680 case ProcessExecuteFlags:
681 if (ProcessInformationLength != sizeof(ULONG))
682 return STATUS_INVALID_PARAMETER;
683 else if (execute_flags & MEM_EXECUTE_OPTION_PERMANENT)
684 return STATUS_ACCESS_DENIED;
685 else
687 BOOL enable;
688 switch (*(ULONG *)ProcessInformation & (MEM_EXECUTE_OPTION_ENABLE|MEM_EXECUTE_OPTION_DISABLE))
690 case MEM_EXECUTE_OPTION_ENABLE:
691 enable = TRUE;
692 break;
693 case MEM_EXECUTE_OPTION_DISABLE:
694 enable = FALSE;
695 break;
696 default:
697 return STATUS_INVALID_PARAMETER;
699 execute_flags = *(ULONG *)ProcessInformation;
700 VIRTUAL_SetForceExec( enable );
702 break;
704 default:
705 FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
706 ProcessHandle,ProcessInformationClass,ProcessInformation,
707 ProcessInformationLength);
708 ret = STATUS_NOT_IMPLEMENTED;
709 break;
711 return ret;
714 /******************************************************************************
715 * NtFlushInstructionCache [NTDLL.@]
716 * ZwFlushInstructionCache [NTDLL.@]
718 NTSTATUS WINAPI NtFlushInstructionCache( HANDLE handle, const void *addr, SIZE_T size )
720 #if defined(__x86_64__) || defined(__i386__)
721 /* no-op */
722 #elif defined(HAVE___CLEAR_CACHE)
723 if (handle == GetCurrentProcess())
725 __clear_cache( (char *)addr, (char *)addr + size );
727 else
729 static int once;
730 if (!once++) FIXME( "%p %p %ld other process not supported\n", handle, addr, size );
732 #else
733 static int once;
734 if (!once++) FIXME( "%p %p %ld\n", handle, addr, size );
735 #endif
736 return STATUS_SUCCESS;
739 /******************************************************************
740 * NtOpenProcess [NTDLL.@]
741 * ZwOpenProcess [NTDLL.@]
743 NTSTATUS WINAPI NtOpenProcess(PHANDLE handle, ACCESS_MASK access,
744 const OBJECT_ATTRIBUTES* attr, const CLIENT_ID* cid)
746 NTSTATUS status;
748 SERVER_START_REQ( open_process )
750 req->pid = HandleToULong(cid->UniqueProcess);
751 req->access = access;
752 req->attributes = attr ? attr->Attributes : 0;
753 status = wine_server_call( req );
754 if (!status) *handle = wine_server_ptr_handle( reply->handle );
756 SERVER_END_REQ;
757 return status;
760 /******************************************************************************
761 * NtResumeProcess
762 * ZwResumeProcess
764 NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
766 NTSTATUS ret;
768 SERVER_START_REQ( resume_process )
770 req->handle = wine_server_obj_handle( handle );
771 ret = wine_server_call( req );
773 SERVER_END_REQ;
775 return ret;
778 /******************************************************************************
779 * NtSuspendProcess
780 * ZwSuspendProcess
782 NTSTATUS WINAPI NtSuspendProcess( HANDLE handle )
784 NTSTATUS ret;
786 SERVER_START_REQ( suspend_process )
788 req->handle = wine_server_obj_handle( handle );
789 ret = wine_server_call( req );
791 SERVER_END_REQ;
793 return ret;
797 /***********************************************************************
798 * build_argv
800 * Build an argv array from a command-line.
801 * 'reserved' is the number of args to reserve before the first one.
803 static char **build_argv( const UNICODE_STRING *cmdlineW, int reserved )
805 int argc;
806 char **argv;
807 char *arg, *s, *d, *cmdline;
808 int in_quotes, bcount, len;
810 len = ntdll_wcstoumbs( 0, cmdlineW->Buffer, cmdlineW->Length / sizeof(WCHAR), NULL, 0, NULL, NULL );
811 if (!(cmdline = RtlAllocateHeap( GetProcessHeap(), 0, len + 1 ))) return NULL;
812 ntdll_wcstoumbs( 0, cmdlineW->Buffer, cmdlineW->Length / sizeof(WCHAR), cmdline, len, NULL, NULL );
813 cmdline[len++] = 0;
815 argc = reserved + 1;
816 bcount = 0;
817 in_quotes = 0;
818 s = cmdline;
819 while (1)
821 if (*s == '\0' || ((*s == ' ' || *s == '\t') && !in_quotes))
823 /* space */
824 argc++;
825 /* skip the remaining spaces */
826 while (*s == ' ' || *s == '\t') s++;
827 if (*s == '\0') break;
828 bcount = 0;
829 continue;
831 else if (*s == '\\') bcount++; /* '\', count them */
832 else if ((*s == '"') && ((bcount & 1) == 0))
834 if (in_quotes && s[1] == '"') s++;
835 else
837 /* unescaped '"' */
838 in_quotes = !in_quotes;
839 bcount = 0;
842 else bcount = 0; /* a regular character */
843 s++;
845 if (!(argv = RtlAllocateHeap( GetProcessHeap(), 0, argc * sizeof(*argv) + len )))
847 RtlFreeHeap( GetProcessHeap(), 0, cmdline );
848 return NULL;
851 arg = d = s = (char *)(argv + argc);
852 memcpy( d, cmdline, len );
853 bcount = 0;
854 in_quotes = 0;
855 argc = reserved;
856 while (*s)
858 if ((*s == ' ' || *s == '\t') && !in_quotes)
860 /* Close the argument and copy it */
861 *d = 0;
862 argv[argc++] = arg;
863 /* skip the remaining spaces */
866 s++;
867 } while (*s == ' ' || *s == '\t');
869 /* Start with a new argument */
870 arg = d = s;
871 bcount = 0;
873 else if (*s == '\\')
875 *d++ = *s++;
876 bcount++;
878 else if (*s == '"')
880 if ((bcount & 1) == 0)
882 /* Preceded by an even number of '\', this is half that
883 * number of '\', plus a '"' which we discard.
885 d -= bcount/2;
886 s++;
887 if (in_quotes && *s == '"')
889 *d++ = '"';
890 s++;
892 else in_quotes = !in_quotes;
894 else
896 /* Preceded by an odd number of '\', this is half that
897 * number of '\' followed by a '"'
899 d = d - bcount / 2 - 1;
900 *d++ = '"';
901 s++;
903 bcount = 0;
905 else
907 /* a regular character */
908 *d++ = *s++;
909 bcount = 0;
912 if (*arg)
914 *d = '\0';
915 argv[argc++] = arg;
917 argv[argc] = NULL;
919 RtlFreeHeap( GetProcessHeap(), 0, cmdline );
920 return argv;
924 static inline const WCHAR *get_params_string( const RTL_USER_PROCESS_PARAMETERS *params,
925 const UNICODE_STRING *str )
927 if (params->Flags & PROCESS_PARAMS_FLAG_NORMALIZED) return str->Buffer;
928 return (const WCHAR *)((const char *)params + (UINT_PTR)str->Buffer);
931 static inline DWORD append_string( void **ptr, const RTL_USER_PROCESS_PARAMETERS *params,
932 const UNICODE_STRING *str )
934 const WCHAR *buffer = get_params_string( params, str );
935 memcpy( *ptr, buffer, str->Length );
936 *ptr = (WCHAR *)*ptr + str->Length / sizeof(WCHAR);
937 return str->Length;
940 /***********************************************************************
941 * create_startup_info
943 static startup_info_t *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *params, DWORD *info_size )
945 startup_info_t *info;
946 DWORD size;
947 void *ptr;
949 size = sizeof(*info);
950 size += params->CurrentDirectory.DosPath.Length;
951 size += params->DllPath.Length;
952 size += params->ImagePathName.Length;
953 size += params->CommandLine.Length;
954 size += params->WindowTitle.Length;
955 size += params->Desktop.Length;
956 size += params->ShellInfo.Length;
957 size += params->RuntimeInfo.Length;
958 size = (size + 1) & ~1;
959 *info_size = size;
961 if (!(info = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) return NULL;
963 info->console_flags = params->ConsoleFlags;
964 info->console = wine_server_obj_handle( params->ConsoleHandle );
965 info->hstdin = wine_server_obj_handle( params->hStdInput );
966 info->hstdout = wine_server_obj_handle( params->hStdOutput );
967 info->hstderr = wine_server_obj_handle( params->hStdError );
968 info->x = params->dwX;
969 info->y = params->dwY;
970 info->xsize = params->dwXSize;
971 info->ysize = params->dwYSize;
972 info->xchars = params->dwXCountChars;
973 info->ychars = params->dwYCountChars;
974 info->attribute = params->dwFillAttribute;
975 info->flags = params->dwFlags;
976 info->show = params->wShowWindow;
978 ptr = info + 1;
979 info->curdir_len = append_string( &ptr, params, &params->CurrentDirectory.DosPath );
980 info->dllpath_len = append_string( &ptr, params, &params->DllPath );
981 info->imagepath_len = append_string( &ptr, params, &params->ImagePathName );
982 info->cmdline_len = append_string( &ptr, params, &params->CommandLine );
983 info->title_len = append_string( &ptr, params, &params->WindowTitle );
984 info->desktop_len = append_string( &ptr, params, &params->Desktop );
985 info->shellinfo_len = append_string( &ptr, params, &params->ShellInfo );
986 info->runtime_len = append_string( &ptr, params, &params->RuntimeInfo );
987 return info;
991 /***********************************************************************
992 * get_alternate_loader
994 * Get the name of the alternate (32 or 64 bit) Wine loader.
996 static const char *get_alternate_loader( char **ret_env )
998 char *env;
999 const char *loader = NULL;
1000 const char *loader_env = getenv( "WINELOADER" );
1002 *ret_env = NULL;
1004 if (wine_get_build_dir()) loader = is_win64 ? "loader/wine" : "loader/wine64";
1006 if (loader_env)
1008 int len = strlen( loader_env );
1009 if (!is_win64)
1011 if (!(env = RtlAllocateHeap( GetProcessHeap(), 0, sizeof("WINELOADER=") + len + 2 ))) return NULL;
1012 strcpy( env, "WINELOADER=" );
1013 strcat( env, loader_env );
1014 strcat( env, "64" );
1016 else
1018 if (!(env = RtlAllocateHeap( GetProcessHeap(), 0, sizeof("WINELOADER=") + len ))) return NULL;
1019 strcpy( env, "WINELOADER=" );
1020 strcat( env, loader_env );
1021 len += sizeof("WINELOADER=") - 1;
1022 if (!strcmp( env + len - 2, "64" )) env[len - 2] = 0;
1024 if (!loader)
1026 if ((loader = strrchr( env, '/' ))) loader++;
1027 else loader = env;
1029 *ret_env = env;
1031 if (!loader) loader = is_win64 ? "wine" : "wine64";
1032 return loader;
1036 /***********************************************************************
1037 * set_stdio_fd
1039 static void set_stdio_fd( int stdin_fd, int stdout_fd )
1041 int fd = -1;
1043 if (stdin_fd == -1 || stdout_fd == -1)
1045 fd = open( "/dev/null", O_RDWR );
1046 if (stdin_fd == -1) stdin_fd = fd;
1047 if (stdout_fd == -1) stdout_fd = fd;
1050 dup2( stdin_fd, 0 );
1051 dup2( stdout_fd, 1 );
1052 if (fd != -1) close( fd );
1056 /***********************************************************************
1057 * spawn_loader
1059 static NTSTATUS spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd,
1060 const char *unixdir, char *winedebug, const pe_image_info_t *pe_info )
1062 pid_t pid;
1063 int stdin_fd = -1, stdout_fd = -1;
1064 char *wineloader = NULL;
1065 const char *loader = NULL;
1066 char **argv;
1067 NTSTATUS status = STATUS_SUCCESS;
1069 argv = build_argv( &params->CommandLine, 1 );
1071 if (!is_win64 ^ !is_64bit_arch( pe_info->cpu ))
1072 loader = get_alternate_loader( &wineloader );
1074 wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL );
1075 wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL );
1077 if (!(pid = fork())) /* child */
1079 if (!(pid = fork())) /* grandchild */
1081 char preloader_reserve[64], socket_env[64];
1082 ULONGLONG res_start = pe_info->base;
1083 ULONGLONG res_end = pe_info->base + pe_info->map_size;
1085 if (params->ConsoleFlags ||
1086 params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ ||
1087 (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
1089 setsid();
1090 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
1092 else set_stdio_fd( stdin_fd, stdout_fd );
1094 if (stdin_fd != -1) close( stdin_fd );
1095 if (stdout_fd != -1) close( stdout_fd );
1097 /* Reset signals that we previously set to SIG_IGN */
1098 signal( SIGPIPE, SIG_DFL );
1100 sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd );
1101 sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x",
1102 (ULONG)(res_start >> 32), (ULONG)res_start, (ULONG)(res_end >> 32), (ULONG)res_end );
1104 putenv( preloader_reserve );
1105 putenv( socket_env );
1106 if (winedebug) putenv( winedebug );
1107 if (wineloader) putenv( wineloader );
1108 if (unixdir) chdir( unixdir );
1110 if (argv) wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
1111 _exit(1);
1114 _exit(pid == -1);
1117 if (pid != -1)
1119 /* reap child */
1120 pid_t wret;
1121 do {
1122 wret = waitpid(pid, NULL, 0);
1123 } while (wret < 0 && errno == EINTR);
1125 else status = FILE_GetNtStatus();
1127 if (stdin_fd != -1) close( stdin_fd );
1128 if (stdout_fd != -1) close( stdout_fd );
1129 RtlFreeHeap( GetProcessHeap(), 0, wineloader );
1130 RtlFreeHeap( GetProcessHeap(), 0, argv );
1131 return status;
1135 /***********************************************************************
1136 * get_pe_file_info
1138 static NTSTATUS get_pe_file_info( UNICODE_STRING *path, ULONG attributes,
1139 HANDLE *handle, pe_image_info_t *info )
1141 NTSTATUS status;
1142 HANDLE mapping;
1143 OBJECT_ATTRIBUTES attr;
1144 IO_STATUS_BLOCK io;
1146 InitializeObjectAttributes( &attr, path, attributes, 0, 0 );
1147 if ((status = NtOpenFile( handle, GENERIC_READ, &attr, &io,
1148 FILE_SHARE_READ | FILE_SHARE_DELETE, 0 ))) return status;
1150 if (!(status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
1151 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
1152 NULL, NULL, PAGE_EXECUTE_READ, SEC_IMAGE, *handle )))
1154 SERVER_START_REQ( get_mapping_info )
1156 req->handle = wine_server_obj_handle( mapping );
1157 req->access = SECTION_QUERY;
1158 wine_server_set_reply( req, info, sizeof(*info) );
1159 status = wine_server_call( req );
1161 SERVER_END_REQ;
1162 NtClose( mapping );
1164 return status;
1168 /***********************************************************************
1169 * get_env_size
1171 static ULONG get_env_size( const RTL_USER_PROCESS_PARAMETERS *params, char **winedebug )
1173 WCHAR *ptr = params->Environment;
1175 while (*ptr)
1177 static const WCHAR WINEDEBUG[] = {'W','I','N','E','D','E','B','U','G','=',0};
1178 if (!*winedebug && !strncmpW( ptr, WINEDEBUG, ARRAY_SIZE( WINEDEBUG ) - 1 ))
1180 DWORD len = ntdll_wcstoumbs( 0, ptr, strlenW(ptr) + 1, NULL, 0, NULL, NULL );
1181 if ((*winedebug = RtlAllocateHeap( GetProcessHeap(), 0, len )))
1182 ntdll_wcstoumbs( 0, ptr, strlenW(ptr) + 1, *winedebug, len, NULL, NULL );
1184 ptr += strlenW(ptr) + 1;
1186 ptr++;
1187 return (ptr - params->Environment) * sizeof(WCHAR);
1191 /***********************************************************************
1192 * get_unix_curdir
1194 static char *get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params )
1196 UNICODE_STRING nt_name;
1197 ANSI_STRING unix_name;
1198 NTSTATUS status;
1200 if (!RtlDosPathNameToNtPathName_U( params->CurrentDirectory.DosPath.Buffer, &nt_name, NULL, NULL ))
1201 return NULL;
1202 status = wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN_IF, FALSE );
1203 RtlFreeUnicodeString( &nt_name );
1204 if (status && status != STATUS_NO_SUCH_FILE) return NULL;
1205 return unix_name.Buffer;
1209 /**********************************************************************
1210 * RtlCreateUserProcess (NTDLL.@)
1212 NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes,
1213 RTL_USER_PROCESS_PARAMETERS *params,
1214 SECURITY_DESCRIPTOR *process_descr,
1215 SECURITY_DESCRIPTOR *thread_descr,
1216 HANDLE parent, BOOLEAN inherit, HANDLE debug, HANDLE exception,
1217 RTL_USER_PROCESS_INFORMATION *info )
1219 NTSTATUS status;
1220 BOOL success = FALSE;
1221 HANDLE file_handle, process_info = 0, process_handle = 0, thread_handle = 0;
1222 ULONG process_id, thread_id;
1223 struct object_attributes *objattr;
1224 data_size_t attr_len;
1225 char *unixdir = NULL, *winedebug = NULL;
1226 startup_info_t *startup_info = NULL;
1227 ULONG startup_info_size, env_size;
1228 int err, socketfd[2] = { -1, -1 };
1229 OBJECT_ATTRIBUTES attr;
1230 pe_image_info_t pe_info;
1232 RtlNormalizeProcessParams( params );
1234 TRACE( "%s image %s cmdline %s\n", debugstr_us( path ),
1235 debugstr_us( &params->ImagePathName ), debugstr_us( &params->CommandLine ));
1237 if ((status = get_pe_file_info( path, attributes, &file_handle, &pe_info ))) goto done;
1238 if (!(startup_info = create_startup_info( params, &startup_info_size ))) goto done;
1239 env_size = get_env_size( params, &winedebug );
1240 unixdir = get_unix_curdir( params );
1242 InitializeObjectAttributes( &attr, NULL, 0, NULL, process_descr );
1243 if ((status = alloc_object_attributes( &attr, &objattr, &attr_len ))) goto done;
1245 /* create the socket for the new process */
1247 if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
1249 status = STATUS_TOO_MANY_OPENED_FILES;
1250 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1251 goto done;
1253 #ifdef SO_PASSCRED
1254 else
1256 int enable = 1;
1257 setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
1259 #endif
1261 wine_server_send_fd( socketfd[1] );
1262 close( socketfd[1] );
1264 /* create the process on the server side */
1266 SERVER_START_REQ( new_process )
1268 req->inherit_all = inherit;
1269 req->create_flags = 0;
1270 req->socket_fd = socketfd[1];
1271 req->exe_file = wine_server_obj_handle( file_handle );
1272 req->access = PROCESS_ALL_ACCESS;
1273 req->cpu = pe_info.cpu;
1274 req->info_size = startup_info_size;
1275 wine_server_add_data( req, objattr, attr_len );
1276 wine_server_add_data( req, startup_info, startup_info_size );
1277 wine_server_add_data( req, params->Environment, env_size );
1278 if (!(status = wine_server_call( req )))
1280 process_id = reply->pid;
1281 process_handle = wine_server_ptr_handle( reply->handle );
1283 process_info = wine_server_ptr_handle( reply->info );
1285 SERVER_END_REQ;
1286 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1288 if (status)
1290 switch (status)
1292 case STATUS_INVALID_IMAGE_WIN_64:
1293 ERR( "64-bit application %s not supported in 32-bit prefix\n",
1294 debugstr_us( &params->ImagePathName ));
1295 break;
1296 case STATUS_INVALID_IMAGE_FORMAT:
1297 ERR( "%s not supported on this installation (%s binary)\n",
1298 debugstr_us( &params->ImagePathName ), cpu_names[pe_info.cpu] );
1299 break;
1301 goto done;
1304 InitializeObjectAttributes( &attr, NULL, 0, NULL, thread_descr );
1305 if ((status = alloc_object_attributes( &attr, &objattr, &attr_len ))) goto done;
1307 SERVER_START_REQ( new_thread )
1309 req->process = wine_server_obj_handle( process_handle );
1310 req->access = THREAD_ALL_ACCESS;
1311 req->suspend = 1;
1312 req->request_fd = -1;
1313 wine_server_add_data( req, objattr, attr_len );
1314 if (!(status = wine_server_call( req )))
1316 thread_handle = wine_server_ptr_handle( reply->handle );
1317 thread_id = reply->tid;
1320 SERVER_END_REQ;
1321 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1322 if (status) goto done;
1324 /* create the child process */
1326 if ((status = spawn_loader( params, socketfd[0], unixdir, winedebug, &pe_info ))) goto done;
1328 close( socketfd[0] );
1329 socketfd[0] = -1;
1331 /* wait for the new process info to be ready */
1333 NtWaitForSingleObject( process_info, FALSE, NULL );
1334 SERVER_START_REQ( get_new_process_info )
1336 req->info = wine_server_obj_handle( process_info );
1337 wine_server_call( req );
1338 success = reply->success;
1339 err = reply->exit_code;
1341 SERVER_END_REQ;
1343 if (success)
1345 TRACE( "%s pid %04x tid %04x handles %p/%p\n", debugstr_us( path ),
1346 process_id, thread_id, process_handle, thread_handle );
1347 info->Process = process_handle;
1348 info->Thread = thread_handle;
1349 info->ClientId.UniqueProcess = ULongToHandle( process_id );
1350 info->ClientId.UniqueThread = ULongToHandle( thread_id );
1351 virtual_fill_image_information( &pe_info, &info->ImageInformation );
1352 process_handle = thread_handle = 0;
1353 status = STATUS_SUCCESS;
1355 else status = err ? err : ERROR_INTERNAL_ERROR;
1357 done:
1358 NtClose( file_handle );
1359 if (process_info) NtClose( process_info );
1360 if (process_handle) NtClose( process_handle );
1361 if (thread_handle) NtClose( thread_handle );
1362 if (socketfd[0] != -1) close( socketfd[0] );
1363 RtlFreeHeap( GetProcessHeap(), 0, startup_info );
1364 RtlFreeHeap( GetProcessHeap(), 0, winedebug );
1365 RtlFreeHeap( GetProcessHeap(), 0, unixdir );
1366 return status;
1369 /***********************************************************************
1370 * DbgUiRemoteBreakin (NTDLL.@)
1372 void WINAPI DbgUiRemoteBreakin( void *arg )
1374 TRACE( "\n" );
1375 if (NtCurrentTeb()->Peb->BeingDebugged) DbgBreakPoint();
1376 RtlExitUserThread( STATUS_SUCCESS );
1379 /***********************************************************************
1380 * DbgUiIssueRemoteBreakin (NTDLL.@)
1382 NTSTATUS WINAPI DbgUiIssueRemoteBreakin( HANDLE process )
1384 apc_call_t call;
1385 apc_result_t result;
1386 NTSTATUS status;
1388 TRACE( "(%p)\n", process );
1390 memset( &call, 0, sizeof(call) );
1392 call.type = APC_BREAK_PROCESS;
1393 status = server_queue_process_apc( process, &call, &result );
1394 if (status) return status;
1395 return result.break_process.status;