mirror of
https://github.com/reactos/reactos.git
synced 2024-11-10 00:34:39 +00:00
251 lines
5.2 KiB
C
251 lines
5.2 KiB
C
|
/* $Id: fork.c,v 1.3 2002/10/29 04:45:46 rex Exp $
|
||
|
*/
|
||
|
/*
|
||
|
* COPYRIGHT: See COPYING in the top level directory
|
||
|
* PROJECT: ReactOS POSIX+ Subsystem
|
||
|
* FILE: subsys/psx/lib/psxdll/unistd/fork.c
|
||
|
* PURPOSE: create a new process
|
||
|
* PROGRAMMER: KJK::Hyperion <noog@libero.it>
|
||
|
* UPDATE HISTORY:
|
||
|
* 14/05/2002: Created
|
||
|
*/
|
||
|
|
||
|
#include <ddk/ntddk.h>
|
||
|
#include <napi/teb.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <stddef.h>
|
||
|
#include <unistd.h>
|
||
|
#include <errno.h>
|
||
|
#include <psx/debug.h>
|
||
|
#include <psx/errno.h>
|
||
|
|
||
|
#include <windows.h>
|
||
|
|
||
|
typedef struct _PORT_MESSAGE {
|
||
|
USHORT DataSize;
|
||
|
USHORT MessageSize;
|
||
|
USHORT MessageType;
|
||
|
USHORT VirtualRangesOffset;
|
||
|
CLIENT_ID ClientId;
|
||
|
ULONG MessageId;
|
||
|
ULONG SectionSize;
|
||
|
/* UCHAR Data[]; */
|
||
|
} PORT_MESSAGE, *PPORT_MESSAGE;
|
||
|
|
||
|
struct CSRSS_MESSAGE {
|
||
|
ULONG Unknown1;
|
||
|
ULONG Opcode;
|
||
|
ULONG Status;
|
||
|
ULONG Unknown2;
|
||
|
};
|
||
|
|
||
|
NTSTATUS STDCALL CsrClientCallServer(
|
||
|
IN PVOID Message,
|
||
|
IN PVOID Unknown,
|
||
|
IN ULONG Opcode,
|
||
|
IN ULONG Size
|
||
|
);
|
||
|
|
||
|
pid_t fork(void)
|
||
|
{
|
||
|
NTSTATUS nErrCode;
|
||
|
CONTEXT ctxThreadContext;
|
||
|
HANDLE hProcess;
|
||
|
HANDLE hThread;
|
||
|
INITIAL_TEB itInitialTeb;
|
||
|
CLIENT_ID ciClientId;
|
||
|
MEMORY_BASIC_INFORMATION mbiStackInfo;
|
||
|
THREAD_BASIC_INFORMATION tbiThreadInfo;
|
||
|
|
||
|
struct __tagcsrmsg{
|
||
|
PORT_MESSAGE PortMessage;
|
||
|
struct CSRSS_MESSAGE CsrssMessage;
|
||
|
PROCESS_INFORMATION ProcessInformation;
|
||
|
CLIENT_ID Debugger;
|
||
|
ULONG CreationFlags;
|
||
|
ULONG VdmInfo[2];
|
||
|
} csrmsg;
|
||
|
|
||
|
/* STEP 1: Duplicate current process */
|
||
|
nErrCode = NtCreateProcess
|
||
|
(
|
||
|
&hProcess,
|
||
|
PROCESS_ALL_ACCESS,
|
||
|
NULL,
|
||
|
NtCurrentProcess(),
|
||
|
TRUE,
|
||
|
0,
|
||
|
0,
|
||
|
0
|
||
|
);
|
||
|
|
||
|
/* failure */
|
||
|
if(!NT_SUCCESS(nErrCode))
|
||
|
{
|
||
|
ERR("NtCreateProcess() failed with status 0x%08X\n", nErrCode);
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
/* STEP 2: Duplicate current thread */
|
||
|
/* 2.1: duplicate registers */
|
||
|
ctxThreadContext.ContextFlags =
|
||
|
CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT;
|
||
|
|
||
|
/* get the current thread's registers */
|
||
|
nErrCode = NtGetContextThread(NtCurrentThread(), &ctxThreadContext);
|
||
|
|
||
|
/* failure */
|
||
|
if(!NT_SUCCESS(nErrCode))
|
||
|
{
|
||
|
ERR("NtGetContextThread() failed with status 0x%08X\n", nErrCode);
|
||
|
goto cleanup_and_fail;
|
||
|
}
|
||
|
|
||
|
/* redirect the child process to the child_branch label (see 4.3 below) */
|
||
|
ctxThreadContext.Eip = (ULONG)&&child_branch;
|
||
|
|
||
|
/* 2.2: duplicate stack */
|
||
|
/* get stack base and size */
|
||
|
nErrCode = NtQueryVirtualMemory
|
||
|
(
|
||
|
NtCurrentProcess(),
|
||
|
(PVOID)ctxThreadContext.Esp,
|
||
|
MemoryBasicInformation,
|
||
|
&mbiStackInfo,
|
||
|
sizeof(mbiStackInfo),
|
||
|
0
|
||
|
);
|
||
|
|
||
|
/* failure */
|
||
|
if(!NT_SUCCESS(nErrCode))
|
||
|
{
|
||
|
ERR("NtQueryVirtualMemory() failed with status 0x%08X\n", nErrCode);
|
||
|
goto cleanup_and_fail;
|
||
|
}
|
||
|
|
||
|
itInitialTeb.StackCommit = 0;
|
||
|
itInitialTeb.StackReserve = 0;
|
||
|
itInitialTeb.StackBase = (PVOID)((ULONG)(mbiStackInfo.BaseAddress) + mbiStackInfo.RegionSize);
|
||
|
itInitialTeb.StackLimit = mbiStackInfo.BaseAddress;
|
||
|
itInitialTeb.StackAllocate = mbiStackInfo.AllocationBase;
|
||
|
|
||
|
/* 2.3: create duplicate thread */
|
||
|
nErrCode = NtCreateThread
|
||
|
(
|
||
|
&hThread,
|
||
|
THREAD_ALL_ACCESS,
|
||
|
NULL,
|
||
|
hProcess,
|
||
|
(CLIENT_ID *)&ciClientId,
|
||
|
&ctxThreadContext,
|
||
|
&itInitialTeb,
|
||
|
TRUE
|
||
|
);
|
||
|
|
||
|
/* failure */
|
||
|
if(!NT_SUCCESS(nErrCode))
|
||
|
{
|
||
|
ERR("NtCreateThread() failed with status 0x%08X\n", nErrCode);
|
||
|
goto cleanup_and_fail;
|
||
|
}
|
||
|
|
||
|
/* 2.4: duplicate the TEB */
|
||
|
/* store the client id in the child thread's stack (see 4.3b) */
|
||
|
nErrCode = NtWriteVirtualMemory
|
||
|
(
|
||
|
hProcess,
|
||
|
&ciClientId,
|
||
|
&ciClientId,
|
||
|
sizeof(ciClientId),
|
||
|
0
|
||
|
);
|
||
|
|
||
|
/* failure */
|
||
|
if(!NT_SUCCESS(nErrCode))
|
||
|
{
|
||
|
ERR("NtWriteVirtualMemory() failed with status 0x%08X\n", nErrCode);
|
||
|
goto cleanup_and_fail;
|
||
|
}
|
||
|
|
||
|
/* get the child thread's TEB base */
|
||
|
nErrCode = NtQueryInformationThread
|
||
|
(
|
||
|
hThread,
|
||
|
ThreadBasicInformation,
|
||
|
&tbiThreadInfo,
|
||
|
sizeof(tbiThreadInfo),
|
||
|
0
|
||
|
);
|
||
|
|
||
|
/* failure */
|
||
|
if(!NT_SUCCESS(nErrCode))
|
||
|
{
|
||
|
ERR("NtQueryInformationThread() failed with status 0x%08X\n", nErrCode);
|
||
|
goto cleanup_and_fail;
|
||
|
}
|
||
|
|
||
|
/* copy the TEB */
|
||
|
nErrCode = NtWriteVirtualMemory
|
||
|
(
|
||
|
hProcess,
|
||
|
tbiThreadInfo.TebBaseAddress,
|
||
|
NtCurrentTeb(),
|
||
|
sizeof(TEB),
|
||
|
0
|
||
|
);
|
||
|
|
||
|
/* failure */
|
||
|
if(!NT_SUCCESS(nErrCode))
|
||
|
{
|
||
|
ERR("NtWriteVirtualMemory() failed with status 0x%08X\n", nErrCode);
|
||
|
goto cleanup_and_fail;
|
||
|
}
|
||
|
|
||
|
/* STEP 3: Call Win32 subsystem */
|
||
|
memset(&csrmsg, 0, sizeof(csrmsg));
|
||
|
|
||
|
csrmsg.ProcessInformation.hProcess = hProcess;
|
||
|
csrmsg.ProcessInformation.hThread = hThread;
|
||
|
csrmsg.ProcessInformation.dwProcessId = (DWORD)ciClientId.UniqueProcess;
|
||
|
csrmsg.ProcessInformation.dwThreadId = (DWORD)ciClientId.UniqueThread;
|
||
|
|
||
|
nErrCode = CsrClientCallServer(&csrmsg, 0, 0x10000, 0x24);
|
||
|
|
||
|
/* failure */
|
||
|
if(!NT_SUCCESS(nErrCode))
|
||
|
{
|
||
|
ERR("CsrClientCallServer() failed with status 0x%08X\n", nErrCode);
|
||
|
goto cleanup_and_fail;
|
||
|
}
|
||
|
|
||
|
/* STEP 4: Finalization */
|
||
|
/* 4.1: resume thread */
|
||
|
nErrCode = NtResumeThread(hThread, 0);
|
||
|
|
||
|
/* 4.2: close superfluous handles */
|
||
|
NtClose(hProcess);
|
||
|
NtClose(hThread);
|
||
|
|
||
|
/* 4.3: (parent) return the child process id */
|
||
|
return ((pid_t)(ciClientId.UniqueProcess));
|
||
|
|
||
|
/* 4.3b: (child) cleanup and return 0 */
|
||
|
child_branch:
|
||
|
/* restore the thread and process id in the TEB */
|
||
|
memcpy(&NtCurrentTeb()->Cid, &ciClientId, sizeof(ciClientId));
|
||
|
|
||
|
/* return 0 */
|
||
|
return (0);
|
||
|
|
||
|
cleanup_and_fail:
|
||
|
NtTerminateProcess(hProcess, nErrCode);
|
||
|
|
||
|
fail:
|
||
|
errno = __status_to_errno(nErrCode);
|
||
|
return (-1);
|
||
|
|
||
|
}
|
||
|
|
||
|
/* EOF */
|
||
|
|