Blame src/internal/slibtool_lconf_impl.c

0801fe
/*******************************************************************/
eac61a
/*  slibtool: a strong libtool implementation, written in C        */
49181b
/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
0801fe
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
0801fe
/*******************************************************************/
0801fe
20aece
#include <ctype.h>
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"
d4b2a5
#include "slibtool_realpath_impl.h"
4b56de
#include "slibtool_visibility_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
c58607
static const char aclr_reset[]   = "\x1b[0m";
c58607
static const char aclr_bold[]    = "\x1b[1m";
c58607
c58607
static const char aclr_red[]     = "\x1b[31m";
c58607
static const char aclr_green[]   = "\x1b[32m";
c58607
static const char aclr_yellow[]  = "\x1b[33m";
c58607
static const char aclr_blue[]    = "\x1b[34m";
c58607
static const char aclr_magenta[] = "\x1b[35m";
c58607
0801fe
static void slbt_lconf_close(int fdcwd, int fdlconfdir)
0801fe
{
0801fe
	if (fdlconfdir != fdcwd)
0801fe
		close(fdlconfdir);
0801fe
}
0801fe
c58607
static int slbt_lconf_trace_lconf_plain(
c58607
	struct slbt_driver_ctx *	dctx,
c58607
	const char *			lconf)
c58607
{
c58607
	int fderr = slbt_driver_fderr(dctx);
c58607
c58607
	if (slbt_dprintf(
c58607
			fderr,
c58607
			"%s: %s: {.name=%c%s%c}.\n",
c58607
			dctx->program,
c58607
			"lconf",
c58607
			'"',lconf,'"') < 0)
c58607
		return -1;
c58607
c58607
	return 0;
c58607
}
c58607
c58607
static int slbt_lconf_trace_lconf_annotated(
c58607
	struct slbt_driver_ctx *	dctx,
c58607
	const char *			lconf)
c58607
{
c58607
	int fderr = slbt_driver_fderr(dctx);
c58607
c58607
	if (slbt_dprintf(
c58607
			fderr,
c58607
			"%s%s%s%s: %s%s%s: {.name=%s%s%c%s%c%s}.\n",
c58607
c58607
			aclr_bold,aclr_magenta,
c58607
			dctx->program,
c58607
			aclr_reset,
c58607
c58607
			aclr_bold,
c58607
			"lconf",
c58607
			aclr_reset,
c58607
c58607
			aclr_bold,aclr_green,
c58607
			'"',lconf,'"',
c58607
			aclr_reset) < 0)
c58607
		return -1;
c58607
c58607
	return 0;
c58607
}
c58607
c58607
static int slbt_lconf_trace_openat_silent(
c58607
	struct slbt_driver_ctx *	dctx,
c58607
	int				fdat,
c58607
	const char *			path,
c58607
	int				oflag,
c58607
	int				mode)
c58607
{
c58607
	(void)dctx;
c58607
	return openat(fdat,path,oflag,mode);
c58607
}
c58607
c58607
static int slbt_lconf_trace_openat_plain(
c58607
	struct slbt_driver_ctx *	dctx,
c58607
	int				fdat,
c58607
	const char *			path,
c58607
	int				oflag,
c58607
	int				mode)
c58607
{
c58607
	char scwd[20];
c58607
	char serr[512];
c58607
c58607
	int  ret   = openat(fdat,path,oflag,mode);
c58607
	int  fderr = slbt_driver_fderr(dctx);
c58607
c58607
	if (fdat == AT_FDCWD) {
c58607
		strcpy(scwd,"AT_FDCWD");
c58607
	} else {
c58607
		sprintf(scwd,"%d",fdat);
c58607
	}
c58607
c58607
	if ((ret < 0) && (errno == ENOENT)) {
c58607
		strcpy(serr," [ENOENT]");
c58607
	} else if (ret < 0) {
c58607
		memset(serr,0,sizeof(serr));
c58607
		strerror_r(errno,&serr[2],sizeof(serr)-4);
c58607
		serr[0] = ' ';
c58607
		serr[1] = '(';
c58607
		serr[strlen(serr)] = ')';
c58607
	} else {
c58607
		serr[0] = 0;
c58607
	}
c58607
c58607
	slbt_dprintf(
c58607
		fderr,
c58607
		"%s: %s: openat(%s,%c%s%c,%s,%d) = %d%s.\n",
c58607
		dctx->program,
c58607
		"lconf",
c58607
		scwd,
c58607
		'"',path,'"',
c58607
		(oflag == O_DIRECTORY) ? "O_DIRECTORY" : "O_RDONLY",
c58607
		mode,ret,serr);
c58607
c58607
	return ret;
c58607
}
c58607
c58607
static int slbt_lconf_trace_openat_annotated(
c58607
	struct slbt_driver_ctx *	dctx,
c58607
	int				fdat,
c58607
	const char *			path,
c58607
	int				oflag,
c58607
	int				mode)
