Blame src/driver/pe_driver_ctx.c

81e8b3
#include <stdint.h>
81e8b3
#include <fcntl.h>
81e8b3
#include <perk/perk.h>
81e8b3
#include "argv/argv.h"
81e8b3
81e8b3
enum app_tags {
81e8b3
	TAG_HELP,
81e8b3
	TAG_VERSION,
81e8b3
	TAG_OUTPUT,
81e8b3
	TAG_EXPSYMS,
81e8b3
};
81e8b3
81e8b3
static const struct argv_option options[] = {
81e8b3
	{"version",	'v',TAG_VERSION,ARGV_OPTARG_NONE,	0,0,
81e8b3
								"show version information"},
81e8b3
81e8b3
	{"help",	'h',TAG_HELP,	ARGV_OPTARG_OPTIONAL,	"short|long",0,
81e8b3
								"show usage information "
81e8b3
								"[listing %s options only]"},
81e8b3
81e8b3
	{"output",	'o',TAG_OUTPUT,	ARGV_OPTARG_REQUIRED,	0,"<file>",
81e8b3
								"write output to %s"},
81e8b3
81e8b3
	{"expsyms",	'e',TAG_EXPSYMS,ARGV_OPTARG_NONE,	0,0,
81e8b3
								"print exported symbols" },
81e8b3
	{0}
81e8b3
};
81e8b3
81e8b3
struct pe_driver_ctx_impl {
81e8b3
	struct argv_meta *	meta;
81e8b3
	struct pe_symbol_ctx	symctx;
81e8b3
	struct pe_output_ctx	outctx;
81e8b3
	struct pe_linker_ctx	lnkctx;
81e8b3
	struct pe_server_ctx	srvctx;
81e8b3
	struct pe_driver_ctx	ctx;
81e8b3
	uint64_t		guard;
81e8b3
	const char *		units[];
81e8b3
};
81e8b3
81e8b3
static uint32_t pe_argv_flags(uint32_t flags)
81e8b3
{
81e8b3
	uint32_t ret = 0;
81e8b3
81e8b3
	if (flags & PERK_DRIVER_VERBOSITY_NONE)
81e8b3
		ret |= ARGV_VERBOSITY_NONE;
81e8b3
81e8b3
	if (flags & PERK_DRIVER_VERBOSITY_ERRORS)
81e8b3
		ret |= ARGV_VERBOSITY_ERRORS;
81e8b3
81e8b3
	if (flags & PERK_DRIVER_VERBOSITY_STATUS)
81e8b3
		ret |= ARGV_VERBOSITY_STATUS;
81e8b3
81e8b3
	return ret;
81e8b3
}
81e8b3
81e8b3
static struct pe_driver_ctx * pe_driver_ctx_alloc(struct argv_meta * meta, size_t nunits)
81e8b3
{
81e8b3
	struct pe_driver_ctx_impl *	ictx;
81e8b3
	size_t				size;
81e8b3
	struct argv_entry *		entry;
81e8b3
	const char **			units;
81e8b3
81e8b3
	size =  sizeof(struct pe_driver_ctx_impl);
81e8b3
	size += (nunits+1)*sizeof(const char *);
81e8b3
81e8b3
	if (!(ictx = calloc(size,1)))
81e8b3
		return 0;
81e8b3
81e8b3
	ictx->meta		= meta;
81e8b3
	ictx->ctx.cctx.symctx	= &ictx->symctx;
81e8b3
	ictx->ctx.cctx.outctx	= &ictx->outctx;
81e8b3
	ictx->ctx.cctx.lnkctx	= &ictx->lnkctx;
81e8b3
	ictx->ctx.cctx.srvctx	= &ictx->srvctx;
81e8b3
81e8b3
	for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++)
81e8b3
		if (!entry->fopt)
81e8b3
			*units++ = entry->arg;
81e8b3
81e8b3
	ictx->ctx.units = ictx->units;
81e8b3
	return &ictx->ctx;
81e8b3
}
81e8b3
81e8b3
int pe_get_driver_ctx_fail(struct argv_meta * meta)
81e8b3
{
81e8b3
	argv_free(meta);
81e8b3
	return -1;
81e8b3
}
81e8b3
81e8b3
int pe_get_driver_ctx(
81e8b3
	const char **		argv,
81e8b3
	const char **		envp,
81e8b3
	uint32_t		flags,
81e8b3
	struct pe_driver_ctx ** pctx)
