/*++ 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 #include #include #include #include #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 // // // // 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; }