|
|
e956c8 |
/*******************************************************************/
|
|
|
e956c8 |
/* slibtool: a skinny libtool implementation, written in C */
|
|
|
49181b |
/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
|
|
|
e956c8 |
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
|
|
|
e956c8 |
/*******************************************************************/
|
|
|
e956c8 |
|
|
|
e956c8 |
#include <string.h>
|
|
|
e956c8 |
#include <stdbool.h>
|
|
|
e956c8 |
#include <fcntl.h>
|
|
|
e956c8 |
#include <errno.h>
|
|
|
e956c8 |
#include <sys/stat.h>
|
|
|
e956c8 |
|
|
|
e956c8 |
#include <slibtool/slibtool.h>
|
|
|
e956c8 |
#include "slibtool_spawn_impl.h"
|
|
|
7ae5c1 |
#include "slibtool_driver_impl.h"
|
|
|
19022e |
#include "slibtool_snprintf_impl.h"
|
|
|
a47c7a |
#include "slibtool_errinfo_impl.h"
|
|
|
e956c8 |
|
|
|
dfb331 |
|
|
|
dfb331 |
/*******************************************************************/
|
|
|
dfb331 |
/* --mode=execute: wrapper script and execution argument vector */
|
|
|
dfb331 |
/* */
|
|
|
dfb331 |
/* The purpose of executable wrapper scripts is to properly handle */
|
|
|
dfb331 |
/* one common scenario where: */
|
|
|
dfb331 |
/* */
|
|
|
dfb331 |
/* (1) a build project would entail both executable programs and */
|
|
|
dfb331 |
/* dynamically linked libraries; and */
|
|
|
dfb331 |
/* */
|
|
|
dfb331 |
/* (2) one or more of the project's executable programs would have */
|
|
|
dfb331 |
/* one or more of the project's libraries as a dynamic runtime */
|
|
|
dfb331 |
/* dependency. */
|
|
|
dfb331 |
/* */
|
|
|
dfb331 |
/* Since the project's dependency libraries are not yet installed, */
|
|
|
dfb331 |
/* correct resolution of a program's dynamic library dependencies */
|
|
|
dfb331 |
/* must depend on an appropriate setting of the LD_LIBRARY_PATH */
|
|
|
dfb331 |
/* encironment variable (on Linxu or Midipix) or an equivalent */
|
|
|
dfb331 |
/* environment variable on any of the other supported platforms. */
|
|
|
dfb331 |
/* */
|
|
|
dfb331 |
/* Here, too, there are two distinct cases: */
|
|
|
dfb331 |
/* */
|
|
|
dfb331 |
/* (a) the executable wrapper script is directly invoked from the */
|
|
|
dfb331 |
/* shell command line or otherwise; or */
|
|
|
dfb331 |
/* */
|
|
|
dfb331 |
/* (b) the build target associated with the executable program is */
|
|
|
dfb331 |
/* an argument passed to `slibtool --mode=execute` either as */
|
|
|
dfb331 |
/* the name of the program to be executed (and thus as the */
|
|
|
dfb331 |
/* first non-slibtool argument) or for processing by another */
|
|
|
dfb331 |
/* program. */
|
|
|
dfb331 |
/* */
|
|
|
dfb331 |
/* The first case is handled entirely from within the executable */
|
|
|
dfb331 |
/* wrapper script. The load environment variable is set based on */
|
|
|
dfb331 |
/* the path that was stored in it by slibtool at link time, and */
|
|
|
dfb331 |
/* the real executable is then exec'ed. */
|
|
|
dfb331 |
/* */
|
|
|
dfb331 |
/* In the second case, slibtool would start by testing whether the */
|
|
|
dfb331 |
/* first non-slibtool argument is the wrapper script of a newly */
|
|
|
dfb331 |
/* built executable program. If it is, then slibtool would invoke */
|
|
|
dfb331 |
/* the wrapper script rather than the executable program, and add */
|
|
|
dfb331 |
/* the path to the executable to the argument vector before all */
|
|
|
dfb331 |
/* other arguments, makign it ${1} from the wrapper script's point */
|
|
|
dfb331 |
/* of view. Then again, and irrespective of the previous step, */
|
|
|
dfb331 |
/* slibtool will replace any remaining command-line argument which */
|
|
|
dfb331 |
/* points to a build target associated with a newly built program */
|
|
|
dfb331 |
/* with the path to the program itself (that is, the one located */
|
|
|
dfb331 |
/* under the internal .libs/ directory). */
|
|
|
dfb331 |
/* */
|
|
|
dfb331 |
/* For the sake of consistency and robustness, wrapper scripts are */
|
|
|
dfb331 |
/* created at link time for _all_ executable programs, including */
|
|
|
dfb331 |
/* those programs which appear to have system libraries as their */
|
|
|
dfb331 |
/* sole dynamic library dependencies. */
|
|
|
dfb331 |
/*******************************************************************/
|
|
|
dfb331 |
|
|
|
dfb331 |
|
|
|
dfb331 |
static int slbt_argument_is_an_executable_wrapper_script(
|
|
|
dfb331 |
const struct slbt_driver_ctx * dctx,
|
|
|
dfb331 |
const char * arg,
|
|
|
dfb331 |
char (*altarg)[PATH_MAX])
|
|
|
dfb331 |
{
|
|
|
dfb331 |
int fdcwd;
|
|
|
dfb331 |
const char * base;
|
|
|
dfb331 |
char * mark;
|
|
|
dfb331 |
struct stat st;
|
|
|
dfb331 |
|
|
|
dfb331 |
/* the extra characters: .libs/.exe.wrapper */
|
|
|
dfb331 |
if (strlen(arg) > (PATH_MAX - 20))
|
|
|
dfb331 |
return SLBT_BUFFER_ERROR(dctx);
|
|
|
dfb331 |
|
|
|
dfb331 |
/* path/to/progname --> path/to/.libs/progname.exe.wapper */
|
|
|
dfb331 |
if ((base = strrchr(arg,'/')))
|
|
|
dfb331 |
base++;
|
|
|
dfb331 |
|
|
|
dfb331 |
if (!base)
|
|
|
dfb331 |
base = arg;
|
|
|
dfb331 |
|
|
|
dfb331 |
mark = *altarg;
|
|
|
dfb331 |
mark += base - arg;
|
|
|
dfb331 |
|
|
|
dfb331 |
strcpy(*altarg,arg);
|
|
|
dfb331 |
mark += sprintf(mark,".libs/%s",base);
|
|
|
dfb331 |
strcpy(mark,".exe.wrapper");
|
|
|
dfb331 |
|
|
|
dfb331 |
/* not an executable wrapper script? */
|
|
|
dfb331 |
fdcwd = slbt_driver_fdcwd(dctx);
|
|
|
dfb331 |
|
|
|
dfb331 |
if (fstatat(fdcwd,*altarg,&st,0) < 0)
|
|
|
dfb331 |
return (errno == ENOENT)
|
|
|
dfb331 |
? 0 : SLBT_SYSTEM_ERROR(dctx,*altarg);
|
|
|
dfb331 |
|
|
|
dfb331 |
/* path/to/.libs/progname.exe.wapper --> path/to/.libs/progname */
|
|
|
dfb331 |
*mark = '\0';
|
|
|
dfb331 |
|
|
|
dfb331 |
return 1;
|
|
|
dfb331 |
}
|
|
|
dfb331 |
|
|
|
dfb331 |
|
|
|
2e30eb |
int slbt_exec_execute(const struct slbt_driver_ctx * dctx)
|
|
|
e956c8 |
{
|
|
|
dfb331 |
int ret;
|
|
|
dfb331 |
char ** parg;
|
|
|
dfb331 |
char ** aarg;
|
|
|
e956c8 |
char * program;
|
|
|
dfb331 |
char * exeref;
|
|
|
e956c8 |
char wrapper[PATH_MAX];
|
|
|
dfb331 |
char exeprog[PATH_MAX];
|
|
|
dfb331 |
char argbuf [PATH_MAX];
|
|
|
2e30eb |
struct slbt_exec_ctx * ectx;
|
|
|
e956c8 |
|
|
|
c4a389 |
/* dry run */
|
|
|
c4a389 |
if (dctx->cctx->drvflags & SLBT_DRIVER_DRY_RUN)
|
|
|
c4a389 |
return 0;
|
|
|
c4a389 |
|
|
|
e956c8 |
/* context */
|
|
|
2e30eb |
if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
|
|
|
2e30eb |
return SLBT_NESTED_ERROR(dctx);
|
|
|
2e30eb |
|
|
|
2e30eb |
slbt_disable_placeholders(ectx);
|
|
|
e956c8 |
|
|
|
dfb331 |
/* original and alternate argument vectors */
|
|
|
dfb331 |
parg = ectx->cargv;
|
|
|
dfb331 |
aarg = ectx->altv;
|
|
|
70949a |
|
|
|
dfb331 |
/* program (first non-slibtool argument) */
|
|
|
dfb331 |
if (!(program = ectx->cargv[0]))
|
|
|
dfb331 |
return SLBT_CUSTOM_ERROR(
|
|
|
dfb331 |
dctx,
|
|
|
dfb331 |
SLBT_ERR_FLOW_ERROR);
|
|
|
7ae5c1 |
|
|
|
dfb331 |
/* init the wrapper argument based on the first qualifying argument */
|
|
|
dfb331 |
for (exeref=0; !exeref && *parg; parg++) {
|
|
|
dfb331 |
strcpy(argbuf,*parg);
|
|
|
dfb331 |
|
|
|
dfb331 |
if ((ret = slbt_argument_is_an_executable_wrapper_script(
|
|
|
dfb331 |
dctx,argbuf,&exeprog)) < 0) {
|
|
|
dfb331 |
return SLBT_NESTED_ERROR(dctx);
|
|
|
dfb331 |
|
|
|
dfb331 |
} else if (ret == 1) {
|
|
|
dfb331 |
sprintf(wrapper,"%s.exe.wrapper",exeprog);
|
|
|
dfb331 |
exeref = *parg;
|
|
|
dfb331 |
*aarg++ = wrapper;
|
|
Lucio Andrés Illanes Albornoz |
f27e85 |
} else {
|
|
|
dfb331 |
strcpy(*parg,argbuf);
|
|
Lucio Andrés Illanes Albornoz |
f27e85 |
}
|
|
|
dfb331 |
}
|
|
Lucio Andrés Illanes Albornoz |
f27e85 |
|
|
|
dfb331 |
/* transform in place as needed all arguments */
|
|
|
dfb331 |
for (parg=ectx->cargv; *parg; parg++) {
|
|
|
dfb331 |
if ((ret = slbt_argument_is_an_executable_wrapper_script(
|
|
|
dfb331 |
dctx,*parg,&argbuf)) < 0) {
|
|
|
dfb331 |
return SLBT_NESTED_ERROR(dctx);
|
|
|
dfb331 |
|
|
|
dfb331 |
} else if (ret == 1) {
|
|
|
dfb331 |
strcpy(*parg,argbuf);
|
|
|
dfb331 |
*aarg++ = *parg;
|
|
|
dfb331 |
} else {
|
|
|
dfb331 |
*aarg++ = *parg;
|
|
|
dfb331 |
}
|
|
|
1ed71a |
}
|
|
|
e956c8 |
|
|
|
dfb331 |
*aarg = 0;
|
|
|
dfb331 |
|
|
|
dfb331 |
/* execute mode */
|
|
|
dfb331 |
ectx->program = ectx->altv[0];
|
|
|
dfb331 |
ectx->argv = ectx->altv;
|
|
|
dfb331 |
|
|
|
e956c8 |
/* step output */
|
|
|
dfb331 |
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) {
|
|
|
33a569 |
if (slbt_output_execute(ectx)) {
|
|
|
2e30eb |
slbt_ectx_free_exec_ctx(ectx);
|
|
|
a47c7a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
e956c8 |
}
|
|
|
dfb331 |
}
|
|
|
e956c8 |
|
|
|
dfb331 |
execvp(ectx->altv[0],ectx->altv);
|
|
|
e956c8 |
|
|
|
2e30eb |
slbt_ectx_free_exec_ctx(ectx);
|
|
|
6beda1 |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
e956c8 |
}
|