Blame src/internal/slibtool_lconf_impl.c

0801fe
/*******************************************************************/
0801fe
/*  slibtool: a skinny libtool implementation, written in C        */
0801fe
/*  Copyright (C) 2016--2018  Z. Gilboa                            */
0801fe
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
0801fe
/*******************************************************************/
0801fe
0801fe
#include <fcntl.h>
0801fe
#include <stdio.h>
0801fe
#include <stdint.h>
0801fe
#include <stdbool.h>
0801fe
#include <unistd.h>
0801fe
#include <sys/mman.h>
0801fe
#include <sys/stat.h>
0801fe
0801fe
#include "slibtool_lconf_impl.h"
0801fe
#include "slibtool_driver_impl.h"
0801fe
#include "slibtool_errinfo_impl.h"
0801fe
#include "slibtool_symlink_impl.h"
0801fe
#include "slibtool_readlink_impl.h"
0801fe
0801fe
enum slbt_lconf_opt {
0801fe
	SLBT_LCONF_OPT_UNKNOWN,
0801fe
	SLBT_LCONF_OPT_NO,
0801fe
	SLBT_LCONF_OPT_YES,
0801fe
};
0801fe
0801fe
static void slbt_lconf_close(int fdcwd, int fdlconfdir)
0801fe
{
0801fe
	if (fdlconfdir != fdcwd)
0801fe
		close(fdlconfdir);
0801fe
}
0801fe
0801fe
static int slbt_lconf_open(
0801fe
	struct slbt_driver_ctx *	dctx,
0801fe
	const char *			lconf)
0801fe
{
0801fe
	int		fdcwd;
0801fe
	int		fdlconf;
0801fe
	int		fdlconfdir;
0801fe
	int		fdparent;
0801fe
	struct stat	stcwd;
0801fe
	struct stat	stparent;
0801fe
0801fe
	fdcwd      = slbt_driver_fdcwd(dctx);
0801fe
	fdlconfdir = fdcwd;
0801fe
0801fe
	if (lconf)
0801fe
		return ((fdlconf = openat(fdcwd,lconf,O_RDONLY,0)) < 0)
0801fe
			? SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LCONF_OPEN)
0801fe
			: fdlconf;
0801fe
0801fe
	if (fstatat(fdlconfdir,".",&stcwd,0) < 0)
0801fe
		return SLBT_SYSTEM_ERROR(dctx);
0801fe
0801fe
	fdlconf = openat(fdlconfdir,"libtool",O_RDONLY,0);
0801fe
0801fe
	while (fdlconf < 0) {
0801fe
		fdparent = openat(fdlconfdir,"../",O_DIRECTORY,0);
0801fe
		slbt_lconf_close(fdcwd,fdlconfdir);
0801fe
0801fe
		if (fdparent < 0)
0801fe
			return SLBT_SYSTEM_ERROR(dctx);
0801fe
0801fe
		if (fstat(fdparent,&stparent) < 0)
0801fe
			return SLBT_SYSTEM_ERROR(dctx);
0801fe
0801fe
		if (stparent.st_dev != stcwd.st_dev)
0801fe
			return SLBT_CUSTOM_ERROR(
0801fe
				dctx,SLBT_ERR_LCONF_OPEN);
0801fe
0801fe
		fdlconfdir = fdparent;
0801fe
		fdlconf    = openat(fdlconfdir,"libtool",O_RDONLY,0);
0801fe
	}
0801fe
0801fe
	return fdlconf;
0801fe
}
0801fe
0801fe
int slbt_get_lconf_flags(
0801fe
	struct slbt_driver_ctx *	dctx,
0801fe
	const char *			lconf,
0801fe
	uint64_t *			flags)