c58607
{
c58607
	char scwd[20];
c58607
	char serr[512];
c58607
c58607
	int  ret   = openat(fdat,path,oflag,mode);
c58607
	int  fderr = slbt_driver_fderr(dctx);
c58607
c58607
	if (fdat == AT_FDCWD) {
c58607
		strcpy(scwd,"AT_FDCWD");
c58607
	} else {
c58607
		sprintf(scwd,"%d",fdat);
c58607
	}
c58607
c58607
	if ((ret < 0) && (errno == ENOENT)) {
c58607
		strcpy(serr," [ENOENT]");
c58607
	} else if (ret < 0) {
c58607
		memset(serr,0,sizeof(serr));
c58607
		strerror_r(errno,&serr[2],sizeof(serr)-4);
c58607
		serr[0] = ' ';
c58607
		serr[1] = '(';
c58607
		serr[strlen(serr)] = ')';
c58607
	} else {
c58607
		serr[0] = 0;
c58607
	}
c58607
c58607
	slbt_dprintf(
c58607
		fderr,
c58607
		"%s%s%s%s: %s%s%s: openat(%s%s%s%s,%s%s%c%s%c%s,%s%s%s%s,%d) = %s%d%s%s%s%s%s.\n",
c58607
c58607
		aclr_bold,aclr_magenta,
c58607
		dctx->program,
c58607
		aclr_reset,
c58607
c58607
		aclr_bold,
c58607
		"lconf",
c58607
		aclr_reset,
c58607
c58607
		aclr_bold,aclr_blue,
c58607
		scwd,
c58607
		aclr_reset,
c58607
c58607
		aclr_bold,aclr_green,
c58607
		'"',path,'"',
c58607
		aclr_reset,
c58607
c58607
		aclr_bold,aclr_blue,
c58607
		(oflag == O_DIRECTORY) ? "O_DIRECTORY" : "O_RDONLY",
c58607
		aclr_reset,
c58607
c58607
		mode,
c58607
c58607
		aclr_bold,
c58607
		ret,
c58607
		aclr_reset,
c58607
c58607
		aclr_bold,aclr_red,
c58607
		serr,
c58607
		aclr_reset);
c58607
c58607
	return ret;
c58607
}
c58607
c58607
static int slbt_lconf_trace_fstat_silent(
c58607
	struct slbt_driver_ctx *	dctx,
c58607
	int				fd,
c58607
	const char *			path,
c58607
	struct stat *			st)
c58607
{
c58607
	(void)dctx;
c58607
c58607
	return path ? fstatat(fd,path,st,0) : fstat(fd,st);
c58607
}
c58607
c58607
static int slbt_lconf_trace_fstat_plain(
c58607
	struct slbt_driver_ctx *	dctx,
c58607
	int				fd,
c58607
	const char *			path,
c58607
	struct stat *			st)
c58607
{
c58607
	char scwd[20];
c58607
	char serr[512];
c58607
	char quot[2] = {'"',0};
c58607
c58607
	int  ret   = path ? fstatat(fd,path,st,0) : fstat(fd,st);
c58607
	int  fderr = slbt_driver_fderr(dctx);
c58607
c58607
	if (fd == AT_FDCWD) {
c58607
		strcpy(scwd,"AT_FDCWD");
c58607
	} else {
c58607
		sprintf(scwd,"%d",fd);
c58607
	}
c58607
c58607
	if ((ret < 0) && (errno == ENOENT)) {
c58607
		strcpy(serr," [ENOENT]");
c58607
	} else if (ret < 0) {
c58607
		memset(serr,0,sizeof(serr));
c58607
		strerror_r(errno,&serr[2],sizeof(serr)-4);
c58607
		serr[0] = ' ';
c58607
		serr[1] = '(';
c58607
		serr[strlen(serr)] = ')';
c58607
	} else {
c58607
		serr[0] = 0;
c58607
	}
c58607
c58607
	slbt_dprintf(
c58607
		fderr,
c58607
		"%s: %s: %s(%s%s%s%s%s,...) = %d%s%s",
c58607
		dctx->program,
c58607
		"lconf",
c58607
		path ? "fstatat" : "fstat",
c58607
		scwd,
c58607
		path ? "," : "",
c58607
		path ? quot : "",
c58607
		path ? path : "",
c58607
		path ? quot : "",
c58607
		ret,
c58607
		serr,
c58607
		ret ? ".\n" : "");
c58607
c58607
	if (ret == 0)
c58607
		slbt_dprintf(
c58607
			fderr,
c58607
			" {.st_dev = %ld, .st_ino = %ld}.\n",
c58607
			st->st_dev,
c58607
			st->st_ino);
c58607
c58607
	return ret;
c58607
}
c58607
c58607
static int slbt_lconf_trace_fstat_annotated(
c58607
	struct slbt_driver_ctx *	dctx,
c58607
	int				fd,
c58607
	const char *			path,
c58607
	struct stat *			st)
