summaryrefslogtreecommitdiffhomepage
path: root/src/pty
diff options
context:
space:
mode:
Diffstat (limited to 'src/pty')
-rw-r--r--src/pty/ptyc_spawn.c262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/pty/ptyc_spawn.c b/src/pty/ptyc_spawn.c
new file mode 100644
index 0000000..93b8237
--- /dev/null
+++ b/src/pty/ptyc_spawn.c
@@ -0,0 +1,262 @@
+/*********************************************************/
+/* ptycon: a pty-console bridge */
+/* Copyright (C) 2016 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.PTYCON. */
+/*********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntcon/ntcon.h>
+#include <ntapi/ntapi.h>
+
+#include <ptycon/ptycon.h>
+#include "ptycon_driver_impl.h"
+
+static int32_t __stdcall ptyc_spawn_return(
+ nt_runtime_data_block * rtblock,
+ int32_t status)
+{
+ nt_runtime_data * rtdata;
+
+ rtdata = (nt_runtime_data *)rtblock;
+
+ if (rtdata->hready)
+ ntapi->zw_close(
+ rtdata->hready);
+
+ ntapi->zw_free_virtual_memory(
+ NT_CURRENT_PROCESS_HANDLE,
+ &rtblock->addr,
+ &rtblock->size,
+ NT_MEM_RELEASE);
+
+ return status;
+}
+
+int __stdcall ptyc_spawn(struct ptyc_driver_ctx * dctx)
+{
+ int32_t status;
+ char * patharg;
+ void * hchild[2];
+ nt_create_process_params params;
+ struct ptyc_driver_ctx_impl * ictx;
+ struct ptyc_client_ctx * clctx;
+ nt_tty_session_info session;
+ nt_runtime_data_block rtblock;
+ nt_runtime_data * rdata;
+ nt_rtdata * self;
+ nt_peb * peb;
+ void * hat;
+ void * hfile;
+ char ** rargv;
+ char ** renvp;
+ wchar16_t ** pwarg;
+ wchar16_t * wch;
+ nt_unicode_string * imgname;
+ uint32_t written;
+ uintptr_t imgbuf[8192/sizeof(uintptr_t)];
+
+ /* init */
+ if (!(ictx = ptyc_get_driver_ictx(dctx)))
+ return NT_STATUS_INVALID_HANDLE;
+
+ if (!dctx->cctx->eargv)
+ return NT_STATUS_SUCCESS;
+
+ if ((status = ntapi->tt_get_runtime_data(&self,0)))
+ return status;
+
+ clctx = &ictx->clctx;
+
+ /* hat */
+ if (!(peb = (nt_peb *)pe_get_peb_address()))
+ return NT_STATUS_INTERNAL_ERROR;
+
+ if (!peb->process_params)
+ return NT_STATUS_INTERNAL_ERROR;
+
+ hat = (dctx->cctx->hroot && (dctx->cctx->eargv[0][0] == '/'))
+ ? dctx->cctx->hroot
+ : self->hcwd
+ ? self->hcwd
+ : peb->process_params->cwd_handle;
+
+ patharg = (dctx->cctx->eargv[0][0] == '/')
+ ? &dctx->cctx->eargv[0][1]
+ : &dctx->cctx->eargv[0][0];
+
+ /* hfile */
+ if ((status = ptyc_open_file(&hfile,hat,patharg,true)))
+ return status;
+
+ /* rtblock */
+ rtblock.addr = 0;
+ rtblock.size = 0x10000;
+ rtblock.remote_addr = 0;
+ rtblock.remote_size = 0;
+ rtblock.flags = 0;
+
+ if ((status = ntapi->zw_allocate_virtual_memory(
+ self->hprocess_self,
+ &rtblock.addr,0,
+ &rtblock.size,
+ NT_MEM_COMMIT,
+ NT_PAGE_READWRITE)))
+ return status;
+
+ ntapi->tt_aligned_block_memset(
+ rtblock.addr,0,rtblock.size);
+
+ if ((status = ntapi->zw_query_object(
+ hfile,
+ NT_OBJECT_NAME_INFORMATION,
+ imgbuf,sizeof(imgbuf),
+ &written)))
+ return ptyc_spawn_return(
+ &rtblock,status);
+
+ imgname = (nt_unicode_string *)imgbuf;
+ rdata = (nt_runtime_data *)rtblock.addr;
+
+ /* argv, envp */
+ if ((status = ntapi->tt_array_copy_utf8(
+ &rdata->argc,
+ (const char **)dctx->cctx->eargv,
+ (const char **)self->envp,
+ 0,0,0,
+ rtblock.addr,
+ rdata->buffer,
+ rtblock.size - sizeof(*rdata),
+ &rtblock.remote_size)))
+ return ptyc_spawn_return(
+ &rtblock,status);
+
+ rdata->argv = (char **)&((nt_runtime_data *)0)->buffer;
+ rdata->envp = rdata->argv + rdata->argc + 1;
+
+ rdata->wargv = (wchar16_t **)(rdata->buffer + (rtblock.remote_size / sizeof(uintptr_t)) + 1);
+ rdata->wenvp = rdata->wargv + rdata->argc + 1;
+
+ rargv = rdata->argv + ((uintptr_t)rtblock.addr / sizeof(char *));
+ renvp = rdata->envp + ((uintptr_t)rtblock.addr / sizeof(char *));
+
+ pwarg = rdata->wenvp + self->envc + 1;
+ wch = (wchar16_t *)pwarg;
+
+ if ((status = ntapi->tt_array_convert_utf8_to_utf16(
+ rargv,
+ rdata->wargv,
+ rdata,
+ wch,
+ rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer),
+ &rtblock.remote_size)))
+ return ptyc_spawn_return(
+ &rtblock,status);
+
+ wch += rtblock.remote_size/sizeof(wchar16_t);
+
+ if ((status = ntapi->tt_array_convert_utf8_to_utf16(
+ renvp,
+ rdata->wenvp,
+ rdata,
+ wch,
+ rtblock.size - sizeof(wchar16_t)*(wch-(wchar16_t *)rdata->buffer),
+ &rtblock.remote_size)))
+ return ptyc_spawn_return(
+ &rtblock,status);
+
+ rdata->wargv -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *);
+ rdata->wenvp -= (uintptr_t)rtblock.addr / sizeof(wchar16_t *);
+
+ /* session */
+ if ((status = ntapi->tt_create_inheritable_event(
+ &rdata->hready,
+ NT_NOTIFICATION_EVENT,
+ NT_EVENT_NOT_SIGNALED)))
+ return ptyc_spawn_return(
+ &rtblock,status);
+
+ ntapi->tt_aligned_block_memcpy(
+ (uintptr_t *)&rdata->cid_parent,
+ (uintptr_t *)&self->cid_self,
+ sizeof(nt_cid));
+
+ rdata->hroot = dctx->cctx->hroot;
+ rdata->hcwd = self->hcwd
+ ? self->hcwd
+ : peb->process_params->cwd_handle;
+
+ rdata->srv_keys[0] = self->srv_keys[0];
+ rdata->srv_keys[1] = self->srv_keys[1];
+ rdata->srv_keys[2] = self->srv_keys[2];
+ rdata->srv_keys[3] = self->srv_keys[3];
+ rdata->srv_keys[4] = self->srv_keys[4];
+ rdata->srv_keys[5] = self->srv_keys[5];
+
+ rdata->hstdin = NT_INVALID_HANDLE_VALUE;
+ rdata->hstdout = NT_INVALID_HANDLE_VALUE;
+ rdata->hstderr = NT_INVALID_HANDLE_VALUE;
+
+ rdata->stdin_type = NT_FILE_TYPE_PTY;
+ rdata->stdout_type = NT_FILE_TYPE_PTY;
+ rdata->stderr_type = NT_FILE_TYPE_PTY;
+
+ rdata->ptyany[0] = clctx->clinfo.any[0];
+ rdata->ptyany[1] = clctx->clinfo.any[1];
+ rdata->ptyany[2] = clctx->clinfo.any[2];
+ rdata->ptyany[3] = clctx->clinfo.any[3];
+
+ /* params */
+ ntapi->tt_aligned_block_memset(
+ &params,0,sizeof(params));
+
+ params.image_name = imgname->buffer;
+ params.rtblock = &rtblock;
+ params.creation_flags_process = NT_PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
+ params.creation_flags_thread = NT_PROCESS_CREATE_FLAGS_CREATE_THREAD_SUSPENDED;
+
+ /* hoppla */
+ if ((status = ntapi->tt_create_native_process(&params)))
+ return ptyc_spawn_return(
+ &rtblock,status);
+
+ /* clctx */
+ clctx->hprocess = params.hprocess;
+ clctx->hthread = params.hthread;
+ clctx->cid.process_id = params.cid.process_id;
+ clctx->cid.thread_id = params.cid.thread_id;
+
+ if ((status = ntapi->tty_client_process_register(
+ self->hsession,
+ params.pbi.unique_process_id,
+ 0,NT_TTY_INHERIT_HANDLES,0)))
+ ntapi->zw_terminate_process(
+ params.hprocess,
+ status);
+
+ session.pid = 0;
+ session.pgid = 0;
+ session.sid = 0;
+ session.syspid = params.pbi.unique_process_id;
+
+ if ((status = ntapi->tty_client_session_set(0,&session)))
+ ntapi->zw_terminate_process(
+ params.hprocess,
+ status);
+
+ if ((status = ntapi->zw_resume_thread(params.hthread,0)))
+ ntapi->zw_terminate_process(
+ params.hprocess,
+ status);
+
+ hchild[1] = params.hprocess;
+ hchild[0] = rdata->hready;
+
+ ntapi->zw_wait_for_multiple_objects(
+ 2,hchild,
+ NT_WAIT_ANY,
+ NT_SYNC_NON_ALERTABLE,
+ 0);
+
+ return ptyc_spawn_return(
+ &rtblock,status);
+}