0801fe
{
0801fe
	int				fdlconf;
0801fe
	struct stat			st;
0801fe
	void *				addr;
0801fe
	const char *			mark;
0801fe
	const char *			cap;
0801fe
	uint64_t			optshared;
0801fe
	uint64_t			optstatic;
0801fe
	int				optlenmax;
0801fe
	int				optsharedlen;
0801fe
	int				optstaticlen;
0801fe
	const char *			optsharedstr;
0801fe
	const char *			optstaticstr;
0801fe
0801fe
	/* open relative libtool script */
0801fe
	if ((fdlconf = slbt_lconf_open(dctx,lconf)) < 0)
0801fe
		return SLBT_NESTED_ERROR(dctx);
0801fe
0801fe
	/* map relative libtool script */
0801fe
	if (fstat(fdlconf,&st) < 0)
0801fe
		return SLBT_SYSTEM_ERROR(dctx);
0801fe
0801fe
	addr = mmap(
0801fe
		0,st.st_size,
0801fe
		PROT_READ,MAP_SHARED,
0801fe
		fdlconf,0);
0801fe
0801fe
	close(fdlconf);
0801fe
0801fe
	if (addr == MAP_FAILED)
0801fe
		return SLBT_CUSTOM_ERROR(
0801fe
			dctx,SLBT_ERR_LCONF_MAP);
0801fe
0801fe
	mark = addr;
0801fe
	cap  = &mark[st.st_size];
0801fe
0801fe
	/* hard-coded options in the generated libtool precede the code */
0801fe
	if (st.st_size >= (optlenmax = strlen("build_libtool_libs=yes\n")))
0801fe
		cap -= optlenmax;
0801fe
0801fe
	/* scan */
0801fe
	optshared = 0;
0801fe
	optstatic = 0;
0801fe
0801fe
	optsharedstr = "build_libtool_libs=";
0801fe
	optstaticstr = "build_old_libs=";
0801fe
0801fe
	optsharedlen = strlen(optsharedstr);
0801fe
	optstaticlen = strlen(optstaticstr);
0801fe
0801fe
	for (; mark && mark
0801fe
		if (!strncmp(mark,optsharedstr,optsharedlen)) {
0801fe
			mark += optsharedlen;
0801fe
0801fe
			if ((mark[0]=='n')
0801fe
					&& (mark[1]=='o')
0801fe
					&& (mark[2]=='\n'))
0801fe
				optshared = SLBT_DRIVER_DISABLE_SHARED;
0801fe
0801fe
			if ((mark[0]=='y')
0801fe
					&& (mark[1]=='e')
0801fe
					&& (mark[2]=='s')
0801fe
					&& (mark[3]=='\n'))
0801fe
				optshared = SLBT_DRIVER_SHARED;
0801fe
0801fe
		} if (!strncmp(mark,optstaticstr,optstaticlen)) {
0801fe
			mark += optstaticlen;
0801fe
0801fe
			if ((mark[0]=='n')
0801fe
					&& (mark[1]=='o')
0801fe
					&& (mark[2]=='\n'))
0801fe
				optstatic = SLBT_DRIVER_DISABLE_STATIC;
0801fe
0801fe
			if ((mark[0]=='y')
0801fe
					&& (mark[1]=='e')
0801fe
					&& (mark[2]=='s')
0801fe
					&& (mark[3]=='\n'))
0801fe
				optstatic = SLBT_DRIVER_STATIC;
0801fe
		}
0801fe
0801fe
		if (optshared && optstatic)
0801fe
			mark = 0;
0801fe
0801fe
		else {
0801fe
			for (; (mark
0801fe
				mark++;
0801fe
			mark++;
0801fe
		}
0801fe
	}
0801fe
0801fe
	munmap(addr,st.st_size);
0801fe
0801fe
	if (!optshared || !optstatic)
0801fe
		return SLBT_CUSTOM_ERROR(
0801fe
			dctx,SLBT_ERR_LCONF_PARSE);
0801fe
0801fe
	*flags = optshared | optstatic;
0801fe
0801fe
	return 0;
0801fe
}