c58607
{
c58607
	char scwd[20];
c58607
	char serr[512];
c58607
	char quot[2] = {'"',0};
c58607
c58607
	int  ret   = path ? fstatat(fd,path,st,0) : fstat(fd,st);
c58607
	int  fderr = slbt_driver_fderr(dctx);
c58607
c58607
	if (fd == AT_FDCWD) {
c58607
		strcpy(scwd,"AT_FDCWD");
c58607
	} else {
c58607
		sprintf(scwd,"%d",fd);
c58607
	}
c58607
c58607
	if ((ret < 0) && (errno == ENOENT)) {
c58607
		strcpy(serr," [ENOENT]");
c58607
	} else if (ret < 0) {
c58607
		memset(serr,0,sizeof(serr));
c58607
		strerror_r(errno,&serr[2],sizeof(serr)-4);
c58607
		serr[0] = ' ';
c58607
		serr[1] = '(';
c58607
		serr[strlen(serr)] = ')';
c58607
	} else {
c58607
		serr[0] = 0;
c58607
	}
c58607
c58607
	slbt_dprintf(
c58607
		fderr,
c58607
		"%s%s%s%s: %s%s%s: %s(%s%s%s%s%s%s%s%s%s%s%s,...) = %s%d%s%s%s%s%s%s",
c58607
c58607
		aclr_bold,aclr_magenta,
c58607
		dctx->program,
c58607
		aclr_reset,
c58607
c58607
		aclr_bold,
c58607
		"lconf",
c58607
		aclr_reset,
c58607
c58607
		path ? "fstatat" : "fstat",
c58607
c58607
		aclr_bold,aclr_blue,
c58607
		scwd,
c58607
		aclr_reset,
c58607
c58607
		aclr_bold,aclr_green,
c58607
		path ? "," : "",
c58607
		path ? quot : "",
c58607
		path ? path : "",
c58607
		path ? quot : "",
c58607
		aclr_reset,
c58607
c58607
		aclr_bold,
c58607
		ret,
c58607
		aclr_reset,
c58607
c58607
		aclr_bold,aclr_red,
c58607
		serr,
c58607
		aclr_reset,
c58607
c58607
		ret ? ".\n" : "");
c58607
c58607
	if (ret == 0)
c58607
		slbt_dprintf(
c58607
			fderr,
c58607
			" {%s%s.st_dev%s = %s%ld%s, %s%s.st_ino%s = %s%ld%s}.\n",
c58607
c58607
			aclr_bold,aclr_yellow,aclr_reset,
c58607
c58607
			aclr_bold,
c58607
			st->st_dev,
c58607
			aclr_reset,
c58607
c58607
			aclr_bold,aclr_yellow,aclr_reset,
c58607
c58607
			aclr_bold,
c58607
			st->st_ino,
c58607
			aclr_reset);
c58607
c58607
	return ret;
c58607
}
c58607
9c11fa
static int slbt_lconf_trace_result_silent(
9c11fa
	struct slbt_driver_ctx *	dctx,
9c11fa
	int				fd,
9c11fa
	int				fdat,
9c11fa
	const char *			lconf,
a2aa78
	int				err,
a2aa78
	char				(*pathbuf)[PATH_MAX])
