Blob Blame History Raw
/*********************************************************/
/*  ptycon: a pty-console bridge                         */
/*  Copyright (C) 2016  Z. Gilboa                        */
/*  Released under GPLv2 and GPLv3; see COPYING.PTYCON.  */
/*********************************************************/

#include <pemagine/pemagine.h>
#include <ntapi/ntapi.h>
#include <ptycon/ptycon.h>
#include "ptycon_init_impl.h"
#include "ptycon_driver_impl.h"

static const nt_guid ptycon_daemon_guid = PTYC_PORT_GUID_DAEMON;

static const nt_tty_affiliation tty_affiliation
	__attr_section__(".midipix")
	= NT_TTY_AFFILIATION_DEFAULT;

static void ptycon_exit(int code)
{
	/* posix exit code? */
	if (code <= 0xff)
		code <<= 8;

	ntapi->zw_terminate_process(
		NT_CURRENT_PROCESS_HANDLE,
		code);
}

static int ptycon_dbg_helper(int32_t status)
{
	return status ? -1 : 0;
}

static int ptycon_dbg_init(char ** argv)
{
	if (argv[1] && !(ntapi->tt_strcmp_multibyte(argv[1],"--wait")))
		return ptycon_dbg_helper(
			ntapi->tt_wait_for_dummy_event());
	return 0;
}

static int32_t ptycon_start(int argc, char ** argv, char ** envp)
{
	int32_t				status;
	nt_runtime_data *		rtdata;
	nt_port_attr			port_attr;
        nt_pty_client_info		client_info;
	nt_iosb				iosb;

	/* rtdata */
	if ((status = ntapi->tt_get_runtime_data(&rtdata,0)))
		return status;

	if (rtdata->argv) {
		argc = rtdata->argc;
		argv = rtdata->argv;
		envp = rtdata->envp;
	}

	/* early debug (optional) */
	ptycon_dbg_init(argv);

	/* daemon */
	if (!(ntapi->tt_guid_compare(
			&rtdata->srv_guid,
			&(nt_guid)NT_PORT_GUID_DEFAULT)))
		ntapi->tt_guid_copy(
			&rtdata->srv_guid,
			&ptycon_daemon_guid);

	/* no tty session? */
	if (!rtdata->srv_keys[0])
		return ptyc_main(argc,argv,envp);

	/* tty */
	ntapi->tt_aligned_block_memset(
		&port_attr,0,sizeof(port_attr));

	port_attr.type		= NT_PORT_TYPE_SUBSYSTEM;
	port_attr.subtype	= NT_PORT_SUBTYPE_DEFAULT;

	port_attr.keys.key[0]	= rtdata->srv_keys[0];
	port_attr.keys.key[1]	= rtdata->srv_keys[1];
	port_attr.keys.key[2]	= rtdata->srv_keys[2];
	port_attr.keys.key[3]	= rtdata->srv_keys[3];
	port_attr.keys.key[4]	= rtdata->srv_keys[4];
	port_attr.keys.key[5]	= rtdata->srv_keys[5];

	ntapi->tt_port_guid_from_type(
		&port_attr.guid,
		port_attr.type,
		port_attr.subtype);

	if ((status = ntapi->tty_join_session(
			&rtdata->hsession,0,
			&port_attr,
			NT_TTY_SESSION_PRIMARY)))
		return status;

	/* pty */
	if ((status = ntapi->pty_inherit_runtime_ctty(
			rtdata->hsession,
			rtdata)))
		return status;

	/* ctty identification */
	if (rtdata->hctty) {
		client_info.any[0] = 0;
		client_info.any[1] = 0;
		client_info.any[2] = 0;
		client_info.any[3] = 0;

		if ((status = ntapi->pty_set(
				rtdata->hctty,&iosb,
				&client_info,sizeof(client_info),
				NT_PTY_CLIENT_INFORMATION)))
			return status;
	}

	/* ready */
	if (rtdata->hready)
		if ((status = ntapi->zw_set_event(rtdata->hready,0)))
			return status;

	/* main */
	return ptyc_main(argc,argv,envp);
}

static int __stdcall ptycon_daemon_entry_point(void * arg)
{
	int32_t		status;
	int		argc;
	char **		argv;
	char **		envp;

	(void)arg;
	(void)tty_affiliation;

	if ((status = ntapi->tt_get_argv_envp_utf8(
			&argc,&argv,&envp,
			0,0,0)))
		ptycon_exit(status);

	ptycon_exit(ptycon_start(
		argc,argv,envp));

	return NT_STATUS_INTERNAL_ERROR;
}

int ptycon_entry_point(void)
{
	int32_t			status;
	nt_thread_params	params;

	if ((status = ptyc_init()))
		return status;

	ntapi->tt_aligned_block_memset(
		&params,0,sizeof(params));

	params.hprocess		  = NT_CURRENT_PROCESS_HANDLE;
	params.start		  = ptycon_daemon_entry_point;
	params.stack_size_commit  = 128 * 1024;
	params.stack_size_reserve = 128 * 1024;
	params.creation_flags	  = NT_CREATE_LOCAL_THREAD;

	if ((status = ntapi->tt_create_thread(&params)))
		ptycon_exit(status);

	ntapi->zw_close(
		params.hthread);

	ntapi->zw_terminate_thread(
		NT_CURRENT_THREAD_HANDLE,
		NT_STATUS_SUCCESS);

	return NT_STATUS_INTERNAL_ERROR;
}