Blame src/driver/ptyc_driver_ctx.c

0efa8c
/*********************************************************/
0efa8c
/*  ptycon: a pty-console bridge                         */
0efa8c
/*  Copyright (C) 2016  Z. Gilboa                        */
0efa8c
/*  Released under GPLv2 and GPLv3; see COPYING.PTYCON.  */
0efa8c
/*********************************************************/
0efa8c
cfc59b
#include <ntcon/ntcon.h>
0efa8c
#include <ntapi/ntapi.h>
cfc59b
#include <ntapi/nt_atomic.h>
74eafc
#include <gdi/gdi.h>
cfc59b
0efa8c
#include <stdint.h>
0efa8c
0efa8c
#include <ptycon/ptycon.h>
0efa8c
#include "ptycon_init_impl.h"
0efa8c
#include "ptycon_nolibc_impl.h"
0efa8c
0efa8c
#define ARGV_DRIVER
0efa8c
0efa8c
#include "ptycon_version.h"
f23497
#include "ptycon_daemon_impl.h"
0efa8c
#include "ptycon_driver_impl.h"
0efa8c
#include "argv/argv.h"
0efa8c
0efa8c
/* ntapi accessor table */
0efa8c
const ntapi_vtbl * ptyc_ntapi;
0efa8c
cfc59b
/* ntcon accessor table */
cfc59b
static ntcon_vtbl ptyc_ntcon_vtbl;
cfc59b
const  ntcon_vtbl * const ptyc_ntcon = &ptyc_ntcon_vtbl;
cfc59b
74eafc
/* gdi accessor table */
74eafc
static gdi_vtbl ptyc_gdi_vtbl;
74eafc
const  gdi_vtbl * const ptyc_gdi = &ptyc_gdi_vtbl;
74eafc
f23497
/* daemon */
f23497
static struct ptyc_daemon_ctx ptyc_daemon_ctx;
f23497
0efa8c
/* package info */
0efa8c
static const struct ptyc_source_version ptyc_src_version = {
0efa8c
	PTYC_TAG_VER_MAJOR,
0efa8c
	PTYC_TAG_VER_MINOR,
0efa8c
	PTYC_TAG_VER_PATCH,
0efa8c
	PTYCON_GIT_VERSION
0efa8c
};
0efa8c
0efa8c
struct ptyc_driver_ctx_alloc {
0efa8c
	struct argv_meta *		meta;
0efa8c
	struct ptyc_driver_ctx_impl	ctx;
0efa8c
	uint64_t			guard;
0efa8c
	const char *			units[];
0efa8c
};
0efa8c
cc22da
struct ptyc_split_vector {
cc22da
	char **		targv;
cc22da
	char **		eargv;
cc22da
};
cc22da
74eafc
static int32_t ptyc_once = 0;
cfc59b
74eafc
static int32_t ptyc_vtbl_init(void)
cfc59b
{
cfc59b
	int32_t		status;
cfc59b
	nt_timeout	timeout;
cfc59b
74eafc
	switch (at_locked_cas_32(&ptyc_once,0,1)) {
cfc59b
		case 0:
cfc59b
			if ((status = ntcon_vtbl_init(&ptyc_ntcon_vtbl))) {
74eafc
				at_locked_add_32(&ptyc_once,2);
74eafc
				return status;
74eafc
			}
74eafc
74eafc
			if ((status = gdi_vtbl_init(&ptyc_gdi_vtbl))) {
74eafc
				at_locked_add_32(&ptyc_once,2);
cfc59b
				return status;
cfc59b
			}
cfc59b
74eafc
			at_locked_inc_32(&ptyc_once);
74eafc
			return 0;
74eafc
cfc59b
		case 1:
cfc59b
			timeout.quad = -10;
cfc59b
74eafc
			for (; (at_locked_cas_32(&ptyc_once,0,1) == 1); )
cfc59b
				ntapi->zw_delay_execution(
cfc59b
					NT_SYNC_ALERTABLE,
cfc59b
					&timeout);
cfc59b
74eafc
			return (ptyc_once == 2)
cfc59b
				? 0 : -1;
cfc59b
cfc59b
		case 2:
cfc59b
			return 0;
cfc59b
cfc59b
		case 3:
cfc59b
		default:
cfc59b
			return -1;
cfc59b
	}
cfc59b
}
cfc59b
0efa8c
static uint32_t ptyc_argv_flags(uint32_t flags)
0efa8c
{
0efa8c
	uint32_t ret = 0;
0efa8c
0efa8c
	if (flags & PTYC_DRIVER_VERBOSITY_NONE)
0efa8c
		ret |= ARGV_VERBOSITY_NONE;
0efa8c
0efa8c
	if (flags & PTYC_DRIVER_VERBOSITY_ERRORS)
0efa8c
		ret |= ARGV_VERBOSITY_ERRORS;
0efa8c
0efa8c
	if (flags & PTYC_DRIVER_VERBOSITY_STATUS)
0efa8c
		ret |= ARGV_VERBOSITY_STATUS;
0efa8c
0efa8c
	return ret;
0efa8c
}
0efa8c
0efa8c
static int ptyc_driver_usage(
0efa8c
	const char *			program,
0efa8c
	const char *			arg,
0efa8c
	const struct argv_option *	options,
0efa8c
	struct argv_meta *		meta)