9c11fa
{
9c11fa
	(void)dctx;
9c11fa
	(void)fd;
9c11fa
	(void)fdat;
9c11fa
	(void)lconf;
a2aa78
a2aa78
	if (err)
a2aa78
		return -1;
a2aa78
a2aa78
	if (slbt_realpath(fdat,lconf,0,*pathbuf,sizeof(*pathbuf)) <0)
a2aa78
		return -1;
a2aa78
a2aa78
	return fd;
9c11fa
}
9c11fa
9c11fa
static int slbt_lconf_trace_result_plain(
9c11fa
	struct slbt_driver_ctx *	dctx,
9c11fa
	int				fd,
9c11fa
	int				fdat,
9c11fa
	const char *			lconf,
a2aa78
	int				err,
a2aa78
	char				(*pathbuf)[PATH_MAX])
9c11fa
{
9c11fa
	int             fderr;
9c11fa
	const char *    cpath;
9c11fa
9c11fa
	fderr = slbt_driver_fderr(dctx);
9c11fa
a2aa78
	cpath = !(slbt_realpath(fdat,lconf,0,*pathbuf,sizeof(*pathbuf)))
a2aa78
		? *pathbuf : lconf;
9c11fa
9c11fa
	switch (err) {
9c11fa
		case 0:
9c11fa
			slbt_dprintf(
9c11fa
				fderr,
9c11fa
				"%s: %s: found %c%s%c.\n",
9c11fa
				dctx->program,
9c11fa
				"lconf",
9c11fa
				'"',cpath,'"');
9c11fa
			return fd;
9c11fa
9c11fa
		case EXDEV:
9c11fa
			slbt_dprintf(
9c11fa
				fderr,
9c11fa
				"%s: %s: stopped in %c%s%c "
9c11fa
				"(config file not found on current device).\n",
9c11fa
				dctx->program,
9c11fa
				"lconf",
9c11fa
				'"',cpath,'"');
9c11fa
			return -1;
9c11fa
9c11fa
		default:
9c11fa
			slbt_dprintf(
9c11fa
				fderr,
9c11fa
				"%s: %s: stopped in %c%s%c "
9c11fa
				"(top-level directory reached).\n",
9c11fa
				dctx->program,
9c11fa
				"lconf",
9c11fa
				'"',cpath,'"');
9c11fa
			return -1;
9c11fa
	}
9c11fa
}
9c11fa
9c11fa
static int slbt_lconf_trace_result_annotated(
9c11fa
	struct slbt_driver_ctx *	dctx,
9c11fa
	int				fd,
9c11fa
	int				fdat,
9c11fa
	const char *			lconf,
a2aa78
	int				err,
a2aa78
	char				(*pathbuf)[PATH_MAX])
9c11fa
{
9c11fa
	int             fderr;
9c11fa
	const char *    cpath;
9c11fa
9c11fa
	fderr = slbt_driver_fderr(dctx);
9c11fa
a2aa78
	cpath = !(slbt_realpath(fdat,lconf,0,*pathbuf,sizeof(*pathbuf)))
a2aa78
		? *pathbuf : lconf;
9c11fa
9c11fa
	switch (err) {
9c11fa
		case 0:
9c11fa
			slbt_dprintf(
9c11fa
				fderr,
9c11fa
				"%s%s%s%s: %s%s%s: found %s%s%c%s%c%s.\n",
9c11fa
9c11fa
				aclr_bold,aclr_magenta,
9c11fa
				dctx->program,
9c11fa
				aclr_reset,
9c11fa
9c11fa
				aclr_bold,
9c11fa
				"lconf",
9c11fa
				aclr_reset,
9c11fa
9c11fa
				aclr_bold,aclr_green,
9c11fa
				'"',cpath,'"',
9c11fa
				aclr_reset);
9c11fa
			return fd;
9c11fa
9c11fa
		case EXDEV:
9c11fa
			slbt_dprintf(
9c11fa
				fderr,
9c11fa
				"%s%s%s%s: %s%s%s: stopped in %s%s%c%s%c%s "
9c11fa
				"%s%s(config file not found on current device)%s.\n",
9c11fa
9c11fa
				aclr_bold,aclr_magenta,
9c11fa
				dctx->program,
9c11fa
				aclr_reset,
9c11fa
9c11fa
				aclr_bold,
9c11fa
				"lconf",
9c11fa
				aclr_reset,
9c11fa
9c11fa
				aclr_bold,aclr_green,
9c11fa
				'"',cpath,'"',
9c11fa
				aclr_reset,
9c11fa
9c11fa
				aclr_bold,aclr_red,
9c11fa
				aclr_reset);
9c11fa
			return -1;
9c11fa
9c11fa
		default:
9c11fa
			slbt_dprintf(
9c11fa
				fderr,
9c11fa
				"%s%s%s%s: %s%s%s: stopped in %s%s%c%s%c%s "
9c11fa
				"%s%s(top-level directory reached)%s.\n",
9c11fa
9c11fa
				aclr_bold,aclr_magenta,
9c11fa
				dctx->program,
9c11fa
				aclr_reset,
9c11fa
9c11fa
				aclr_bold,
9c11fa
				"lconf",
9c11fa
				aclr_reset,
9c11fa
9c11fa
				aclr_bold,aclr_green,
9c11fa
				'"',cpath,'"',
9c11fa
				aclr_reset,
9c11fa
9c11fa
				aclr_bold,aclr_red,
9c11fa
				aclr_reset);
9c11fa
			return -1;
9c11fa
	}
9c11fa
}
9c11fa
0801fe
static int slbt_lconf_open(
0801fe
	struct slbt_driver_ctx *	dctx,
a2aa78
	const char *			lconf,
036a9e
	bool                            fsilent,
a2aa78
	char				(*lconfpath)[PATH_MAX])
