/*******************************************************************/
/* 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 <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <slibtool/slibtool.h>
#include "slibtool_driver_impl.h"
#include "slibtool_errinfo_impl.h"
#include "slibtool_realpath_impl.h"
#include "slibtool_stoolie_impl.h"
#include "slibtool_txtline_impl.h"
#include "slibtool_m4fake_impl.h"
static const char slbt_this_dir[2] = {'.',0};
static int slbt_st_free_stoolie_ctx_impl(
struct slbt_stoolie_ctx_impl * ctx,
int fdsrc,
int ret)
{
char ** parg;
if (ctx) {
if (fdsrc >= 0)
close(fdsrc);
if (ctx->fdtgt >= 0)
close(ctx->fdtgt);
if (ctx->fdaux >= 0)
close(ctx->fdaux);
if (ctx->fdm4 >= 0)
close(ctx->fdm4);
for (parg=ctx->m4argv; parg && *parg; parg++)
free(*parg);
free(ctx->m4buf);
free(ctx->m4argv);
free(ctx->auxbuf);
free(ctx->pathbuf);
slbt_lib_free_txtfile_ctx(ctx->acinc);
slbt_lib_free_txtfile_ctx(ctx->cfgac);
slbt_lib_free_txtfile_ctx(ctx->makam);
free(ctx);
}
return ret;
}
int slbt_st_get_stoolie_ctx(
const struct slbt_driver_ctx * dctx,
const char * path,
struct slbt_stoolie_ctx ** pctx)
{
struct slbt_stoolie_ctx_impl * ctx;
int cint;
int fdcwd;
int fdtgt;
int fdsrc;
const char ** pline;
char ** margv;
const char * mark;
const char * dpath;
char pathbuf[PATH_MAX];
/* target directory: fd and real path*/
fdcwd = slbt_driver_fdcwd(dctx);
if ((fdtgt = openat(fdcwd,path,O_DIRECTORY|O_CLOEXEC,0)) < 0)
return SLBT_SYSTEM_ERROR(dctx,path);
if (slbt_realpath(fdtgt,".",0,pathbuf,sizeof(pathbuf)) < 0) {
close(fdtgt);
return SLBT_SYSTEM_ERROR(dctx,path);
}
/* context alloc and init */
if (!(ctx = calloc(1,sizeof(*ctx)))) {
close(fdtgt);
return SLBT_BUFFER_ERROR(dctx);
}
ctx->fdtgt = fdtgt;
ctx->fdaux = (-1);
ctx->fdm4 = (-1);
/* target directory real path */
if (!(ctx->pathbuf = strdup(pathbuf)))
return slbt_st_free_stoolie_ctx_impl(ctx,(-1),
SLBT_NESTED_ERROR(dctx));
/* acinclude.m4, configure.ac, Makefile.am */
if ((fdsrc = openat(fdtgt,"acinlcude.m4",O_RDONLY,0)) < 0) {
if (errno != ENOENT)
return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc,
SLBT_SYSTEM_ERROR(dctx,"acinlcude.m4"));
} else {
if (slbt_impl_get_txtfile_ctx(dctx,"acinclude.m4",fdsrc,&ctx->acinc) < 0)
return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc,
SLBT_NESTED_ERROR(dctx));
close(fdsrc);
}
if ((fdsrc = openat(fdtgt,"configure.ac",O_RDONLY,0)) < 0) {
if (errno != ENOENT)
return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc,
SLBT_SYSTEM_ERROR(dctx,"configure.ac"));
} else {
if (slbt_impl_get_txtfile_ctx(dctx,"configure.ac",fdsrc,&ctx->cfgac) < 0)
return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc,
SLBT_NESTED_ERROR(dctx));
close(fdsrc);
}
if ((fdsrc = openat(fdtgt,"Makefile.am",O_RDONLY,0)) < 0) {
if (errno != ENOENT)
return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc,
SLBT_SYSTEM_ERROR(dctx,"Makefile.am"));
} else {
if (slbt_impl_get_txtfile_ctx(dctx,"Makefile.am",fdsrc,&ctx->makam) < 0)
return slbt_st_free_stoolie_ctx_impl(ctx,fdsrc,
SLBT_NESTED_ERROR(dctx));
close(fdsrc);
}
/* aux dir */
if (ctx->acinc) {
if (slbt_m4fake_expand_cmdarg(
dctx,ctx->acinc,
"AC_CONFIG_AUX_DIR",
&pathbuf) < 0)
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_NESTED_ERROR(dctx));
if (pathbuf[0])
if (!(ctx->auxbuf = strdup(pathbuf)))
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_NESTED_ERROR(dctx));
}
if (!ctx->auxbuf && ctx->cfgac) {
if (slbt_m4fake_expand_cmdarg(
dctx,ctx->cfgac,
"AC_CONFIG_AUX_DIR",
&pathbuf) < 0)
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_NESTED_ERROR(dctx));
if (pathbuf[0])
if (!(ctx->auxbuf = strdup(pathbuf)))
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_NESTED_ERROR(dctx));
}
/* m4 dir */
if (ctx->acinc) {
if (slbt_m4fake_expand_cmdarg(
dctx,ctx->acinc,
"AC_CONFIG_MACRO_DIR",
&pathbuf) < 0)
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_NESTED_ERROR(dctx));
if (pathbuf[0])
if (!(ctx->m4buf = strdup(pathbuf)))
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_NESTED_ERROR(dctx));
}
if (!ctx->m4buf && ctx->cfgac) {
if (slbt_m4fake_expand_cmdarg(
dctx,ctx->cfgac,
"AC_CONFIG_MACRO_DIR",
&pathbuf) < 0)
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_NESTED_ERROR(dctx));
if (pathbuf[0])
if (!(ctx->m4buf = strdup(pathbuf)))
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_NESTED_ERROR(dctx));
}
if (!ctx->m4buf && ctx->makam) {
for (pline=ctx->makam->txtlinev; !ctx->m4argv && *pline; pline++) {
if (!strncmp(*pline,"ACLOCAL_AMFLAGS",15)) {
if (isspace((cint = (*pline)[15])) || ((*pline)[15] == '=')) {
mark = &(*pline)[15];
for (; isspace(cint = *mark); )
mark++;
if (mark[0] != '=')
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_CUSTOM_ERROR(
dctx,
SLBT_ERR_FLOW_ERROR));
if (slbt_txtline_to_string_vector(++mark,&margv) < 0)
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_CUSTOM_ERROR(
dctx,
SLBT_ERR_FLOW_ERROR));
ctx->m4argv = margv;
if (!strcmp((mark = margv[0]),"-I")) {
ctx->m4buf = strdup(margv[1]);
} else if (!strncmp(mark,"-I",2)) {
ctx->m4buf = strdup(&mark[2]);
}
if (!ctx->m4buf)
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_CUSTOM_ERROR(
dctx,
SLBT_ERR_FLOW_ERROR));
}
}
}
}
/* build-aux directory */
if (!(dpath = ctx->auxbuf))
dpath = slbt_this_dir;
if ((ctx->fdaux = openat(fdtgt,dpath,O_DIRECTORY,0)) < 0)
if (errno == ENOENT)
if (!mkdirat(fdtgt,dpath,0755))
ctx->fdaux = openat(fdtgt,dpath,O_DIRECTORY,0);
if (ctx->fdaux < 0)
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_SYSTEM_ERROR(dctx,dpath));
/* m4 directory */
if ((dpath = ctx->m4buf))
if ((ctx->fdm4 = openat(fdtgt,dpath,O_DIRECTORY,0)) < 0)
if (errno == ENOENT)
if (!mkdirat(fdtgt,dpath,0755))
ctx->fdm4 = openat(fdtgt,dpath,O_DIRECTORY,0);
if (dpath && (ctx->fdm4 < 0))
return slbt_st_free_stoolie_ctx_impl(
ctx,(-1),
SLBT_SYSTEM_ERROR(dctx,dpath));
/* all done */
ctx->path = ctx->pathbuf;
ctx->auxarg = ctx->auxbuf;
ctx->m4arg = ctx->m4buf;
ctx->zctx.path = &ctx->path;
ctx->zctx.acinc = ctx->acinc;
ctx->zctx.cfgac = ctx->cfgac;
ctx->zctx.makam = ctx->makam;
ctx->zctx.auxarg = &ctx->auxarg;
ctx->zctx.m4arg = &ctx->m4arg;
*pctx = &ctx->zctx;
return 0;
}
void slbt_st_free_stoolie_ctx(struct slbt_stoolie_ctx * ctx)
{
struct slbt_stoolie_ctx_impl * ictx;
uintptr_t addr;
if (ctx) {
addr = (uintptr_t)ctx - offsetof(struct slbt_stoolie_ctx_impl,zctx);
ictx = (struct slbt_stoolie_ctx_impl *)addr;
slbt_st_free_stoolie_ctx_impl(ictx,(-1),0);
}
}