81e8b3
{
81e8b3
	struct pe_driver_ctx *	ctx;
81e8b3
	struct argv_meta *	meta;
81e8b3
	struct argv_entry *	entry;
81e8b3
	size_t			nunits;
81e8b3
	uint64_t		dflags;
81e8b3
	uint64_t		fflags;
81e8b3
	const char *		program;
81e8b3
	const char *		output;
81e8b3
	int			fdout;
81e8b3
	char			header[512];
81e8b3
81e8b3
	if (!(meta = argv_get(argv,options,pe_argv_flags(flags))))
81e8b3
		return -1;
81e8b3
81e8b3
	dflags	= 0;
81e8b3
	fflags	= 0;
81e8b3
	output	= 0;
81e8b3
	nunits	= 0;
81e8b3
	program = argv_program_name(argv[0]);
81e8b3
81e8b3
	/* get options, count units */
81e8b3
	for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
81e8b3
		if (entry->fopt) {
81e8b3
			switch (entry->tag) {
81e8b3
				case TAG_HELP:
81e8b3
					if (flags & PERK_DRIVER_VERBOSITY_USAGE) {
81e8b3
						snprintf(header,sizeof(header),
81e8b3
							"Usage: %s [options] <file>...\n" "Options:\n",
81e8b3
							program);
81e8b3
81e8b3
						argv_usage(stdout,header,options,entry->arg);
81e8b3
						argv_free(meta);
81e8b3
						return PERK_USAGE;
81e8b3
					}
81e8b3
81e8b3
				case TAG_VERSION:
8fd1f5
					dflags |= PERK_DRIVER_VERSION;
81e8b3
					break;
81e8b3
81e8b3
				case TAG_OUTPUT:
81e8b3
					output = entry->arg;
81e8b3
					break;
81e8b3
81e8b3
				case TAG_EXPSYMS:
8fd1f5
					fflags |= PERK_OUTPUT_EXPORT_SYMS;
81e8b3
					break;
81e8b3
			}
81e8b3
		} else
81e8b3
			nunits++;
81e8b3
	}
81e8b3
81e8b3
	if (output && ((fdout = open(output,
81e8b3
			O_CREAT|O_TRUNC|O_WRONLY|O_NOCTTY|O_NOFOLLOW,
81e8b3
			S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0))
81e8b3
		return pe_get_driver_ctx_fail(meta);
81e8b3
2699a2
	if (!(ctx = pe_driver_ctx_alloc(meta,nunits)) && output)
2699a2
		close(fdout);
2699a2
2699a2
	if (!ctx)
81e8b3
		return pe_get_driver_ctx_fail(meta);
81e8b3
81e8b3
	ctx->program		= program;
81e8b3
	ctx->cctx.drvflags	= dflags;
81e8b3
	ctx->cctx.fmtflags	= fflags;
81e8b3
	ctx->cctx.output	= output;
81e8b3
	ctx->cctx.fdout		= output ? fdout : -1;
81e8b3
81e8b3
	ctx->cctx.fdin		= -1;
81e8b3
	ctx->cctx.fderr		= -1;
81e8b3
	ctx->cctx.fdlog		= -1;
81e8b3
	ctx->cctx.fdsrc		= AT_FDCWD;
81e8b3
	ctx->cctx.fddst		= AT_FDCWD;
81e8b3
	ctx->cctx.fdtmp		= AT_FDCWD;
81e8b3
81e8b3
	*pctx = ctx;
81e8b3
	return PERK_OK;
81e8b3
}
81e8b3
81e8b3
static void pe_driver_close_fds(struct pe_common_ctx * cctx)
81e8b3
{
81e8b3
	if (cctx->status && cctx->output)
81e8b3
		unlinkat(cctx->fddst,cctx->output,0);
81e8b3
81e8b3
	if (cctx->fdout >= 0)
81e8b3
		close(cctx->fdout);
81e8b3
}
81e8b3
81e8b3
static void pe_free_driver_ctx_impl(struct pe_driver_ctx_impl * ictx)
81e8b3
{
81e8b3
	if (ictx->symctx.append)
81e8b3
		free(ictx->symctx.append);
81e8b3
81e8b3
	if (ictx->symctx.exclude)
81e8b3
		free(ictx->symctx.exclude);
81e8b3
81e8b3
	pe_driver_close_fds(&ictx->ctx.cctx);
81e8b3
	argv_free(ictx->meta);
81e8b3
	free(ictx);
81e8b3
}
81e8b3
81e8b3
void pe_free_driver_ctx(struct pe_driver_ctx * ctx)
81e8b3
{
81e8b3
	struct pe_driver_ctx_impl *	ictx;
81e8b3
	uintptr_t			addr;
81e8b3
81e8b3
	if (ctx) {
81e8b3
		addr = (uintptr_t)ctx - offsetof(struct pe_driver_ctx_impl,ctx);
81e8b3
		ictx = (struct pe_driver_ctx_impl *)addr;
81e8b3
		pe_free_driver_ctx_impl(ictx);
81e8b3
	}
81e8b3
}