0801fe
{
c58607
	int		fderr;
0801fe
	int		fdcwd;
0801fe
	int		fdlconf;
0801fe
	int		fdlconfdir;
0801fe
	int		fdparent;
0801fe
	struct stat	stcwd;
0801fe
	struct stat	stparent;
0b404d
	ino_t		stinode;
179d2e
	const char *    mconf;
0801fe
c58607
	int             (*trace_lconf)(struct slbt_driver_ctx *,
c58607
	                                const char *);
c58607
c58607
	int             (*trace_fstat)(struct slbt_driver_ctx *,
c58607
	                                int,const char *, struct stat *);
c58607
c58607
	int             (*trace_openat)(struct slbt_driver_ctx *,
c58607
	                                int,const char *,int,int);
c58607
9c11fa
	int             (*trace_result)(struct slbt_driver_ctx *,
a2aa78
	                                int,int,const char *,int,
a2aa78
	                                char (*)[PATH_MAX]);
9c11fa
c58607
	fderr      = slbt_driver_fderr(dctx);
0801fe
	fdcwd      = slbt_driver_fdcwd(dctx);
0801fe
	fdlconfdir = fdcwd;
036a9e
	fsilent   |= (dctx->cctx->drvflags & SLBT_DRIVER_SILENT);
0801fe
179d2e
	if (lconf) {
179d2e
		mconf = 0;
179d2e
	} else {
179d2e
		mconf = "slibtool.cfg";
179d2e
		lconf = "libtool";
179d2e
	}
179d2e
036a9e
	if (fsilent) {
c58607
		trace_lconf  = 0;
c58607
		trace_fstat  = slbt_lconf_trace_fstat_silent;
c58607
		trace_openat = slbt_lconf_trace_openat_silent;
9c11fa
		trace_result = slbt_lconf_trace_result_silent;
c58607
c58607
	} else if (dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER) {
c58607
		trace_lconf  = slbt_lconf_trace_lconf_plain;
c58607
		trace_fstat  = slbt_lconf_trace_fstat_plain;
c58607
		trace_openat = slbt_lconf_trace_openat_plain;
9c11fa
		trace_result = slbt_lconf_trace_result_plain;
c58607
c58607
	} else if (dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_ALWAYS) {
c58607
		trace_lconf  = slbt_lconf_trace_lconf_annotated;
c58607
		trace_fstat  = slbt_lconf_trace_fstat_annotated;
c58607
		trace_openat = slbt_lconf_trace_openat_annotated;
9c11fa
		trace_result = slbt_lconf_trace_result_annotated;
c58607
c58607
	} else if (isatty(fderr)) {
c58607
		trace_lconf  = slbt_lconf_trace_lconf_annotated;
c58607
		trace_fstat  = slbt_lconf_trace_fstat_annotated;
c58607
		trace_openat = slbt_lconf_trace_openat_annotated;
9c11fa
		trace_result = slbt_lconf_trace_result_annotated;
c58607
c58607
	} else {
c58607
		trace_lconf  = slbt_lconf_trace_lconf_plain;
c58607
		trace_fstat  = slbt_lconf_trace_fstat_plain;
c58607
		trace_openat = slbt_lconf_trace_openat_plain;
9c11fa
		trace_result = slbt_lconf_trace_result_plain;
c58607
	}
c58607
503f2f
	if (!(dctx->cctx->drvflags & SLBT_DRIVER_DEBUG)) {
503f2f
		trace_fstat  = slbt_lconf_trace_fstat_silent;
503f2f
		trace_openat = slbt_lconf_trace_openat_silent;
503f2f
	}
503f2f
036a9e
	if (!fsilent) {
179d2e
		if (!mconf)
179d2e
			trace_lconf(dctx,lconf);
179d2e
c58607
		slbt_output_fdcwd(dctx);
c58607
	}
c58607
d70e37
	if (lconf && strchr(lconf,'/'))
c58607
		return ((fdlconf = trace_openat(dctx,fdcwd,lconf,O_RDONLY,0)) < 0)
0801fe
			? SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_LCONF_OPEN)
