Blame src/driver/pe_driver_ctx.c

e2e2c2
/***************************************************************/
e2e2c2
/*  perk: PE Resource Kit                                      */
e2e2c2
/*  Copyright (C) 2015--2016  Z. Gilboa                        */
e2e2c2
/*  Released under GPLv2 and GPLv3; see COPYING.PERK.          */
e2e2c2
/***************************************************************/
e2e2c2
81e8b3
#include <stdint.h>
6f882b
#include <unistd.h>
81e8b3
#include <fcntl.h>
c61328
249590
#define ARGV_DRIVER
249590
81e8b3
#include <perk/perk.h>
949bb3
#include <perk/perk_output.h>
b7025c
#include "perk_version.h"
249590
#include "perk_driver_impl.h"
81e8b3
#include "argv/argv.h"
81e8b3
b7025c
/* package info */
b7025c
static const struct pe_source_version pe_src_version = {
b7025c
	PERK_TAG_VER_MAJOR,
b7025c
	PERK_TAG_VER_MINOR,
b7025c
	PERK_TAG_VER_PATCH,
b7025c
	PERK_GIT_VERSION
b7025c
};
b7025c
1711ab
struct pe_driver_ctx_alloc {
44d7e6
	struct argv_meta *		meta;
c61328
	struct pe_driver_ctx_impl	ctx;
44d7e6
	uint64_t			guard;
44d7e6
	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(
612b7d
	const char *			program,
612b7d
	const char *			arg,
249590
	const struct argv_option *	options,
612b7d
	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
99763f
static struct pe_driver_ctx_impl * pe_driver_ctx_alloc(
99763f
	struct argv_meta *		meta,
99763f
	const struct pe_common_ctx *	cctx,
99763f
	size_t				nunits)
81e8b3
{
1711ab
	struct pe_driver_ctx_alloc *	ictx;
81e8b3
	size_t				size;
81e8b3
	struct argv_entry *		entry;
81e8b3
	const char **			units;
c9c5f7
	int				elements;
81e8b3
1711ab
	size =  sizeof(struct pe_driver_ctx_alloc);
81e8b3
	size += (nunits+1)*sizeof(const char *);
81e8b3
ffcd00
	if (!(ictx = calloc(1,size)))
81e8b3
		return 0;
81e8b3
99763f
	if (cctx)
99763f
		memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx));
99763f
c9c5f7
	elements = sizeof(ictx->ctx.erribuf) / sizeof(*ictx->ctx.erribuf);
c9c5f7
c9c5f7
	ictx->ctx.errinfp  = &ictx->ctx.erriptr[0];
c9c5f7
	ictx->ctx.erricap  = &ictx->ctx.erriptr[--elements];
c9c5f7
81e8b3
	ictx->meta		= meta;
1d9a6e
	ictx->ctx.cctx.symctx	= &ictx->ctx.symctx;
1d9a6e
	ictx->ctx.cctx.outctx	= &ictx->ctx.outctx;
1d9a6e
	ictx->ctx.cctx.lnkctx	= &ictx->ctx.lnkctx;
1d9a6e
	ictx->ctx.cctx.srvctx	= &ictx->ctx.srvctx;
76aabf
	ictx->ctx.cctx.ioctx	= &ictx->ctx.ioctx;
81e8b3
81e8b3
	for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++)
81e8b3
		if (!entry->fopt)
81e8b3
			*units++ = entry->arg;
81e8b3
c61328
	ictx->ctx.ctx.units = ictx->units;
c9c5f7
	ictx->ctx.ctx.errv  = ictx->ctx.errinfp;
81e8b3
	return &ictx->ctx;
81e8b3
}
81e8b3
712fa6
static 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(
7d4640
	char **			argv,
7d4640
	char **			envp,
81e8b3
	uint32_t		flags,
81e8b3
	struct pe_driver_ctx ** pctx)
