diff options
Diffstat (limited to 'src/logic/slbt_exec_ar.c')
-rw-r--r-- | src/logic/slbt_exec_ar.c | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/src/logic/slbt_exec_ar.c b/src/logic/slbt_exec_ar.c new file mode 100644 index 0000000..ba56f5b --- /dev/null +++ b/src/logic/slbt_exec_ar.c @@ -0,0 +1,431 @@ +/*******************************************************************/ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include <slibtool/slibtool.h> +#include <slibtool/slibtool_output.h> +#include "slibtool_driver_impl.h" +#include "slibtool_ar_impl.h" +#include "slibtool_errinfo_impl.h" +#include "argv/argv.h" + +#define SLBT_DRIVER_MODE_AR_ACTIONS (SLBT_DRIVER_MODE_AR_CHECK \ + | SLBT_DRIVER_MODE_AR_MERGE) + +#define SLBT_DRIVER_MODE_AR_OUTPUTS (SLBT_OUTPUT_ARCHIVE_MEMBERS \ + | SLBT_OUTPUT_ARCHIVE_HEADERS \ + | SLBT_OUTPUT_ARCHIVE_SYMBOLS \ + | SLBT_OUTPUT_ARCHIVE_ARMAPS) + +#define SLBT_PRETTY_FLAGS (SLBT_PRETTY_YAML \ + | SLBT_PRETTY_POSIX \ + | SLBT_PRETTY_HEXDATA) + +static int slbt_ar_usage( + int fdout, + const char * program, + const char * arg, + const struct argv_option ** optv, + struct argv_meta * meta, + struct slbt_exec_ctx * ectx, + int noclr) +{ + char header[512]; + bool armode; + const char * dash; + + armode = (dash = strrchr(program,'-')) + && !strcmp(++dash,"ar"); + + snprintf(header,sizeof(header), + "Usage: %s%s [options] [ARCHIVE-FILE] [ARCHIVE_FILE] ...\n" + "Options:\n", + program, + armode ? "" : " --mode=ar"); + + switch (noclr) { + case 0: + slbt_argv_usage(fdout,header,optv,arg); + break; + + default: + slbt_argv_usage_plain(fdout,header,optv,arg); + break; + } + + if (ectx) + slbt_ectx_free_exec_ctx(ectx); + + slbt_argv_free(meta); + + return SLBT_USAGE; +} + +static int slbt_exec_ar_fail( + struct slbt_exec_ctx * ectx, + struct argv_meta * meta, + int ret) +{ + slbt_argv_free(meta); + slbt_ectx_free_exec_ctx(ectx); + return ret; +} + +static int slbt_exec_ar_perform_archive_actions( + const struct slbt_driver_ctx * dctx, + struct slbt_archive_ctx ** arctxv) +{ + struct slbt_archive_ctx ** arctxp; + struct slbt_archive_ctx * arctx; + bool farname; + + switch (dctx->cctx->fmtflags & SLBT_PRETTY_FLAGS) { + case SLBT_PRETTY_POSIX: + farname = (arctxv[0] && arctxv[1]); + break; + + default: + farname = true; + break; + } + + for (arctxp=arctxv; *arctxp; arctxp++) { + if (dctx->cctx->fmtflags & SLBT_DRIVER_MODE_AR_OUTPUTS) + if (farname && (slbt_au_output_arname(*arctxp) < 0)) + return SLBT_NESTED_ERROR(dctx); + + if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_MEMBERS) + if (slbt_au_output_members((*arctxp)->meta) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_SYMBOLS) + if (slbt_au_output_symbols((*arctxp)->meta) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_MAPFILE) + if (slbt_au_output_mapfile((*arctxp)->meta) < 0) + return SLBT_NESTED_ERROR(dctx); + } + + if (dctx->cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_DLSYMS) + if (slbt_au_output_dlsyms(arctxv,dctx->cctx->dlunit) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (dctx->cctx->drvflags & SLBT_DRIVER_MODE_AR_MERGE) { + if (slbt_ar_merge_archives(arctxv,&arctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* (defer mode to umask) */ + if (slbt_ar_store_archive(arctx,dctx->cctx->output,0666) < 0) + return SLBT_NESTED_ERROR(dctx); + } + + return 0; +} + +int slbt_exec_ar(const struct slbt_driver_ctx * dctx) +{ + int ret; + int fdout; + int fderr; + char ** argv; + char ** iargv; + struct slbt_exec_ctx * ectx; + struct slbt_driver_ctx_impl * ictx; + const struct slbt_common_ctx * cctx; + struct slbt_archive_ctx ** arctxv; + struct slbt_archive_ctx ** arctxp; + const char ** unitv; + const char ** unitp; + size_t nunits; + struct argv_meta * meta; + struct argv_entry * entry; + const struct argv_option * optv[SLBT_OPTV_ELEMENTS]; + + /* context */ + if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* initial state, ar mode skin */ + slbt_ectx_reset_arguments(ectx); + slbt_disable_placeholders(ectx); + + ictx = slbt_get_driver_ictx(dctx); + cctx = dctx->cctx; + iargv = ectx->cargv; + + fdout = slbt_driver_fdout(dctx); + fderr = slbt_driver_fderr(dctx); + + /* missing arguments? */ + slbt_optv_init(slbt_ar_options,optv); + + if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE)) + return slbt_ar_usage( + fdout, + dctx->program, + 0,optv,0,ectx, + dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER); + + /* <ar> argv meta */ + if (!(meta = slbt_argv_get( + iargv,optv, + dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS + ? ARGV_VERBOSITY_ERRORS + : ARGV_VERBOSITY_NONE, + fdout))) + return slbt_exec_ar_fail( + ectx,meta, + SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_AR_FAIL)); + + /* dest, alternate argument vector options */ + argv = ectx->altv; + *argv++ = iargv[0]; + nunits = 0; + + for (entry=meta->entries; entry->fopt || entry->arg; entry++) { + if (entry->fopt) { + switch (entry->tag) { + case TAG_AR_HELP: + slbt_ar_usage( + fdout, + dctx->program, + 0,optv,0,ectx, + dctx->cctx->drvflags + & SLBT_DRIVER_ANNOTATE_NEVER); + + ictx->cctx.drvflags |= SLBT_DRIVER_VERSION; + ictx->cctx.drvflags ^= SLBT_DRIVER_VERSION; + + slbt_argv_free(meta); + + return SLBT_OK; + + case TAG_AR_VERSION: + ictx->cctx.drvflags |= SLBT_DRIVER_VERSION; + break; + + case TAG_AR_CHECK: + ictx->cctx.drvflags |= SLBT_DRIVER_MODE_AR_CHECK; + break; + + case TAG_AR_MERGE: + ictx->cctx.drvflags |= SLBT_DRIVER_MODE_AR_MERGE; + break; + + case TAG_AR_OUTPUT: + ictx->cctx.output = entry->arg; + break; + + case TAG_AR_PRINT: + if (!entry->arg) + ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_MEMBERS; + + else if (!strcmp(entry->arg,"members")) + ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_MEMBERS; + + else if (!strcmp(entry->arg,"headers")) + ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_HEADERS; + + else if (!strcmp(entry->arg,"symbols")) + ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_SYMBOLS; + + else if (!strcmp(entry->arg,"armaps")) + ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_ARMAPS; + + break; + + case TAG_AR_MAPFILE: + ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_MAPFILE; + break; + + case TAG_AR_DLSYMS: + ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_DLSYMS; + break; + + case TAG_AR_DLUNIT: + ictx->cctx.dlunit = entry->arg; + break; + + case TAG_AR_NOSORT: + ictx->cctx.fmtflags |= SLBT_OUTPUT_ARCHIVE_NOSORT; + break; + + case TAG_AR_REGEX: + ictx->cctx.regex = entry->arg; + break; + + case TAG_AR_PRETTY: + if (!strcmp(entry->arg,"yaml")) { + ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS; + ictx->cctx.fmtflags |= SLBT_PRETTY_YAML; + + } else if (!strcmp(entry->arg,"posix")) { + ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS; + ictx->cctx.fmtflags |= SLBT_PRETTY_POSIX; + } + + break; + + case TAG_AR_POSIX: + ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS; + ictx->cctx.fmtflags |= SLBT_PRETTY_POSIX; + break; + + case TAG_AR_YAML: + ictx->cctx.fmtflags &= ~(uint64_t)SLBT_PRETTY_FLAGS; + ictx->cctx.fmtflags |= SLBT_PRETTY_YAML; + break; + + case TAG_AR_VERBOSE: + ictx->cctx.fmtflags |= SLBT_PRETTY_VERBOSE; + break; + } + + if (entry->fval) { + *argv++ = (char *)entry->arg; + } + } else { + nunits++; + }; + } + + /* defer --version printing to slbt_main() as needed */ + if (cctx->drvflags & SLBT_DRIVER_VERSION) { + slbt_argv_free(meta); + slbt_ectx_free_exec_ctx(ectx); + return SLBT_OK; + } + + /* at least one action must be specified */ + if (cctx->fmtflags & SLBT_DRIVER_MODE_AR_OUTPUTS) { + (void)0; + + } else if (cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_MAPFILE) { + (void)0; + + } else if (cctx->fmtflags & SLBT_OUTPUT_ARCHIVE_DLSYMS) { + if (!cctx->dlunit) { + slbt_dprintf(fderr, + "%s: missing -Wdlunit: generation of a dlsyms vtable " + "requires the name of the dynamic library, executable " + "program, or dynamic module for which the vtable would " + "be generated.\n", + dctx->program); + + return slbt_exec_ar_fail( + ectx,meta, + SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_DLUNIT_NOT_SPECIFIED)); + } + } else if (!(cctx->drvflags & SLBT_DRIVER_MODE_AR_ACTIONS)) { + if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_dprintf(fderr, + "%s: at least one action must be specified\n", + dctx->program); + + return slbt_exec_ar_fail( + ectx,meta, + SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_NO_ACTION_SPECIFIED)); + } + + /* -Wmerge without -Woutput? */ + if ((cctx->drvflags & SLBT_DRIVER_MODE_AR_MERGE) && !cctx->output) { + if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_dprintf(fderr, + "%s: archive merging: output must be specified.\n", + dctx->program); + + return slbt_exec_ar_fail( + ectx,meta, + SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_OUTPUT_NOT_SPECIFIED)); + } + + + /* -Woutput without -Wmerge? */ + if (cctx->output && !(cctx->drvflags & SLBT_DRIVER_MODE_AR_MERGE)) { + if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_dprintf(fderr, + "%s: output may only be specified " + "when merging one or more archives.\n", + dctx->program); + + return slbt_exec_ar_fail( + ectx,meta, + SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_OUTPUT_NOT_APPLICABLE)); + } + + + /* at least one unit must be specified */ + if (!nunits) { + if (cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS) + slbt_dprintf(fderr, + "%s: all actions require at least one input unit\n", + dctx->program); + + return slbt_exec_ar_fail( + ectx,meta, + SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_AR_NO_INPUT_SPECIFIED)); + } + + /* archive vector allocation */ + if (!(arctxv = calloc(nunits+1,sizeof(struct slbt_archive_ctx *)))) + return slbt_exec_ar_fail( + ectx,meta, + SLBT_SYSTEM_ERROR(dctx,0)); + + /* unit vector allocation */ + if (!(unitv = calloc(nunits+1,sizeof(const char *)))) { + free (arctxv); + + return slbt_exec_ar_fail( + ectx,meta, + SLBT_SYSTEM_ERROR(dctx,0)); + } + + /* unit vector initialization */ + for (entry=meta->entries,unitp=unitv; entry->fopt || entry->arg; entry++) + if (!entry->fopt) + *unitp++ = entry->arg; + + /* archive context vector initialization */ + for (unitp=unitv,arctxp=arctxv; *unitp; unitp++,arctxp++) { + if (slbt_ar_get_archive_ctx(dctx,*unitp,arctxp) < 0) { + for (arctxp=arctxv; *arctxp; arctxp++) + slbt_ar_free_archive_ctx(*arctxp); + + free(unitv); + free(arctxv); + + return slbt_exec_ar_fail( + ectx,meta, + SLBT_NESTED_ERROR(dctx)); + } + } + + /* archive operations */ + ret = slbt_exec_ar_perform_archive_actions(dctx,arctxv); + + /* all done */ + for (arctxp=arctxv; *arctxp; arctxp++) + slbt_ar_free_archive_ctx(*arctxp); + + free(unitv); + free(arctxv); + + slbt_argv_free(meta); + slbt_ectx_free_exec_ctx(ectx); + + return ret; +} |