a2aa78
			: trace_result(dctx,fdlconf,fdcwd,lconf,0,lconfpath);
0801fe
c58607
	if (trace_fstat(dctx,fdlconfdir,".",&stcwd) < 0)
6beda1
		return SLBT_SYSTEM_ERROR(dctx,0);
0801fe
0b404d
	stinode = stcwd.st_ino;
179d2e
	fdlconf = -1;
179d2e
179d2e
	if (mconf)
179d2e
		if ((fdlconf = trace_openat(dctx,fdlconfdir,mconf,O_RDONLY,0)) >= 0)
179d2e
			lconf = mconf;
179d2e
179d2e
	if (fdlconf < 0)
179d2e
		fdlconf = trace_openat(dctx,fdlconfdir,lconf,O_RDONLY,0);
0801fe
0801fe
	while (fdlconf < 0) {
c58607
		fdparent = trace_openat(dctx,fdlconfdir,"../",O_DIRECTORY,0);
0801fe
		slbt_lconf_close(fdcwd,fdlconfdir);
0801fe
0801fe
		if (fdparent < 0)
6beda1
			return SLBT_SYSTEM_ERROR(dctx,0);
0801fe
c58607
		if (trace_fstat(dctx,fdparent,0,&stparent) < 0) {
bab3d0
			close(fdparent);
6beda1
			return SLBT_SYSTEM_ERROR(dctx,0);
bab3d0
		}
0801fe
bab3d0
		if (stparent.st_dev != stcwd.st_dev) {
a2aa78
			trace_result(dctx,fdparent,fdparent,".",EXDEV,lconfpath);
bab3d0
			close(fdparent);
0801fe
			return SLBT_CUSTOM_ERROR(
0801fe
				dctx,SLBT_ERR_LCONF_OPEN);
bab3d0
		}
0801fe
0b404d
		if (stparent.st_ino == stinode) {
a2aa78
			trace_result(dctx,fdparent,fdparent,".",ELOOP,lconfpath);
0b404d
			close(fdparent);
0b404d
			return SLBT_CUSTOM_ERROR(
0b404d
				dctx,SLBT_ERR_LCONF_OPEN);
0b404d
		}
0b404d
0801fe
		fdlconfdir = fdparent;
0b404d
		stinode    = stparent.st_ino;
179d2e
179d2e
		if (mconf)
179d2e
			if ((fdlconf = trace_openat(dctx,fdlconfdir,mconf,O_RDONLY,0)) >= 0)
179d2e
				lconf = mconf;
179d2e
179d2e
		if (fdlconf < 0)
179d2e
			fdlconf = trace_openat(dctx,fdlconfdir,lconf,O_RDONLY,0);
0801fe
	}
0801fe
a2aa78
	trace_result(dctx,fdlconf,fdlconfdir,lconf,0,lconfpath);
9c11fa
bab3d0
	slbt_lconf_close(fdcwd,fdlconfdir);
bab3d0
0801fe
	return fdlconf;
0801fe
}
0801fe
20aece
static int slbt_get_lconf_var(
489101
	const struct slbt_txtfile_ctx * tctx,
489101
	const char *                    var,
489101
	const char                      space,
489101
	char                            (*val)[PATH_MAX])