0efa8c
{
0efa8c
	char header[512];
0efa8c
0efa8c
	snprintf(header,sizeof(header),
0efa8c
		"Usage: %s [options] <file>...\n" "Options:\n",
0efa8c
		program);
0efa8c
0efa8c
	argv_usage(stdout,header,options,arg);
0efa8c
	argv_free(meta);
0efa8c
0efa8c
	return PTYC_USAGE;
0efa8c
}
0efa8c
0efa8c
static struct ptyc_driver_ctx_impl * ptyc_driver_ctx_alloc(
0efa8c
	struct argv_meta *		meta,
0efa8c
	const struct ptyc_common_ctx *	cctx,
0efa8c
	size_t				nunits)
0efa8c
{
0efa8c
	struct ptyc_driver_ctx_alloc *	ictx;
0efa8c
	size_t				size;
0efa8c
	struct argv_entry *		entry;
0efa8c
	const char **			units;
c26174
	nt_runtime_data *		rtdata;
c26174
c26174
	if (ntapi->tt_get_runtime_data(&rtdata,0))
c26174
		return 0;
0efa8c
0efa8c
	size =  sizeof(struct ptyc_driver_ctx_alloc);
0efa8c
	size += (nunits+1)*sizeof(const char *);
0efa8c
0efa8c
	if (!(ictx = calloc(1,size)))
0efa8c
		return 0;
0efa8c
0efa8c
	if (cctx)
0efa8c
		memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx));
0efa8c
0efa8c
	for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++)
2de078
		if (entry->tag == TAG_CAT)
0efa8c
			*units++ = entry->arg;
0efa8c
0efa8c
	ictx->meta = meta;
0efa8c
	ictx->ctx.ctx.units = ictx->units;
c26174
	ictx->ctx.rtdata = rtdata;
0efa8c
	return &ictx->ctx;
0efa8c
}
0efa8c
0efa8c
static int ptyc_get_driver_ctx_fail(struct argv_meta * meta)
0efa8c
{
0efa8c
	argv_free(meta);
0efa8c
	return -1;
0efa8c
}
0efa8c
cc22da
#define PTYC_SARGV_ELEMENTS		1024
cc22da
cc22da
static int ptyc_split_argv(
cc22da
	char **				argv,
cc22da
	struct ptyc_split_vector *	sargv)
cc22da
{
cc22da
	ptrdiff_t	argc;
cc22da
	char **		parg;
cc22da
cc22da
	/* argc */
cc22da
	for (parg=argv; *parg; )
cc22da
		parg++;
cc22da
cc22da
	if ((argc = parg - argv) >= PTYC_SARGV_ELEMENTS)
cc22da
		return -1;
cc22da
cc22da
	/* clone argv into targv */
cc22da
	ntapi->tt_aligned_block_memset(
cc22da
		(uintptr_t *)sargv->targv,
cc22da
		0,PTYC_SARGV_ELEMENTS*sizeof(char *));
cc22da
cc22da
	ntapi->tt_aligned_block_memcpy(
cc22da
		(uintptr_t *)sargv->targv,
cc22da
		(uintptr_t *)argv,
cc22da
		argc*sizeof(char *));
cc22da
cc22da
	/* eargv */
cc22da
	for (parg=sargv->targv; *parg; parg++) {
cc22da
		if (!(strcmp(*parg,"-e")) || !(strcmp(*parg,"--exec"))) {
16c3a6
			sargv->eargv = &argv[parg-sargv->targv];
cc22da
			sargv->eargv++;
cc22da
			*parg = 0;
cc22da
			return 0;
cc22da
		}
cc22da
	}
cc22da
cc22da
	return 0;
cc22da
}
cc22da
0efa8c
int ptyc_get_driver_ctx(
0efa8c
	char **				argv,
0efa8c
	char **				envp,
0efa8c
	uint32_t			flags,
0efa8c
	struct ptyc_driver_ctx **	pctx)
