Blame src/driver/pe_driver_ctx.c

81e8b3
#include <stdint.h>
6f882b
#include <unistd.h>
81e8b3
#include <fcntl.h>
81e8b3
#include <perk/perk.h>
949bb3
#include <perk/perk_output.h>
81e8b3
#include "argv/argv.h"
81e8b3
81e8b3
enum app_tags {
81e8b3
	TAG_HELP,
81e8b3
	TAG_VERSION,
81e8b3
	TAG_OUTPUT,
0d3dde
	TAG_PRETTY,
81e8b3
	TAG_EXPSYMS,
9c5807
	TAG_IMPLIBS,
9c5807
	TAG_IMPSYMS,
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
0d3dde
	{"pretty",	'p',TAG_PRETTY,	ARGV_OPTARG_REQUIRED,	"yaml",0,
0d3dde
								"format output for parsing by %s"},
0d3dde
81e8b3
	{"expsyms",	'e',TAG_EXPSYMS,ARGV_OPTARG_NONE,	0,0,
81e8b3
								"print exported symbols" },
9c5807
9c5807
	{"implibs",	'i',TAG_IMPLIBS,ARGV_OPTARG_NONE,	0,0,
9c5807
								"list direct dependency libraries"},
9c5807
9c5807
	{"impsyms",	'I',TAG_IMPSYMS,ARGV_OPTARG_NONE,	0,0,
9c5807
								"list direct dependency libraries "
9c5807
								"along with required 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
dd97ea
static int pe_driver_usage(
6f882b
	const char *		program,
6f882b
	const char *		arg,
dd97ea
	struct argv_meta *	meta)
dd97ea
{
dd97ea
	char header[512];
dd97ea
dd97ea
	snprintf(header,sizeof(header),
dd97ea
		"Usage: %s [options] <file>...\n" "Options:\n",
dd97ea
		program);
dd97ea
dd97ea
	argv_usage(stdout,header,options,arg);
dd97ea
	argv_free(meta);
dd97ea
dd97ea
	return PERK_USAGE;
dd97ea
}
dd97ea
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;
0d3dde
	const char *		pretty;
81e8b3
	int			fdout;
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;
0d3dde
	pretty	= 0;
81e8b3
	nunits	= 0;
81e8b3
	program = argv_program_name(argv[0]);
81e8b3
dd97ea
	if (!argv[1] && (flags & PERK_DRIVER_VERBOSITY_USAGE))
dd97ea
		return pe_driver_usage(program,0,meta);
dd97ea
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:
dd97ea
					if (flags & PERK_DRIVER_VERBOSITY_USAGE)
dd97ea
						return pe_driver_usage(program,entry->arg,meta);
81e8b3
81e8b3
				case TAG_VERSION:
8fd1f5
					dflags |= PERK_DRIVER_VERSION;
81e8b3
					break;
81e8b3
81e8b3
				case TAG_OUTPUT:
81e8b3
					output = entry->arg;
81e8b3
					break;
81e8b3
0d3dde
				case TAG_PRETTY:
0d3dde
					pretty = entry->arg;
0d3dde
					break;
0d3dde
81e8b3
				case TAG_EXPSYMS:
8fd1f5
					fflags |= PERK_OUTPUT_EXPORT_SYMS;
81e8b3
					break;
9c5807
9c5807
				case TAG_IMPLIBS:
9c5807
					fflags |= PERK_OUTPUT_IMPORT_LIBS;
9c5807
					break;
9c5807
9c5807
				case TAG_IMPSYMS:
9c5807
					fflags |= PERK_OUTPUT_IMPORT_SYMS;
9c5807
					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
0d3dde
	if (pretty && !strcmp(pretty,"yaml"))
0d3dde
		fflags |= PERK_PRETTY_YAML;
0d3dde
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
}