20aece
{
489101
	const char **   pline;
20aece
	const char *    mark;
20aece
	const char *    match;
489101
	const char *    cap;
20aece
	ssize_t         len;
bb9df1
	int             cint;
20aece
20aece
	/* init */
20aece
	match = 0;
489101
	pline = tctx->txtlinev;
489101
	len   = strlen(var);
20aece
20aece
	/* search for ^var= */
489101
	for (; *pline && !match; ) {
489101
		if (!strncmp(*pline,var,len)) {
489101
			match = *pline;
20aece
		} else {
489101
			pline++;
20aece
		}
20aece
	}
20aece
20aece
	/* not found? */
00c58e
	if (!match) {
00c58e
		(*val)[0] = '\0';
20aece
		return 0;
00c58e
	}
20aece
d29f9c
	/* support a single pair of double quotes */
20aece
	match = &match[len];
20aece
	mark  = match;
20aece
d29f9c
	if (match[0] == '"') {
d29f9c
		match++;
20aece
		mark++;
20aece
489101
		for (; *mark && (*mark != '"'); )
d29f9c
			mark++;
489101
489101
		/* unpaired quote? */
489101
		if (*mark != '"')
489101
			return -1;
d29f9c
	} else {
489101
		for (; *mark && !isspace((cint=*mark)); )
d29f9c
			mark++;
d29f9c
	}
d29f9c
489101
	cap = mark;
d29f9c
20aece
	/* validate */
489101
	for (mark=match; mark
20aece
		if ((*mark >= 'a') && (*mark <= 'z'))
20aece
			(void)0;
20aece
20aece
		else if ((*mark >= 'A') && (*mark <= 'Z'))
20aece
			(void)0;
20aece
20aece
		else if ((*mark >= '0') && (*mark <= '9'))
20aece
			(void)0;
20aece
20aece
		else if ((*mark == '+') || (*mark == '-'))
20aece
			(void)0;
20aece
20aece
		else if ((*mark == '/') || (*mark == '@'))
20aece
			(void)0;
20aece
20aece
		else if ((*mark == '.') || (*mark == '_'))
20aece
			(void)0;
20aece
145d2b
		else if ((*mark == ':') || (*mark == space))
d89592
			(void)0;
d89592
20aece
		else
20aece
			return -1;
20aece
	}
20aece
489101
	/* all done */
489101
	memcpy(*val,match,cap-match);
489101
	(*val)[cap-match] = '\0';
489101
20aece
	return 0;
20aece
}
20aece
4b56de
slbt_hidden int slbt_get_lconf_flags(
0801fe
	struct slbt_driver_ctx *	dctx,
0801fe
	const char *			lconf,
036a9e
	uint64_t *			flags,
036a9e
	bool                            fsilent)
