diff options
author | midipix <writeonce@midipix.org> | 2018-08-13 12:37:34 +0000 |
---|---|---|
committer | midipix <writeonce@midipix.org> | 2018-08-13 19:26:24 -0400 |
commit | 0801fe615c2657fec3205626c7ae60a28db680fe (patch) | |
tree | f728805fc4960e38f3ad2219c56a63298ead46ff /src/internal/slibtool_lconf_impl.c | |
parent | 6333087b29192cf14498ce1891d68b9335897e68 (diff) | |
download | slibtool-0801fe615c2657fec3205626c7ae60a28db680fe.tar.bz2 slibtool-0801fe615c2657fec3205626c7ae60a28db680fe.tar.xz |
internals: -shared/-static heuristics: added slbt_get_lconf_flags().
Diffstat (limited to 'src/internal/slibtool_lconf_impl.c')
-rw-r--r-- | src/internal/slibtool_lconf_impl.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/src/internal/slibtool_lconf_impl.c b/src/internal/slibtool_lconf_impl.c new file mode 100644 index 0000000..9daba91 --- /dev/null +++ b/src/internal/slibtool_lconf_impl.c @@ -0,0 +1,185 @@ +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016--2018 Z. Gilboa */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include <fcntl.h> +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> + +#include "slibtool_lconf_impl.h" +#include "slibtool_driver_impl.h" +#include "slibtool_errinfo_impl.h" +#include "slibtool_symlink_impl.h" +#include "slibtool_readlink_impl.h" + +enum slbt_lconf_opt { + SLBT_LCONF_OPT_UNKNOWN, + SLBT_LCONF_OPT_NO, + SLBT_LCONF_OPT_YES, +}; + +static void slbt_lconf_close(int fdcwd, int fdlconfdir) +{ + if (fdlconfdir != fdcwd) + close(fdlconfdir); +} + +static int slbt_lconf_open( + struct slbt_driver_ctx * dctx, + const char * lconf) +{ + int fdcwd; + int fdlconf; + int fdlconfdir; + int fdparent; + struct stat stcwd; + struct stat stparent; + + fdcwd = slbt_driver_fdcwd(dctx); + fdlconfdir = fdcwd; + + if (lconf) + return ((fdlconf = openat(fdcwd,lconf,O_RDONLY,0)) < 0) + ? SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LCONF_OPEN) + : fdlconf; + + if (fstatat(fdlconfdir,".",&stcwd,0) < 0) + return SLBT_SYSTEM_ERROR(dctx); + + fdlconf = openat(fdlconfdir,"libtool",O_RDONLY,0); + + while (fdlconf < 0) { + fdparent = openat(fdlconfdir,"../",O_DIRECTORY,0); + slbt_lconf_close(fdcwd,fdlconfdir); + + if (fdparent < 0) + return SLBT_SYSTEM_ERROR(dctx); + + if (fstat(fdparent,&stparent) < 0) + return SLBT_SYSTEM_ERROR(dctx); + + if (stparent.st_dev != stcwd.st_dev) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_OPEN); + + fdlconfdir = fdparent; + fdlconf = openat(fdlconfdir,"libtool",O_RDONLY,0); + } + + return fdlconf; +} + +int slbt_get_lconf_flags( + struct slbt_driver_ctx * dctx, + const char * lconf, + uint64_t * flags) +{ + int fdlconf; + struct stat st; + void * addr; + const char * mark; + const char * cap; + uint64_t optshared; + uint64_t optstatic; + int optlenmax; + int optsharedlen; + int optstaticlen; + const char * optsharedstr; + const char * optstaticstr; + + /* open relative libtool script */ + if ((fdlconf = slbt_lconf_open(dctx,lconf)) < 0) + return SLBT_NESTED_ERROR(dctx); + + if (fdlconf < 0) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_OPEN); + + /* map relative libtool script */ + if (fstat(fdlconf,&st) < 0) + return SLBT_SYSTEM_ERROR(dctx); + + addr = mmap( + 0,st.st_size, + PROT_READ,MAP_SHARED, + fdlconf,0); + + close(fdlconf); + + if (addr == MAP_FAILED) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_MAP); + + mark = addr; + cap = &mark[st.st_size]; + + /* hard-coded options in the generated libtool precede the code */ + if (st.st_size >= (optlenmax = strlen("build_libtool_libs=yes\n"))) + cap -= optlenmax; + + /* scan */ + optshared = 0; + optstatic = 0; + + optsharedstr = "build_libtool_libs="; + optstaticstr = "build_old_libs="; + + optsharedlen = strlen(optsharedstr); + optstaticlen = strlen(optstaticstr); + + for (; mark && mark<cap; ) { + if (!strncmp(mark,optsharedstr,optsharedlen)) { + mark += optsharedlen; + + if ((mark[0]=='n') + && (mark[1]=='o') + && (mark[2]=='\n')) + optshared = SLBT_DRIVER_DISABLE_SHARED; + + if ((mark[0]=='y') + && (mark[1]=='e') + && (mark[2]=='s') + && (mark[3]=='\n')) + optshared = SLBT_DRIVER_SHARED; + + } if (!strncmp(mark,optstaticstr,optstaticlen)) { + mark += optstaticlen; + + if ((mark[0]=='n') + && (mark[1]=='o') + && (mark[2]=='\n')) + optstatic = SLBT_DRIVER_DISABLE_STATIC; + + if ((mark[0]=='y') + && (mark[1]=='e') + && (mark[2]=='s') + && (mark[3]=='\n')) + optstatic = SLBT_DRIVER_STATIC; + } + + if (optshared && optstatic) + mark = 0; + + else { + for (; (mark<cap) && (*mark!='\n'); ) + mark++; + mark++; + } + } + + munmap(addr,st.st_size); + + if (!optshared || !optstatic) + return SLBT_CUSTOM_ERROR( + dctx,SLBT_ERR_LCONF_PARSE); + + *flags = optshared | optstatic; + + return 0; +} |