0efa8c
{
0efa8c
	struct ptyc_driver_ctx_impl *	ctx;
0efa8c
	struct ptyc_common_ctx		cctx;
cc22da
	struct ptyc_split_vector	sargv;
0efa8c
	const struct argv_option *	options;
0efa8c
	struct argv_meta *		meta;
0efa8c
	struct argv_entry *		entry;
0efa8c
	size_t				nunits;
0efa8c
	const char *			program;
cc22da
	char *				targv[PTYC_SARGV_ELEMENTS];
0efa8c
0efa8c
	(void)envp;
0efa8c
0efa8c
	if (ptyc_init())
0efa8c
		return -1;
0efa8c
74eafc
	if (ptyc_vtbl_init())
cfc59b
		return -1;
cfc59b
0efa8c
	options = ptyc_default_options;
0efa8c
cc22da
	sargv.targv = targv;
cc22da
	sargv.eargv = 0;
cc22da
cc22da
	if (ptyc_split_argv(argv,&sargv))
cc22da
		return -1;
cc22da
cc22da
	if (!(meta = argv_get(sargv.targv,options,ptyc_argv_flags(flags))))
0efa8c
		return -1;
0efa8c
0efa8c
	nunits	= 0;
0efa8c
	program = argv_program_name(argv[0]);
0efa8c
	memset(&cctx,0,sizeof(cctx));
0efa8c
	cctx.drvflags = flags;
cc22da
	cctx.eargv = sargv.eargv;
0efa8c
0efa8c
	if (!argv[1] && (flags & PTYC_DRIVER_VERBOSITY_USAGE))
0efa8c
		return ptyc_driver_usage(program,0,options,meta);
0efa8c
0efa8c
	/* get options, count units */
0efa8c
	for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
0efa8c
		if (entry->fopt) {
0efa8c
			switch (entry->tag) {
0efa8c
				case TAG_HELP:
0efa8c
					if (flags & PTYC_DRIVER_VERBOSITY_USAGE)
0efa8c
						return ptyc_driver_usage(program,entry->arg,options,meta);
0efa8c
0efa8c
				case TAG_VERSION:
0efa8c
					cctx.drvflags |= PTYC_DRIVER_VERSION;
0efa8c
					break;
64c887
f67c20
				case TAG_DAEMON:
f67c20
					if (!strcmp("always",entry->arg))
f67c20
						cctx.drvflags |= PTYC_DRIVER_DAEMON_ALWAYS;
f67c20
f67c20
					else if (!strcmp("never",entry->arg))
f67c20
						cctx.drvflags |= PTYC_DRIVER_DAEMON_NEVER;
f67c20
f67c20
					break;
f67c20
64c887
				case TAG_DEBUG:
7307c5
					if (!entry->arg) {
64c887
						cctx.drvflags |= PTYC_DRIVER_DBG_EVENT;
64c887
7307c5
					} else if (!strcmp("event",entry->arg)) {
64c887
						cctx.drvflags |= PTYC_DRIVER_DBG_EVENT;
64c887
7307c5
					} else if (!strcmp("oven",entry->arg)) {
7307c5
						cctx.drvflags &= ~(uint64_t)PTYC_DRIVER_DBG_RAW;
64c887
						cctx.drvflags |= PTYC_DRIVER_DBG_OVEN;
64c887
7307c5
					} else if (!strcmp("raw",entry->arg)) {
7307c5
						cctx.drvflags &= ~(uint64_t)PTYC_DRIVER_DBG_OVEN;
64c887
						cctx.drvflags |= PTYC_DRIVER_DBG_RAW;
7307c5
					}
7307c5
64c887
					break;
2de078
fd0f9b
				case TAG_BELL:
fd0f9b
					if ((!entry->arg) || !strcmp("on",entry->arg))
fd0f9b
						cctx.drvflags |= PTYC_DRIVER_BELL;
fd0f9b
					break;
fd0f9b
2de078
				case TAG_CAT:
2de078
					nunits++;
2de078
					break;
e9e742
d881b6
				case TAG_SYSROOT:
d881b6
					cctx.sysroot = entry->arg;
d881b6
					break;
d881b6
e9e742
				case TAG_WAIT:
e9e742
					cctx.drvflags |= PTYC_DRIVER_DBG_WAIT;
e9e742
					break;
0efa8c
			}
cc22da
		} else
cc22da
			/* strict */
cc22da
			return ptyc_driver_usage(program,0,options,meta);
0efa8c
	}