0801fe
{
d29f9c
	struct slbt_driver_ctx_impl *   ctx;
489101
	struct slbt_txtfile_ctx *       confctx;
0801fe
	int				fdlconf;
0801fe
	struct stat			st;
0801fe
	void *				addr;
0801fe
	uint64_t			optshared;
0801fe
	uint64_t			optstatic;
20aece
	char                            val[PATH_MAX];
0801fe
d29f9c
	/* driver context (ar, ranlib, cc) */
d29f9c
	ctx = slbt_get_driver_ictx(dctx);
d29f9c
0801fe
	/* open relative libtool script */
036a9e
	if ((fdlconf = slbt_lconf_open(dctx,lconf,fsilent,&val)) < 0)
a2aa78
		return SLBT_NESTED_ERROR(dctx);
a2aa78
a2aa78
	/* cache the configuration in library friendly form) */
a2aa78
	if (slbt_lib_get_txtfile_ctx(dctx,val,&ctx->lconfctx) < 0)
0801fe
		return SLBT_NESTED_ERROR(dctx);
0801fe
489101
	confctx = ctx->lconfctx;
489101
0801fe
	/* map relative libtool script */
0801fe
	if (fstat(fdlconf,&st) < 0)
6beda1
		return SLBT_SYSTEM_ERROR(dctx,0);
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
	/* scan */
0801fe
	optshared = 0;
0801fe
	optstatic = 0;
0801fe
20aece
	/* shared libraries option */
489101
	if (slbt_get_lconf_var(confctx,"build_libtool_libs=",0,&val) < 0)
20aece
		return SLBT_CUSTOM_ERROR(
20aece
			dctx,SLBT_ERR_LCONF_PARSE);
20aece
20aece
	if (!strcmp(val,"yes")) {
20aece
		optshared = SLBT_DRIVER_SHARED;
20aece
20aece
	} else if (!strcmp(val,"no")) {
20aece
		optshared = SLBT_DRIVER_DISABLE_SHARED;
20aece
	}
20aece
20aece
20aece
	/* static libraries option */
489101
	if (slbt_get_lconf_var(confctx,"build_old_libs=",0,&val) < 0)
20aece
		return SLBT_CUSTOM_ERROR(
20aece
			dctx,SLBT_ERR_LCONF_PARSE);
20aece
20aece
	if (!strcmp(val,"yes")) {
20aece
		optstatic = SLBT_DRIVER_STATIC;
32fd48
20aece
	} else if (!strcmp(val,"no")) {
20aece
		optstatic = SLBT_DRIVER_DISABLE_STATIC;
0801fe
	}
0801fe
0801fe
	if (!optshared || !optstatic)
0801fe
		return SLBT_CUSTOM_ERROR(
0801fe
			dctx,SLBT_ERR_LCONF_PARSE);
0801fe
0801fe
	*flags = optshared | optstatic;
0801fe
d29f9c
771899
	/* host */
771899
	if (!ctx->cctx.host.host) {
489101
		if (slbt_get_lconf_var(confctx,"host=",0,&val) < 0)
771899
			return SLBT_CUSTOM_ERROR(
771899
				dctx,SLBT_ERR_LCONF_PARSE);
771899
771899
		if (val[0] && !(ctx->host.host = strdup(val)))
771899
			return SLBT_SYSTEM_ERROR(dctx,0);
771899
771899
		ctx->cctx.host.host = ctx->host.host;
771899
	}
771899
771899
d29f9c
	/* ar tool */
d29f9c
	if (!ctx->cctx.host.ar) {
489101
		if (slbt_get_lconf_var(confctx,"AR=",0x20,&val) < 0)
d29f9c
			return SLBT_CUSTOM_ERROR(
d29f9c
				dctx,SLBT_ERR_LCONF_PARSE);
d29f9c
4964fd
		if (val[0] && !(ctx->host.ar = strdup(val)))
d29f9c
			return SLBT_SYSTEM_ERROR(dctx,0);
4964fd
4964fd
		ctx->cctx.host.ar = ctx->host.ar;
b5e104
	}
b5e104
b5e104
b5e104
	/* nm tool */
b5e104
	if (!ctx->cctx.host.nm) {
b5e104
		if (slbt_get_lconf_var(confctx,"NM=",0x20,&val) < 0)
b5e104
			return SLBT_CUSTOM_ERROR(
b5e104
				dctx,SLBT_ERR_LCONF_PARSE);
b5e104
b5e104
		if (val[0] && !(ctx->host.nm = strdup(val)))
b5e104
			return SLBT_SYSTEM_ERROR(dctx,0);
b5e104
b5e104
		ctx->cctx.host.nm = ctx->host.nm;
d29f9c
	}
d29f9c
d29f9c
d29f9c
	/* ranlib tool */
d29f9c
	if (!ctx->cctx.host.ranlib) {
489101
		if (slbt_get_lconf_var(confctx,"RANLIB=",0x20,&val) < 0)
d29f9c
			return SLBT_CUSTOM_ERROR(
d29f9c
				dctx,SLBT_ERR_LCONF_PARSE);
d29f9c
4964fd
		if (val[0] && !(ctx->host.ranlib = strdup(val)))
d29f9c
			return SLBT_SYSTEM_ERROR(dctx,0);
4964fd
4964fd
		ctx->cctx.host.ranlib = ctx->host.ranlib;
d29f9c
	}
d29f9c
d29f9c
b4058c
	/* as tool (optional) */
b4058c
	if (!ctx->cctx.host.as) {
489101
		if (slbt_get_lconf_var(confctx,"AS=",0x20,&val) < 0)
ba9228
			return SLBT_CUSTOM_ERROR(
ba9228
				dctx,SLBT_ERR_LCONF_PARSE);
b4058c
ba9228
		if (val[0] && !(ctx->host.as = strdup(val)))
ba9228
			return SLBT_SYSTEM_ERROR(dctx,0);
ba9228
ba9228
ba9228
		ctx->cctx.host.as = ctx->host.as;
b4058c
	}
b4058c
b4058c
fc8ee9
	/* dlltool tool (optional) */
fc8ee9
	if (!ctx->cctx.host.dlltool) {
489101
		if (slbt_get_lconf_var(confctx,"DLLTOOL=",0x20,&val) < 0)
94868f
			return SLBT_CUSTOM_ERROR(
94868f
				dctx,SLBT_ERR_LCONF_PARSE);
fc8ee9
94868f
		if (val[0] && !(ctx->host.dlltool = strdup(val)))
94868f
			return SLBT_SYSTEM_ERROR(dctx,0);
94868f
94868f
		ctx->cctx.host.dlltool = ctx->host.dlltool;
fc8ee9
	}
fc8ee9
fc8ee9
d29f9c
	/* all done */
6ab3f1
	ctx->lconf.addr = addr;
6ab3f1
	ctx->lconf.size = st.st_size;
d29f9c
0801fe
	return 0;
0801fe
}