diff --git a/include/slibtool/slibtool.h b/include/slibtool/slibtool.h index e06ef79..fac022f 100644 --- a/include/slibtool/slibtool.h +++ b/include/slibtool/slibtool.h @@ -87,6 +87,9 @@ enum slbt_custom_error { SLBT_ERR_LINK_FREQ, SLBT_ERR_BAD_DATA, SLBT_ERR_UNINSTALL_FAIL, + SLBT_ERR_LCONF_OPEN, + SLBT_ERR_LCONF_MAP, + SLBT_ERR_LCONF_PARSE, }; /* execution modes */ diff --git a/project/common.mk b/project/common.mk index 9267415..e08e900 100644 --- a/project/common.mk +++ b/project/common.mk @@ -21,6 +21,7 @@ API_SRCS = \ INTERNAL_SRCS = \ src/internal/$(PACKAGE)_dprintf_impl.c \ src/internal/$(PACKAGE)_errinfo_impl.c \ + src/internal/$(PACKAGE)_lconf_impl.c \ src/internal/$(PACKAGE)_libmeta_impl.c \ src/internal/$(PACKAGE)_mapfile_impl.c \ src/internal/$(PACKAGE)_objmeta_impl.c \ diff --git a/project/headers.mk b/project/headers.mk index 2581965..62b6f52 100644 --- a/project/headers.mk +++ b/project/headers.mk @@ -8,6 +8,7 @@ INTERNAL_HEADERS = \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_driver_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_errinfo_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_install_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_lconf_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_mapfile_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_metafile_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_mkdir_impl.h \ 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 +#include +#include +#include +#include +#include +#include + +#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 + +struct slbt_driver_ctx; + +int slbt_get_lconf_flags( + struct slbt_driver_ctx * dctx, + const char * lconf, + uint64_t * flags); + +#endif