81e8b3
{
c61328
	struct pe_driver_ctx_impl *	ctx;
dccbc5
	struct pe_common_ctx		cctx;
249590
	const struct argv_option *	options;
44d7e6
	struct argv_meta *		meta;
44d7e6
	struct argv_entry *		entry;
44d7e6
	size_t				nunits;
44d7e6
	const char *			program;
44d7e6
	const char *			pretty;
44d7e6
	int				fdout;
81e8b3
209439
	(void)envp;
209439
249590
	options = pe_default_options;
249590
81e8b3
	if (!(meta = argv_get(argv,options,pe_argv_flags(flags))))
81e8b3
		return -1;
81e8b3
0d3dde
	pretty	= 0;
81e8b3
	nunits	= 0;
4e7a71
	fdout	= 0;
81e8b3
	program = argv_program_name(argv[0]);
dccbc5
	memset(&cctx,0,sizeof(cctx));
b70615
	cctx.drvflags = flags;
81e8b3
dd97ea
	if (!argv[1] && (flags & PERK_DRIVER_VERBOSITY_USAGE))
249590
		return pe_driver_usage(program,0,options,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)
249590
						return pe_driver_usage(program,entry->arg,options,meta);
81e8b3
81e8b3
				case TAG_VERSION:
dccbc5
					cctx.drvflags |= PERK_DRIVER_VERSION;
81e8b3
					break;
81e8b3
81e8b3
				case TAG_OUTPUT:
dccbc5
					cctx.output = entry->arg;
81e8b3
					break;
81e8b3
0d3dde
				case TAG_PRETTY:
0d3dde
					pretty = entry->arg;
0d3dde
					break;
0d3dde
81e8b3
				case TAG_EXPSYMS:
dccbc5
					cctx.fmtflags |= PERK_OUTPUT_EXPORT_SYMS;
81e8b3
					break;
9c5807
9c5807
				case TAG_IMPLIBS:
dccbc5
					cctx.fmtflags |= PERK_OUTPUT_IMPORT_LIBS;
9c5807
					break;
9c5807
9c5807
				case TAG_IMPSYMS:
dccbc5
					cctx.fmtflags |= PERK_OUTPUT_IMPORT_SYMS;
9c5807
					break;
81e8b3
			}
81e8b3
		} else
81e8b3
			nunits++;
81e8b3
	}
81e8b3
dccbc5
	if (cctx.output && ((fdout = open(cctx.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
99763f
	if (pretty && !strcmp(pretty,"yaml"))
99763f
		cctx.fmtflags |= PERK_PRETTY_YAML;
08a894
	else if (pretty && !strcmp(pretty,"dlltool"))
08a894
		cctx.fmtflags |= PERK_PRETTY_DLLTOOL;
99763f
99763f
	if (!(ctx = pe_driver_ctx_alloc(meta,&cctx,nunits)) && cctx.output)
2699a2
		close(fdout);
2699a2
2699a2
	if (!ctx)
81e8b3
		return pe_get_driver_ctx_fail(meta);
81e8b3
c61328
	ctx->ctx.program	= program;
99763f
	ctx->ctx.cctx		= &ctx->cctx;
81e8b3
99763f
	ctx->ioctx.fdout	= cctx.output ? fdout : -1;
76aabf
	ctx->ioctx.fdin		= -1;
76aabf
	ctx->ioctx.fderr	= -1;
76aabf
	ctx->ioctx.fdlog	= -1;
76aabf
	ctx->ioctx.fdsrc	= AT_FDCWD;
76aabf
	ctx->ioctx.fddst	= AT_FDCWD;
76aabf
	ctx->ioctx.fdtmp	= AT_FDCWD;
81e8b3
c61328
	*pctx = &ctx->ctx;
81e8b3
	return PERK_OK;
81e8b3
}
81e8b3
81e8b3
static void pe_driver_close_fds(struct pe_common_ctx * cctx)
81e8b3
{
76aabf
	if (cctx->ioctx->status && cctx->output)
76aabf
		unlinkat(cctx->ioctx->fddst,cctx->output,0);
81e8b3
76aabf
	if (cctx->ioctx->fdout >= 0)
76aabf
		close(cctx->ioctx->fdout);
81e8b3
}
81e8b3
1711ab
static void pe_free_driver_ctx_impl(struct pe_driver_ctx_alloc * ictx)
81e8b3
{
1d9a6e
	if (ictx->ctx.symctx.append)
1d9a6e
		free(ictx->ctx.symctx.append);
81e8b3
1d9a6e
	if (ictx->ctx.symctx.exclude)
1d9a6e
		free(ictx->ctx.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
{
1711ab
	struct pe_driver_ctx_alloc *	ictx;
81e8b3
	uintptr_t			addr;
81e8b3
81e8b3
	if (ctx) {
95fab3
		addr = (uintptr_t)ctx - offsetof(struct pe_driver_ctx_impl,ctx);
95fab3
		addr = addr - offsetof(struct pe_driver_ctx_alloc,ctx);
1711ab
		ictx = (struct pe_driver_ctx_alloc *)addr;
81e8b3
		pe_free_driver_ctx_impl(ictx);
81e8b3
	}
81e8b3
}
b7025c
b7025c
const struct pe_source_version * pe_source_version(void)
b7025c
{
b7025c
	return &pe_src_version;
b7025c
}