1266 lines
28 KiB
C
1266 lines
28 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1989 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
dllproc.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements POSIX process structure APIs
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Mark Lucovsky (markl) 27-Jun-1989
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include <sys\utsname.h>
|
||
|
#include <unistd.h>
|
||
|
#include <time.h>
|
||
|
#include <string.h>
|
||
|
#include <stdarg.h>
|
||
|
|
||
|
#ifdef _ALPHA_
|
||
|
#include "psxalpha.h"
|
||
|
#endif
|
||
|
#ifdef _MIPS_
|
||
|
#include "psxmips.h"
|
||
|
#endif
|
||
|
#ifdef _PPC_
|
||
|
#include "psxppc.h"
|
||
|
#endif
|
||
|
#ifdef _X86_
|
||
|
#include "psxi386.h"
|
||
|
#endif
|
||
|
#ifdef _IA64_
|
||
|
#include "psxia64.h"
|
||
|
#endif
|
||
|
|
||
|
#include "psxdll.h"
|
||
|
|
||
|
void
|
||
|
__cdecl
|
||
|
_exit(int status)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_EXIT_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.Exit;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxExitApi, sizeof(*args));
|
||
|
|
||
|
args->ExitStatus = (ULONG)status;
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
if (!NT_SUCCESS(st)) {
|
||
|
KdPrint(("PSXDLL: _exit: 0x%x\n", st));
|
||
|
}
|
||
|
#endif
|
||
|
NtTerminateProcess(NtCurrentProcess(), 0);
|
||
|
}
|
||
|
|
||
|
gid_t
|
||
|
__cdecl
|
||
|
getegid(void)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_GETIDS_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.GetIds;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args));
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
return args->EffectiveGid;
|
||
|
}
|
||
|
|
||
|
gid_t
|
||
|
__cdecl
|
||
|
getgid(void)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_GETIDS_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.GetIds;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args));
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
return args->RealGid;
|
||
|
}
|
||
|
|
||
|
uid_t
|
||
|
__cdecl
|
||
|
geteuid(void)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_GETIDS_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.GetIds;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args));
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
return args->EffectiveUid;
|
||
|
}
|
||
|
|
||
|
uid_t
|
||
|
__cdecl
|
||
|
getuid(void)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_GETIDS_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.GetIds;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args));
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
return args->RealUid;
|
||
|
}
|
||
|
|
||
|
pid_t
|
||
|
__cdecl
|
||
|
getppid(void)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_GETIDS_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.GetIds;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args));
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
return args->ParentPid;
|
||
|
}
|
||
|
|
||
|
pid_t
|
||
|
__cdecl
|
||
|
getpid(void)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_GETIDS_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.GetIds;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args));
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
return args->Pid;
|
||
|
}
|
||
|
|
||
|
pid_t
|
||
|
__cdecl
|
||
|
getpgrp(void)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_GETIDS_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.GetIds;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args));
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
return args->GroupId;
|
||
|
}
|
||
|
|
||
|
pid_t
|
||
|
__cdecl
|
||
|
setsid(void)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxSetSidApi, 0);
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
if (m.Error) {
|
||
|
errno = m.Error;
|
||
|
return -1;
|
||
|
}
|
||
|
return (pid_t)m.ReturnValue;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
__cdecl
|
||
|
setpgid(pid_t pid, pid_t pgid)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_SETPGROUPID_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.SetPGroupId;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxSetPGroupIdApi, sizeof(*args));
|
||
|
|
||
|
args->Pid = pid;
|
||
|
args->Pgid = pgid;
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
if (m.Error) {
|
||
|
errno = (int)m.Error;
|
||
|
return -1;
|
||
|
}
|
||
|
return (int)m.ReturnValue;
|
||
|
}
|
||
|
|
||
|
pid_t
|
||
|
__cdecl
|
||
|
waitpid(pid_t pid, int *stat_loc, int options)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_WAITPID_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.WaitPid;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxWaitPidApi, sizeof(*args));
|
||
|
|
||
|
args->Pid = pid;
|
||
|
args->Options = options;
|
||
|
|
||
|
for (;;) {
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
if (!NT_SUCCESS(st)) {
|
||
|
KdPrint(("PSXDLL: waitpid: 0x%x\n", st));
|
||
|
}
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
|
||
|
if (EINTR == m.Error && SIGCONT == m.Signal) {
|
||
|
// We were stopped and then continued. Continue
|
||
|
// waiting.
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxWaitPidApi, sizeof(*args));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (m.Error) {
|
||
|
errno = (int)m.Error;
|
||
|
return -1;
|
||
|
}
|
||
|
if (NULL != stat_loc) {
|
||
|
try {
|
||
|
*stat_loc = args->StatLocValue;
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
errno = EFAULT;
|
||
|
m.ReturnValue = (ULONG)-1;
|
||
|
}
|
||
|
}
|
||
|
return (int)m.ReturnValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pid_t
|
||
|
__cdecl
|
||
|
wait(int *stat_loc)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_WAITPID_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.WaitPid;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxWaitPidApi, sizeof(*args));
|
||
|
|
||
|
args->Pid = (pid_t)-1;
|
||
|
args->Options = (pid_t)0;
|
||
|
|
||
|
for (;;) {
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
if (!NT_SUCCESS(st)) {
|
||
|
KdPrint(("PSXDLL: wait: NtRequest: 0x%x\n", st));
|
||
|
}
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
|
||
|
if (EINTR == m.Error && SIGCONT == m.Signal) {
|
||
|
// We were stopped and continued. Continue waiting.
|
||
|
PSX_FORMAT_API_MSG(m, PsxWaitPidApi, sizeof(*args));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (m.Error) {
|
||
|
errno = (int)m.Error;
|
||
|
return -1;
|
||
|
}
|
||
|
if (ARGUMENT_PRESENT(stat_loc)) {
|
||
|
try {
|
||
|
*stat_loc = args->StatLocValue;
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
errno = EFAULT;
|
||
|
m.ReturnValue = (ULONG)-1;
|
||
|
}
|
||
|
}
|
||
|
return (int)m.ReturnValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pid_t
|
||
|
__cdecl
|
||
|
fork(void)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
NTSTATUS st;
|
||
|
PPSX_FORK_MSG args;
|
||
|
PTEB ThreadInfo;
|
||
|
|
||
|
args = &m.u.Fork;
|
||
|
|
||
|
again:
|
||
|
PSX_FORMAT_API_MSG(m, PsxForkApi, sizeof(*args));
|
||
|
|
||
|
ThreadInfo = NtCurrentTeb();
|
||
|
args->StackBase = ThreadInfo->NtTib.StackBase;
|
||
|
args->StackLimit = ThreadInfo->NtTib.StackLimit;
|
||
|
args->StackAllocationBase = ThreadInfo->DeallocationStack;
|
||
|
#ifdef _IA64_
|
||
|
args->BStoreLimit = ThreadInfo->BStoreLimit;
|
||
|
#endif
|
||
|
|
||
|
try {
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
KdPrint(("PSXDLL: fork: took an exception\n"));
|
||
|
KdPrint(("PSXDLL: exception is 0x%x\n", GetExceptionCode()));
|
||
|
}
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
|
||
|
if (st == PSX_FORK_RETURN) {
|
||
|
st = PsxConnectToServer();
|
||
|
if (!NT_SUCCESS(st)) {
|
||
|
KdPrint(("PsxConnectToServer: 0x%x\n", st));
|
||
|
NtTerminateProcess(NtCurrentProcess(), 1);
|
||
|
ASSERT(0);
|
||
|
}
|
||
|
|
||
|
// take any pending signals now.
|
||
|
PdxNullPosixApi();
|
||
|
return 0;
|
||
|
}
|
||
|
if (EINTR == m.Error) {
|
||
|
// try again.
|
||
|
goto again;
|
||
|
}
|
||
|
|
||
|
if (m.Error) {
|
||
|
errno = (int)m.Error;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return (int)m.ReturnValue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// vexec -- Varargs exec program, called by execl*.
|
||
|
//
|
||
|
|
||
|
int
|
||
|
vexec(const char *path, const char *arg0, char * const envp[], va_list arglist)
|
||
|
{
|
||
|
NTSTATUS st;
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_EXEC_MSG args;
|
||
|
|
||
|
char **ppch;
|
||
|
char *pch, *pcharg;
|
||
|
int i;
|
||
|
int retval = 0;
|
||
|
char *Args; // the args + env for the call
|
||
|
|
||
|
va_list save_arglist;
|
||
|
|
||
|
try {
|
||
|
if (0 == *path) {
|
||
|
errno = ENOENT;
|
||
|
return -1;
|
||
|
}
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
errno = EFAULT;
|
||
|
retval = -1;
|
||
|
}
|
||
|
if (0 != retval) {
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
args = &m.u.Exec;
|
||
|
PSX_FORMAT_API_MSG(m, PsxExecApi, sizeof(*args));
|
||
|
|
||
|
if (!PdxCanonicalize((PSZ)path, &args->Path, PdxHeap)) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
Args = RtlAllocateHeap(PdxPortHeap, 0, ARG_MAX);
|
||
|
if (NULL == Args) {
|
||
|
errno = ENOMEM;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
args->Args = Args + PsxPortMemoryRemoteDelta;
|
||
|
|
||
|
//
|
||
|
// Port Memory Setup is same as for execve, see below.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// first we count the strings so we know how much space to leave
|
||
|
// for pointers.
|
||
|
//
|
||
|
|
||
|
save_arglist = arglist;
|
||
|
|
||
|
for (i = 0, pcharg = va_arg(arglist, char *); NULL != pcharg;
|
||
|
pcharg = va_arg(arglist, char *)) {
|
||
|
++i;
|
||
|
}
|
||
|
++i; // add one for arg0
|
||
|
for (ppch = (char **)envp; NULL != *ppch; ++ppch)
|
||
|
++i;
|
||
|
i += 2; // add space for the NULL pointers
|
||
|
|
||
|
pch = Args + sizeof(char *) * i;
|
||
|
|
||
|
if (pch > Args + ARG_MAX) {
|
||
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args);
|
||
|
errno = E2BIG;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
ppch = (char **)Args;
|
||
|
|
||
|
arglist = save_arglist; // restart arglist
|
||
|
|
||
|
try {
|
||
|
pcharg = (char *)arg0;
|
||
|
while (NULL != pcharg) {
|
||
|
if (pch + strlen(pcharg) + 1 > Args + ARG_MAX) {
|
||
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args);
|
||
|
errno = E2BIG;
|
||
|
return -1;
|
||
|
}
|
||
|
*ppch = pch - (ULONG_PTR)Args;
|
||
|
ppch++;
|
||
|
(void)strcpy(pch, pcharg);
|
||
|
pcharg = va_arg(arglist, char *);
|
||
|
|
||
|
pch += strlen(pch);
|
||
|
*pch++ = '\0';
|
||
|
}
|
||
|
*ppch = NULL;
|
||
|
ppch++;
|
||
|
|
||
|
while (NULL != *envp) {
|
||
|
if (pch + strlen(*envp) + 1 > Args + ARG_MAX) {
|
||
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args);
|
||
|
errno = E2BIG;
|
||
|
return -1;
|
||
|
}
|
||
|
*ppch = pch - (ULONG_PTR)Args;
|
||
|
ppch++;
|
||
|
(void)strcpy(pch, *envp);
|
||
|
envp++;
|
||
|
|
||
|
pch += strlen(pch);
|
||
|
*pch++ = '\0';
|
||
|
}
|
||
|
*ppch = NULL;
|
||
|
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
errno = EFAULT;
|
||
|
retval = -1;
|
||
|
}
|
||
|
if (0 != retval) {
|
||
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
(void)NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
//
|
||
|
// If we get here, there's been an error.
|
||
|
//
|
||
|
|
||
|
errno = (int)m.Error;
|
||
|
RtlFreeHeap(PdxHeap, 0, (PVOID)&args->Path);
|
||
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args);
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
__cdecl
|
||
|
execve(const char *path, char * const argv[], char * const envp[])
|
||
|
{
|
||
|
NTSTATUS st;
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_EXEC_MSG args;
|
||
|
PCHAR Args; // allocate args + environ
|
||
|
|
||
|
char **ppch;
|
||
|
char *pch;
|
||
|
int i;
|
||
|
int retval = 0;
|
||
|
|
||
|
try {
|
||
|
if (0 == strlen(path)) {
|
||
|
errno = ENOENT;
|
||
|
return -1;
|
||
|
}
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
retval = -1;
|
||
|
errno = EFAULT;
|
||
|
}
|
||
|
if (0 != retval) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
args = &m.u.Exec;
|
||
|
PSX_FORMAT_API_MSG(m, PsxExecApi, sizeof(*args));
|
||
|
|
||
|
if (!PdxCanonicalize((PSZ)path, &args->Path, PdxHeap)) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Copy the caller's environment into view memory so that it may
|
||
|
// be transmitted to the "overlaid" process. We set up the port
|
||
|
// memory to look like:
|
||
|
//
|
||
|
// ClientPortMemory:
|
||
|
// argv[0]
|
||
|
// argv[1]
|
||
|
// ...
|
||
|
// NULL
|
||
|
// envp[0]
|
||
|
// envp[1]
|
||
|
// ...
|
||
|
// NULL
|
||
|
// <argv strings>
|
||
|
// <environ strings>
|
||
|
//
|
||
|
// The argv and envp pointers are converted to offsets relative to
|
||
|
// ClientPortMemory.
|
||
|
//
|
||
|
// Because we need all this memory for args and environ, we destroy
|
||
|
// the heap and recreate it if the call fails.
|
||
|
//
|
||
|
|
||
|
Args = RtlAllocateHeap(PdxPortHeap, 0, ARG_MAX);
|
||
|
if (NULL == Args) {
|
||
|
errno = ENOMEM;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
args->Args = Args + PsxPortMemoryRemoteDelta;
|
||
|
|
||
|
try {
|
||
|
|
||
|
// first we count the strings so we know how much space to leave
|
||
|
// for pointers.
|
||
|
|
||
|
for (i = 0, ppch = (char **)argv; NULL != *ppch; ++ppch)
|
||
|
++i;
|
||
|
for (ppch = (char **)envp; NULL != *ppch; ++ppch)
|
||
|
++i;
|
||
|
i += 2; // add space for the NULL pointers
|
||
|
|
||
|
pch = Args + sizeof(char *) * i;
|
||
|
|
||
|
if (pch > Args + ARG_MAX) {
|
||
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args);
|
||
|
errno = E2BIG;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
ppch = (char **)Args;
|
||
|
|
||
|
while (NULL != *argv) {
|
||
|
if (pch + strlen(*argv) + 1 > Args + ARG_MAX) {
|
||
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args);
|
||
|
errno = E2BIG;
|
||
|
return -1;
|
||
|
}
|
||
|
*ppch = pch - (ULONG_PTR)Args;
|
||
|
ppch++;
|
||
|
(void)strcpy(pch, *argv);
|
||
|
argv++;
|
||
|
|
||
|
pch += strlen(pch);
|
||
|
*pch++ = '\0';
|
||
|
}
|
||
|
*ppch = NULL;
|
||
|
ppch++;
|
||
|
|
||
|
while (NULL != *envp) {
|
||
|
if (pch + strlen(*envp) + 1 > Args + ARG_MAX) {
|
||
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args);
|
||
|
errno = E2BIG;
|
||
|
return -1;
|
||
|
}
|
||
|
*ppch = pch - (ULONG_PTR)Args;
|
||
|
ppch++;
|
||
|
(void)strcpy(pch, *envp);
|
||
|
envp++;
|
||
|
|
||
|
pch += strlen(pch);
|
||
|
*pch++ = '\0';
|
||
|
}
|
||
|
*ppch = NULL;
|
||
|
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
retval = -1;
|
||
|
errno = EFAULT;
|
||
|
}
|
||
|
if (0 != retval) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
(void)NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
//
|
||
|
// If we get here, there's been an error.
|
||
|
//
|
||
|
|
||
|
errno = (int)m.Error;
|
||
|
RtlFreeHeap(PdxHeap, 0, (PVOID)&args->Path);
|
||
|
RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args);
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
__cdecl
|
||
|
execv(const char *path, char * const argv[])
|
||
|
{
|
||
|
return execve(path, argv, environ);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
__cdecl
|
||
|
execl(const char *path, const char *arg0, ...)
|
||
|
{
|
||
|
va_list args;
|
||
|
int retval;
|
||
|
|
||
|
va_start(args, arg0);
|
||
|
|
||
|
retval = vexec(path, arg0, environ, args);
|
||
|
|
||
|
va_end(args);
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
__cdecl
|
||
|
execle(const char *path, const char *arg0, ...)
|
||
|
{
|
||
|
va_list args;
|
||
|
char * const *Env;
|
||
|
int retval;
|
||
|
|
||
|
va_start(args, arg0);
|
||
|
|
||
|
// Skip up to the NULL, then one more, to find environ.
|
||
|
|
||
|
do {
|
||
|
Env = va_arg(args, char * const *);
|
||
|
} while (NULL != Env);
|
||
|
|
||
|
Env = va_arg(args, char * const *);
|
||
|
|
||
|
va_end(args);
|
||
|
|
||
|
if (NULL == Env) {
|
||
|
return EINVAL;
|
||
|
}
|
||
|
|
||
|
// Restart the arglist traversal
|
||
|
|
||
|
va_start(args, arg0);
|
||
|
|
||
|
retval = vexec(path, arg0, Env, args);
|
||
|
|
||
|
va_end(args);
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
__cdecl
|
||
|
execlp(const char *file, const char *arg0, ...)
|
||
|
{
|
||
|
char *pch;
|
||
|
char *path;
|
||
|
static char buf[PATH_MAX + 1];
|
||
|
va_list args;
|
||
|
int retval = 0;
|
||
|
BOOLEAN done = FALSE;
|
||
|
|
||
|
va_start(args, arg0);
|
||
|
|
||
|
//
|
||
|
// 1003.1-1990 (3.1.2.2): If the file argument contains a slash
|
||
|
// character, the file argument shall be used as the pathname for
|
||
|
// this file....
|
||
|
//
|
||
|
|
||
|
try {
|
||
|
if ('\0' == *file) {
|
||
|
errno = ENOENT;
|
||
|
va_end(args);
|
||
|
return -1;
|
||
|
}
|
||
|
if (NULL != (pch = strchr(file, '/'))) {
|
||
|
if (-1 == access(file, F_OK)) {
|
||
|
va_end(args);
|
||
|
return -1;
|
||
|
}
|
||
|
retval = vexec(file, arg0, environ, args);
|
||
|
va_end(args);
|
||
|
return retval;
|
||
|
}
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
errno = EFAULT;
|
||
|
retval = -1;
|
||
|
}
|
||
|
if (0 != retval) {
|
||
|
va_end(args);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// ... Otherwise, the path prefix for this file is obtained by a
|
||
|
// search of the directories passed as the environment variable
|
||
|
// PATH.
|
||
|
//
|
||
|
|
||
|
if (NULL == (path = getenv("PATH"))) {
|
||
|
//
|
||
|
// The file name doesn't contain a slash, and we have
|
||
|
// no PATH. We just try for it in the current working
|
||
|
// directory, and will return ENOENT if it's not there.
|
||
|
//
|
||
|
retval = vexec(file, arg0, environ, args);
|
||
|
va_end(args);
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
errno = 0;
|
||
|
do {
|
||
|
pch = strchr(path, ':');
|
||
|
if (NULL == pch) {
|
||
|
done = TRUE;
|
||
|
} else {
|
||
|
*pch = '\0';
|
||
|
}
|
||
|
if (strlen(path) + strlen(file) + 1 > PATH_MAX) {
|
||
|
if (pch) {
|
||
|
*pch = ':';
|
||
|
}
|
||
|
errno = ENAMETOOLONG;
|
||
|
va_end(args);
|
||
|
return -1;
|
||
|
}
|
||
|
strcpy(buf, path);
|
||
|
if (!done) {
|
||
|
*pch = ':';
|
||
|
path = pch + 1;
|
||
|
}
|
||
|
if (strlen(buf) > 0) {
|
||
|
// this case is "::" in the PATH
|
||
|
strcat(buf, "/");
|
||
|
}
|
||
|
strcat(buf, file);
|
||
|
|
||
|
// avoid trying to execute files that do not exist.
|
||
|
|
||
|
if (-1 != access(buf, F_OK)) {
|
||
|
(void)vexec(buf, arg0, environ, args);
|
||
|
break;
|
||
|
}
|
||
|
} while (!done);
|
||
|
|
||
|
va_end(args);
|
||
|
|
||
|
if (0 == errno) {
|
||
|
//
|
||
|
// We went all the way through the PATH without finding
|
||
|
// a file to exec. Since errno didn't get set by execve(),
|
||
|
// we set it here.
|
||
|
//
|
||
|
|
||
|
errno = ENOENT;
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
__cdecl
|
||
|
execvp(const char *file, char * const argv[])
|
||
|
{
|
||
|
char *pch;
|
||
|
char *path;
|
||
|
static char buf[PATH_MAX + 1];
|
||
|
BOOLEAN done = FALSE;
|
||
|
int retval = 0;
|
||
|
|
||
|
//
|
||
|
// 1003.1-1990 (3.1.2.2): If the file argument contains a slash
|
||
|
// character, the file argument shall be used as the pathname for
|
||
|
// this file....
|
||
|
//
|
||
|
|
||
|
try {
|
||
|
if ('\0' == *file) {
|
||
|
errno = ENOENT;
|
||
|
return -1;
|
||
|
}
|
||
|
if (NULL != (pch = strchr(file, '/'))) {
|
||
|
if (-1 == access(file, F_OK)) {
|
||
|
return -1;
|
||
|
}
|
||
|
return execve(file, argv, environ);
|
||
|
}
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
errno = EFAULT;
|
||
|
retval = -1;
|
||
|
}
|
||
|
if (0 != retval) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// ... Otherwise, the path prefix for this file is obtained by a
|
||
|
// search of the directories passed as the environment variable
|
||
|
// PATH.
|
||
|
//
|
||
|
|
||
|
if (NULL == (path = getenv("PATH"))) {
|
||
|
return execve(file, argv, environ);
|
||
|
}
|
||
|
|
||
|
errno = 0;
|
||
|
|
||
|
do {
|
||
|
pch = strchr(path, ':');
|
||
|
if (NULL == pch) {
|
||
|
done = TRUE;
|
||
|
} else {
|
||
|
*pch = '\0';
|
||
|
}
|
||
|
if (strlen(path) + strlen(file) + 1 > PATH_MAX) {
|
||
|
if (pch) {
|
||
|
*pch = ':';
|
||
|
}
|
||
|
errno = ENAMETOOLONG;
|
||
|
return -1;
|
||
|
}
|
||
|
strcpy(buf, path);
|
||
|
if (!done) {
|
||
|
*pch = ':';
|
||
|
path = pch + 1;
|
||
|
}
|
||
|
if (strlen(buf) > 0) {
|
||
|
// this case is "::" in the PATH
|
||
|
strcat(buf, "/");
|
||
|
}
|
||
|
strcat(buf, file);
|
||
|
|
||
|
// avoid trying to execute files that do not exist
|
||
|
|
||
|
if (-1 != access(buf, F_OK)) {
|
||
|
(void)execve(buf, argv, environ);
|
||
|
break;
|
||
|
}
|
||
|
} while (!done);
|
||
|
|
||
|
if (0 == errno) {
|
||
|
|
||
|
//
|
||
|
// We went all the way through the PATH without finding
|
||
|
// a file to exec. Since errno didn't get set by execve(),
|
||
|
// we set it here.
|
||
|
//
|
||
|
|
||
|
errno = ENOENT;
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
#define COMPUTERNAME_ROOT \
|
||
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName"
|
||
|
#define NON_VOLATILE_COMPUTERNAME L"ComputerName"
|
||
|
#define COMPUTERNAME_VALUE_NAME L"ComputerName"
|
||
|
#define VALUE_BUFFER_SIZE \
|
||
|
(sizeof(KEY_VALUE_PARTIAL_INFORMATION) \
|
||
|
+ (_POSIX_NAME_MAX * sizeof(WCHAR)))
|
||
|
|
||
|
int __cdecl
|
||
|
uname(struct utsname *name)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
SYSTEM_PROCESSOR_INFORMATION
|
||
|
ProcInfo;
|
||
|
UNICODE_STRING
|
||
|
KeyName,
|
||
|
Class,
|
||
|
ValueName,
|
||
|
Computer_U;
|
||
|
ANSI_STRING
|
||
|
Computer_A;
|
||
|
OBJECT_ATTRIBUTES
|
||
|
ObjectAttributes;
|
||
|
HANDLE hKey = NULL,
|
||
|
hSubKey = NULL;
|
||
|
WCHAR ValueBuf[VALUE_BUFFER_SIZE];
|
||
|
PKEY_VALUE_PARTIAL_INFORMATION
|
||
|
pKeyValueInfo = (PVOID)ValueBuf;
|
||
|
ULONG ValueLength;
|
||
|
char *pchProcType, // processor type
|
||
|
*pchNode = ""; // node name
|
||
|
int retval = 0;
|
||
|
|
||
|
Status = NtQuerySystemInformation(SystemProcessorInformation,
|
||
|
(PVOID)&ProcInfo, sizeof(ProcInfo), NULL);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
errno = PdxStatusToErrno(Status);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
switch (ProcInfo.ProcessorArchitecture) {
|
||
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
||
|
if (ProcInfo.ProcessorLevel == 3) {
|
||
|
pchProcType = "i386";
|
||
|
} else if (ProcInfo.ProcessorLevel == 4) {
|
||
|
pchProcType = "i486";
|
||
|
} else if (ProcInfo.ProcessorLevel == 5) {
|
||
|
pchProcType = "Pentium";
|
||
|
} else {
|
||
|
pchProcType = "Intel Unknown";
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case PROCESSOR_ARCHITECTURE_IA64:
|
||
|
pchProcType = "IA64";
|
||
|
break;
|
||
|
|
||
|
case PROCESSOR_ARCHITECTURE_MIPS:
|
||
|
pchProcType = "R4000";
|
||
|
break;
|
||
|
|
||
|
case PROCESSOR_ARCHITECTURE_ALPHA:
|
||
|
if (ProcInfo.ProcessorLevel == 21064) {
|
||
|
pchProcType = "Alpha 21064";
|
||
|
} else if (ProcInfo.ProcessorLevel == 21164) {
|
||
|
pchProcType = "Alpha 21164";
|
||
|
} else {
|
||
|
pchProcType = "Alpha Unknown";
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case PROCESSOR_ARCHITECTURE_PPC:
|
||
|
if (ProcInfo.ProcessorLevel == 1) {
|
||
|
pchProcType = "PowerPC 601";
|
||
|
} else if (ProcInfo.ProcessorLevel == 3) {
|
||
|
pchProcType = "PowerPC 603";
|
||
|
} else if (ProcInfo.ProcessorLevel == 4) {
|
||
|
pchProcType = "PowerPC 604";
|
||
|
} else if (ProcInfo.ProcessorLevel == 6) {
|
||
|
pchProcType = "PowerPC 603+";
|
||
|
} else if (ProcInfo.ProcessorLevel == 9) {
|
||
|
pchProcType = "PowerPC 604+";
|
||
|
} else if (ProcInfo.ProcessorLevel == 20) {
|
||
|
pchProcType = "PowerPC 620";
|
||
|
} else {
|
||
|
pchProcType = "PowerPC Unknown";
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
pchProcType = "unknown";
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find the node name: this code lifted from
|
||
|
// windows/base/client/compname.c
|
||
|
//
|
||
|
|
||
|
RtlInitUnicodeString(&KeyName, COMPUTERNAME_ROOT);
|
||
|
InitializeObjectAttributes(&ObjectAttributes, &KeyName,
|
||
|
OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||
|
|
||
|
Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
KdPrint(("PSXDLL: NtOpenKey: 0x%x\n", Status));
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
RtlInitUnicodeString(&KeyName, NON_VOLATILE_COMPUTERNAME);
|
||
|
InitializeObjectAttributes(&ObjectAttributes, &KeyName,
|
||
|
OBJ_CASE_INSENSITIVE, hKey, NULL);
|
||
|
|
||
|
Status = NtOpenKey(&hSubKey, KEY_READ, &ObjectAttributes);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
KdPrint(("PSXDLL: NtOpenKey: 0x%x\n", Status));
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
RtlInitUnicodeString(&ValueName, COMPUTERNAME_VALUE_NAME);
|
||
|
|
||
|
Status = NtQueryValueKey(hSubKey, &ValueName,
|
||
|
KeyValuePartialInformation,
|
||
|
(PVOID)pKeyValueInfo, VALUE_BUFFER_SIZE, &ValueLength);
|
||
|
ASSERT(ValueLength < VALUE_BUFFER_SIZE);
|
||
|
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
KdPrint(("PSXDLL: NtQueryValueKey: 0x%x\n", Status));
|
||
|
goto done;
|
||
|
}
|
||
|
if (pKeyValueInfo->DataLength == 0) {
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
Computer_U.Buffer = (PVOID)&pKeyValueInfo->Data;
|
||
|
Computer_U.Length = Computer_U.MaximumLength =
|
||
|
(USHORT)pKeyValueInfo->DataLength;
|
||
|
|
||
|
Status = RtlUnicodeStringToAnsiString(&Computer_A, &Computer_U, TRUE);
|
||
|
if (!NT_SUCCESS(Status)) {
|
||
|
goto done;
|
||
|
}
|
||
|
pchNode = Computer_A.Buffer;
|
||
|
|
||
|
done:
|
||
|
if (NULL != hSubKey) {
|
||
|
NtClose(hSubKey);
|
||
|
}
|
||
|
if (NULL != hKey) {
|
||
|
NtClose(hKey);
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
strncpy((PCHAR)name->sysname, (PCHAR)UNAME_SYSNAME, sizeof(name->sysname));
|
||
|
strncpy((PCHAR)name->release, (PCHAR)UNAME_RELEASE, sizeof(name->release));
|
||
|
strncpy((PCHAR)name->version, (PCHAR)UNAME_VERSION, sizeof(name->version));
|
||
|
strncpy((PCHAR)name->nodename, (PCHAR)pchNode, sizeof(name->nodename));
|
||
|
strncpy((PCHAR)name->machine, (PCHAR)pchProcType, sizeof(name->machine));
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
errno = EFAULT;
|
||
|
retval = -1;
|
||
|
}
|
||
|
RtlFreeAnsiString(&Computer_A);
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
char * __cdecl
|
||
|
getenv(const char *name)
|
||
|
{
|
||
|
char **ppch;
|
||
|
char *pch;
|
||
|
|
||
|
try {
|
||
|
for (ppch = environ; NULL != *ppch; ++ppch) {
|
||
|
if (NULL == (pch = strchr(*ppch, '='))) {
|
||
|
continue;
|
||
|
}
|
||
|
*pch = '\0'; // delete the equals
|
||
|
if (0 == strcmp(*ppch, name)) {
|
||
|
*pch = '=';
|
||
|
return pch + 1;
|
||
|
}
|
||
|
*pch = '=';
|
||
|
}
|
||
|
return NULL;
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
errno = EFAULT;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
time_t __cdecl
|
||
|
time(time_t *tloc)
|
||
|
{
|
||
|
LARGE_INTEGER TimeOfDay;
|
||
|
ULONG PosixTime;
|
||
|
|
||
|
NtQuerySystemTime(&TimeOfDay);
|
||
|
if (RtlTimeToSecondsSince1970(&TimeOfDay, &PosixTime)) {
|
||
|
if (ARGUMENT_PRESENT(tloc)) {
|
||
|
try {
|
||
|
*tloc = PosixTime;
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
errno = EFAULT;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
PosixTime = (ULONG)-1; // Time not within range of 1970 - 2105
|
||
|
}
|
||
|
return (time_t)PosixTime;
|
||
|
}
|
||
|
|
||
|
|
||
|
clock_t
|
||
|
__cdecl
|
||
|
times(struct tms *buffer)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_GETPROCESSTIMES_MSG args;
|
||
|
LARGE_INTEGER TimeOfDay;
|
||
|
ULONG Remainder;
|
||
|
NTSTATUS st;
|
||
|
int retval = 0;
|
||
|
|
||
|
args = &m.u.GetProcessTimes;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxGetProcessTimesApi, sizeof(*args));
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
if (m.Error) {
|
||
|
errno = (int)m.Error;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
*buffer = args->ProcessTimes;
|
||
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
errno = EFAULT;
|
||
|
retval = -1;
|
||
|
}
|
||
|
if (0 != retval) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
NtQuerySystemTime(&TimeOfDay);
|
||
|
|
||
|
TimeOfDay = RtlExtendedLargeIntegerDivide(TimeOfDay, 10000L,
|
||
|
&Remainder);
|
||
|
|
||
|
return TimeOfDay.LowPart;
|
||
|
}
|
||
|
|
||
|
long
|
||
|
__cdecl
|
||
|
sysconf(int name)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_SYSCONF_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.Sysconf;
|
||
|
|
||
|
args->Name = name;
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxSysconfApi, sizeof(*args));
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
|
||
|
if (0 != m.Error) {
|
||
|
errno = m.Error;
|
||
|
return -1;
|
||
|
}
|
||
|
return m.ReturnValue;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
__cdecl
|
||
|
getgroups(int gidsetsize, gid_t *grouplist)
|
||
|
{
|
||
|
PSX_API_MSG m;
|
||
|
PPSX_GETGROUPS_MSG args;
|
||
|
NTSTATUS st;
|
||
|
|
||
|
args = &m.u.GetGroups;
|
||
|
args->GroupList = grouplist;
|
||
|
args->NGroups = gidsetsize;
|
||
|
|
||
|
//
|
||
|
// The Posix server will write group id's into the group
|
||
|
// array with NtWriteVirtualMemory, unless gidsetsize is
|
||
|
// 0. In that case, he returns the size required and does
|
||
|
// not try to write the list.
|
||
|
//
|
||
|
|
||
|
PSX_FORMAT_API_MSG(m, PsxGetGroupsApi, sizeof(*args));
|
||
|
|
||
|
st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
|
||
|
(PPORT_MESSAGE)&m);
|
||
|
#ifdef PSX_MORE_ERRORS
|
||
|
ASSERT(NT_SUCCESS(st));
|
||
|
#endif
|
||
|
if (0 != m.Error) {
|
||
|
errno = m.Error;
|
||
|
return -1;
|
||
|
}
|
||
|
return m.ReturnValue;
|
||
|
}
|