blob: b275ff5151f7c5b0517439c9e5630fee163d58af [file] [log] [blame] [raw]
/* A part of the Native C Library for Windows NT
Copyright 2007-2015 PC GO Ld.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
#include <windows.h>
#include <nt.h>
#include <errno.h>
#include <unistd.h>
#include <process.h>
#include <pathname.h>
#include <string.h>
#include <wchar.h>
//#include <stdio.h>
wchar_t *__environ_to_wenvblock(wchar_t *buffer, size_t buffer_size);
static long int open_file_for_execute(void **handle, UNICODE_STRING *ntpathname) {
//void *fh;
OBJECT_ATTRIBUTES foa = { sizeof(OBJECT_ATTRIBUTES), NULL, ntpathname, OBJ_INHERIT, NULL, NULL };
IO_STATUS_BLOCK io_status;
unsigned long int file_share = FILE_SHARE_READ | FILE_SHARE_DELETE;
return NtOpenFile(handle, SYNCHRONIZE | FILE_EXECUTE, &foa, &io_status, file_share, FILE_NON_DIRECTORY_FILE);
}
pid_t _create_process(const char *program, const char *commandline, int start) {
if(!program) {
errno = EFAULT;
return -1;
}
if(!*program) {
errno = ENOENT;
return -1;
}
if(*program != '/') {
errno = ENOSYS;
return -1;
}
if(!commandline) {
int i, offset = 0;
for(i=0; program[i]; i++) if(program[i] == '/') offset = i + 1;
//commandline = offset ? program + offset + 1 : program;
commandline = program + offset;
for(i=offset; program[i]; i++) if(program[i] == ' ') {
static char buffer[258] = "\"";
size_t len = strlen(commandline);
if(len > 255) len = 255;
memcpy(buffer + 1, commandline, len);
memcpy(buffer + 1 + len, "\"", 2);
commandline = buffer;
break;
}
}
UNICODE_STRING ntpathname;
UNICODE_STRING command_line;
KUSER_SHARED_DATA *shared_data = (KUSER_SHARED_DATA *)USER_SHARED_DATA;
size_t dllpath_len = wcslen(shared_data->NtSystemRoot) * 2 + 5 + 1;
wchar_t wdllpath[dllpath_len];
wcscpy(wdllpath, shared_data->NtSystemRoot);
wcscat(wdllpath, L"\\lib;");
wcscat(wdllpath, shared_data->NtSystemRoot);
UNICODE_STRING dllpath = { (dllpath_len - 1) * sizeof(wchar_t), dllpath_len * sizeof(wchar_t), wdllpath };
if(!RtlCreateUnicodeStringFromAsciiz(&ntpathname, program)) {
errno = ENOMEM;
return -1;
}
if(!RtlCreateUnicodeStringFromAsciiz(&command_line, commandline)) {
errno = ENOMEM;
return -1;
}
RTL_USER_PROCESS_PARAMETERS *processparameters;
RTL_USER_PROCESS_INFORMATION pi;
wchar_t wenvblock[1024];
memset(&pi, 0, sizeof pi);
__environ_to_wenvblock(wenvblock, sizeof wenvblock);
long int status = RtlCreateProcessParameters(&processparameters, &ntpathname, &dllpath, NULL, &command_line, wenvblock, 0, 0, 0, 0);
//printf("nativelibc debug: _create_process: status = 0x%lx\n", status);
RtlFreeUnicodeString(&command_line);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
processparameters->StandardOutput = (void *)_get_stdout_fd();
processparameters->StandardError = (void *)_get_stderr_fd();
PATHNAME_UNIX2NT_UTF16_STRUCT(ntpathname);
void *fh;
status = open_file_for_execute(&fh, &ntpathname);
//printf("nativelibc debug: _create_process: open_file_for_execute returned: 0x%lx\n", status);
RtlFreeUnicodeString(&ntpathname);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
void *sh;
status = NtCreateSection(&sh, SECTION_ALL_ACCESS, NULL, NULL, PAGE_EXECUTE, SEC_IMAGE, fh);
//printf("nativelibc debug: _create_process: status = 0x%lx\n", status);
NtClose(fh);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
OBJECT_ATTRIBUTES object_attrib = { sizeof(OBJECT_ATTRIBUTES), NULL, NULL, 0, NULL, NULL };
status = NtCreateProcess(&pi.ProcessHandle, PROCESS_ALL_ACCESS, &object_attrib, (void *)-1, 1, sh, NULL, NULL);
//printf("nativelibc debug: _create_process: status = 0x%lx\n", status);
if(status < 0) {
NtClose(sh);
__set_errno_from_ntstatus(status);
return -1;
}
status = NtQuerySection(sh, SectionImageInformation, &pi.ImageInformation, sizeof pi.ImageInformation, NULL);
//printf("nativelibc debug: _create_process: status = 0x%lx\n", status);
if(status < 0) goto failed;
PROCESS_BASIC_INFORMATION pbi;
status = NtQueryInformationProcess(pi.ProcessHandle, ProcessBasicInformation, &pbi, sizeof pbi, NULL);
//printf("nativelibc debug: _create_process: status = 0x%lx\n", status);
if(status < 0) goto failed;
OBJECT_BASIC_INFORMATION obi;
switch((int)processparameters->StandardOutput) {
case TTY_FD_DEFAULT:
case TTY_FD_INVALID:
break;
default:
status = NtQueryObject(processparameters->StandardOutput, ObjectBasicInformation, &obi, sizeof obi, NULL);
if(status < 0) break;
if(obi.Attributes & OBJ_INHERIT) break;
status = NtDuplicateObject((void *)-1, processparameters->StandardOutput, pi.ProcessHandle,
&processparameters->StandardOutput, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES);
if(status < 0) goto failed;
}
switch((int)processparameters->StandardError) {
case TTY_FD_DEFAULT:
case TTY_FD_INVALID:
break;
default:
status = NtQueryObject(processparameters->StandardError, ObjectBasicInformation, &obi, sizeof obi, NULL);
if(status < 0) break;
if(obi.Attributes & OBJ_INHERIT) break;
status = NtDuplicateObject((void *)-1, processparameters->StandardError, pi.ProcessHandle,
&processparameters->StandardError, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES);
if(status < 0) goto failed;
}
if(processparameters->Environment) {
// Copy the environment block
const wchar_t *s = processparameters->Environment;
void *e = NULL;
size_t envblock_size = 2;
while(*s++ || *s) envblock_size++;
envblock_size *= sizeof(wchar_t);
size_t envblock_size_ = envblock_size;
status = NtAllocateVirtualMemory(pi.ProcessHandle, &e, 0, &envblock_size_, MEM_COMMIT, PAGE_READWRITE);
//printf("nativelibc debug: _create_process: status = 0x%lx\n", status);
if(status < 0) goto failed;
status = NtWriteVirtualMemory(pi.ProcessHandle, e, processparameters->Environment, envblock_size, NULL);
//printf("nativelibc debug: _create_process: status = 0x%lx\n", status);
if(status < 0) goto failed;
processparameters->Environment = e;
}
{
// Copy the process parameters
RTL_USER_PROCESS_PARAMETERS *p = NULL;
size_t pp_size = processparameters->MaximumLength;
status = NtAllocateVirtualMemory(pi.ProcessHandle, &p, 0, &pp_size, MEM_COMMIT, PAGE_READWRITE);
//printf("nativelibc debug: _create_process: status = 0x%lx, MaximumLength = %lu, Length = %lu\n", status, processparameters->MaximumLength, processparameters->Length);
if(status < 0) goto failed;
status = NtWriteVirtualMemory(pi.ProcessHandle, p, processparameters, processparameters->Length, NULL);
//printf("nativelibc debug: _create_process: status = 0x%lx\n", status);
if(status < 0) goto failed;
// Copy the pointer of process parameters to the process environment block
status = NtWriteVirtualMemory(pi.ProcessHandle, &pbi.PebBaseAddress->ProcessParameters, &p, sizeof p, NULL);
//printf("nativelibc debug: _create_process: status = 0x%lx\n", status);
if(status < 0) goto failed;
}
RtlDestroyProcessParameters(processparameters);
// Create the main thread
status = RtlCreateUserThread(pi.ProcessHandle, NULL, start, pi.ImageInformation.ZeroBits, pi.ImageInformation.MaximumStackSize,
pi.ImageInformation.CommittedStackSize, (PUSER_THREAD_START_ROUTINE)pi.ImageInformation.TransferAddress, pbi.PebBaseAddress, &pi.ThreadHandle, &pi.ClientId);
//printf("nativelibc debug: _create_process: status = 0x%lx\n", status);
NtClose(sh);
if(status < 0) {
NtClose(pi.ProcessHandle);
NtClose(pi.ThreadHandle);
__set_errno_from_ntstatus(status);
return -1;
}
if(start) {
status = NtResumeThread(pi.ThreadHandle, NULL);
if(status < 0) {
NtClose(pi.ProcessHandle);
NtClose(pi.ThreadHandle);
__set_errno_from_ntstatus(status);
return -1;
}
}
NtClose(pi.ThreadHandle);
__child_process_table_add(pi.ClientId.UniqueProcess, pi.ProcessHandle);
return pi.ClientId.UniqueProcess;
failed:
NtClose(pi.ProcessHandle);
NtClose(sh);
RtlDestroyProcessParameters(processparameters);
__set_errno_from_ntstatus(status);
return -1;
}