0efa8c
d881b6
	if (cctx.sysroot && ptyc_open_dir(&cctx.hroot,0,cctx.sysroot,false)) {
d881b6
		if (flags & PTYC_DRIVER_VERBOSITY_ERRORS)
d881b6
			fprintf(stderr,
d881b6
				"%s: error: could not open sysroot directory '%s'",
d881b6
				program,cctx.sysroot);
d881b6
		return ptyc_get_driver_ctx_fail(meta);
d881b6
	}
d881b6
0efa8c
	if (!(ctx = ptyc_driver_ctx_alloc(meta,&cctx,nunits)))
0efa8c
		return ptyc_get_driver_ctx_fail(meta);
0efa8c
f23497
	if (ptyc_daemon_init(&ptyc_daemon_ctx,cctx.drvflags))
f23497
		return ptyc_get_driver_ctx_fail(meta);
f23497
0efa8c
	ctx->ctx.program	= program;
0efa8c
	ctx->ctx.cctx		= &ctx->cctx;
0efa8c
0efa8c
	*pctx = &ctx->ctx;
0efa8c
	return PTYC_OK;
0efa8c
}
0efa8c
0efa8c
int ptyc_create_driver_ctx(
0efa8c
	const struct ptyc_common_ctx *	cctx,
0efa8c
	struct ptyc_driver_ctx **	pctx)
0efa8c
{
0efa8c
	struct argv_meta *		meta;
0efa8c
	struct ptyc_driver_ctx_impl *	ctx;
0efa8c
	char *				argv[] = {"ptycon_driver",0};
0efa8c
0efa8c
	if (ptyc_init())
0efa8c
		return -1;
0efa8c
74eafc
	if (ptyc_vtbl_init())
cfc59b
		return -1;
cfc59b
0efa8c
	if (!(meta = argv_get(argv,ptyc_default_options,0)))
0efa8c
		return -1;
0efa8c
0efa8c
	if (!(ctx = ptyc_driver_ctx_alloc(meta,cctx,0)))
0efa8c
		return ptyc_get_driver_ctx_fail(0);
0efa8c
0efa8c
	ctx->ctx.cctx = &ctx->cctx;
0efa8c
	memcpy(&ctx->cctx,cctx,sizeof(*cctx));
0efa8c
	*pctx = &ctx->ctx;
0efa8c
	return PTYC_OK;
0efa8c
}
0efa8c
0efa8c
static void ptyc_free_driver_ctx_impl(struct ptyc_driver_ctx_alloc * ictx)
0efa8c
{
538c8a
	ptyc_free_pty(&ictx->ctx.ctx);
0efa8c
	argv_free(ictx->meta);
0efa8c
	free(ictx);
0efa8c
}
0efa8c
0efa8c
void ptyc_free_driver_ctx(struct ptyc_driver_ctx * ctx)
0efa8c
{
0efa8c
	struct ptyc_driver_ctx_alloc *	ictx;
0efa8c
	uintptr_t			addr;
0efa8c
0efa8c
	if (ctx) {
31bc75
		addr = (uintptr_t)ctx - offsetof(struct ptyc_driver_ctx_impl,ctx);
31bc75
		addr = addr - offsetof(struct ptyc_driver_ctx_alloc,ctx);
0efa8c
		ictx = (struct ptyc_driver_ctx_alloc *)addr;
0efa8c
		ptyc_free_driver_ctx_impl(ictx);
0efa8c
	}
0efa8c
}
0efa8c
0efa8c
const struct ptyc_source_version * ptyc_source_version(void)
0efa8c
{
0efa8c
	return &ptyc_src_version;
0efa8c
}