|
|
258073 |
/*******************************************************************/
|
|
|
258073 |
/* slibtool: a skinny libtool implementation, written in C */
|
|
|
258073 |
/* Copyright (C) 2016 Z. Gilboa */
|
|
|
258073 |
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
|
|
|
258073 |
/*******************************************************************/
|
|
|
258073 |
|
|
|
258073 |
#include <stdio.h>
|
|
|
258073 |
#include <string.h>
|
|
|
258073 |
#include <stdbool.h>
|
|
|
258073 |
#include <fcntl.h>
|
|
|
258073 |
#include <errno.h>
|
|
|
258073 |
#include <sys/stat.h>
|
|
|
258073 |
|
|
|
258073 |
#define ARGV_DRIVER
|
|
|
258073 |
|
|
|
258073 |
#include <slibtool/slibtool.h>
|
|
|
258073 |
#include "slibtool_install_impl.h"
|
|
|
258073 |
#include "slibtool_spawn_impl.h"
|
|
|
258073 |
#include "slibtool_symlink_impl.h"
|
|
|
258073 |
#include "argv/argv.h"
|
|
|
258073 |
|
|
|
258073 |
static int slbt_install_usage(
|
|
|
258073 |
const char * program,
|
|
|
258073 |
const char * arg,
|
|
|
258073 |
const struct argv_option * options,
|
|
|
258073 |
struct argv_meta * meta)
|
|
|
258073 |
{
|
|
|
258073 |
char header[512];
|
|
|
258073 |
|
|
|
258073 |
snprintf(header,sizeof(header),
|
|
|
258073 |
"Usage: %s --mode=install <install> [options] [SOURCE]... DEST\n"
|
|
|
258073 |
"Options:\n",
|
|
|
258073 |
program);
|
|
|
258073 |
|
|
|
258073 |
argv_usage(stdout,header,options,arg);
|
|
|
258073 |
argv_free(meta);
|
|
|
258073 |
|
|
|
258073 |
return SLBT_USAGE;
|
|
|
258073 |
}
|
|
|
258073 |
|
|
|
258073 |
static int slbt_exec_install_fail(
|
|
|
258073 |
struct slbt_exec_ctx * actx,
|
|
|
258073 |
struct argv_meta * meta)
|
|
|
258073 |
{
|
|
|
258073 |
argv_free(meta);
|
|
|
258073 |
slbt_free_exec_ctx(actx);
|
|
|
258073 |
return -1;
|
|
|
258073 |
}
|
|
|
258073 |
|
|
|
258073 |
static int slbt_exec_install_init_dstdir(
|
|
|
258073 |
struct argv_entry * dest,
|
|
|
258073 |
struct argv_entry * last,
|
|
|
258073 |
char * dstdir)
|
|
|
258073 |
{
|
|
|
061d4a |
struct stat st;
|
|
|
258073 |
char * slash;
|
|
|
258073 |
size_t len;
|
|
|
258073 |
|
|
|
258073 |
if (dest)
|
|
|
258073 |
last = dest;
|
|
|
258073 |
|
|
|
258073 |
/* dstdir: initial string */
|
|
|
258073 |
if ((size_t)snprintf(dstdir,PATH_MAX,"%s",
|
|
|
258073 |
last->arg) >= PATH_MAX)
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
/* dstdir might end with a slash */
|
|
|
258073 |
len = strlen(dstdir);
|
|
|
258073 |
|
|
|
258073 |
if (dstdir[--len] == '/')
|
|
|
258073 |
dstdir[len] = '\0';
|
|
|
258073 |
|
|
|
061d4a |
/* -t DSTDIR? */
|
|
|
061d4a |
if (dest)
|
|
|
061d4a |
return 0;
|
|
|
061d4a |
|
|
|
061d4a |
/* is DEST a directory? */
|
|
|
061d4a |
if (!(stat(dstdir,&st)))
|
|
|
061d4a |
if (S_ISDIR(st.st_mode))
|
|
|
061d4a |
return 0;
|
|
|
061d4a |
|
|
|
258073 |
/* remove last path component */
|
|
|
061d4a |
if ((slash = strrchr(dstdir,'/')))
|
|
|
258073 |
*slash = '\0';
|
|
|
258073 |
|
|
|
258073 |
return 0;
|
|
|
258073 |
}
|
|
|
258073 |
|
|
|
258073 |
static int slbt_exec_install_entry(
|
|
|
258073 |
const struct slbt_driver_ctx * dctx,
|
|
|
258073 |
struct slbt_exec_ctx * ectx,
|
|
|
258073 |
struct argv_entry * entry,
|
|
|
258073 |
struct argv_entry * last,
|
|
|
258073 |
struct argv_entry * dest,
|
|
|
258073 |
char * dstdir,
|
|
|
258073 |
char ** src,
|
|
|
258073 |
char ** dst)
|
|
|
258073 |
{
|
|
|
258073 |
int ret;
|
|
|
258073 |
char * dot;
|
|
|
258073 |
char * base;
|
|
|
258073 |
char * slash;
|
|
|
258073 |
char target [PATH_MAX];
|
|
|
258073 |
char srcfile [PATH_MAX];
|
|
|
258073 |
char dstfile [PATH_MAX];
|
|
|
258073 |
char slnkname[PATH_MAX];
|
|
|
258073 |
char dlnkname[PATH_MAX];
|
|
|
258073 |
char lasource[PATH_MAX];
|
|
|
5e5804 |
bool fexe = false;
|
|
|
5e5804 |
struct stat st;
|
|
|
5e5804 |
|
|
|
5e5804 |
/* executable wrapper? */
|
|
|
5e5804 |
if ((size_t)snprintf(slnkname,sizeof(slnkname),"%s.exe.wrapper",
|
|
|
5e5804 |
entry->arg) >= sizeof(slnkname))
|
|
|
5e5804 |
return -1;
|
|
|
5e5804 |
|
|
|
5e5804 |
fexe = stat(slnkname,&st)
|
|
|
5e5804 |
? false
|
|
|
5e5804 |
: true;
|
|
|
258073 |
|
|
|
258073 |
/* .la ? */
|
|
|
5e5804 |
if (!fexe && (!(dot = strrchr(entry->arg,'.')) || strcmp(dot,".la"))) {
|
|
|
258073 |
*src = (char *)entry->arg;
|
|
|
258073 |
*dst = dest ? 0 : (char *)last->arg;
|
|
|
258073 |
|
|
|
258073 |
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
|
|
|
258073 |
if (slbt_output_install(dctx,ectx))
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
return (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
|
|
|
258073 |
? -1 : 0;
|
|
|
258073 |
}
|
|
|
258073 |
|
|
|
258073 |
/* srcfile */
|
|
|
258073 |
if (strlen(entry->arg) + strlen(".libs/") >= (PATH_MAX-1))
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
strcpy(lasource,entry->arg);
|
|
|
258073 |
|
|
|
258073 |
if ((slash = strrchr(lasource,'/'))) {
|
|
|
258073 |
*slash++ = '\0';
|
|
|
258073 |
sprintf(srcfile,"%s/.libs/%s",lasource,slash);
|
|
|
258073 |
} else
|
|
|
258073 |
sprintf(srcfile,".libs/%s",lasource);
|
|
|
258073 |
|
|
|
5e5804 |
/* executable? */
|
|
|
5e5804 |
if (fexe) {
|
|
|
5e5804 |
*src = srcfile;
|
|
|
5e5804 |
*dst = dest ? 0 : (char *)last->arg;
|
|
|
5e5804 |
|
|
|
5e5804 |
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
|
|
|
5e5804 |
if (slbt_output_install(dctx,ectx))
|
|
|
5e5804 |
return -1;
|
|
|
5e5804 |
|
|
|
5e5804 |
return (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
|
|
|
5e5804 |
? -1 : 0;
|
|
|
5e5804 |
}
|
|
|
258073 |
|
|
|
258073 |
/* libfoo.la --> libfoo.so */
|
|
|
5e5804 |
strcpy(slnkname,srcfile);
|
|
|
258073 |
dot = strrchr(slnkname,'.');
|
|
|
b3c21a |
strcpy(dot,dctx->cctx->settings.dsosuffix);
|
|
|
258073 |
|
|
|
258073 |
/* basename */
|
|
|
258073 |
if ((base = strrchr(slnkname,'/')))
|
|
|
258073 |
base++;
|
|
|
258073 |
else
|
|
|
258073 |
base = slnkname;
|
|
|
258073 |
|
|
|
258073 |
/* source (build) symlink target */
|
|
|
b107e2 |
if (readlink(slnkname,target,sizeof(target)) <= 0) {
|
|
|
b107e2 |
/* -avoid-version? */
|
|
|
b107e2 |
if (stat(slnkname,&st))
|
|
|
b107e2 |
return -1;
|
|
|
b107e2 |
|
|
|
b107e2 |
/* dstfile */
|
|
|
b107e2 |
if ((size_t)snprintf(dstfile,sizeof(dstfile),"%s/%s",
|
|
|
b107e2 |
dstdir,base) >= sizeof(dstfile))
|
|
|
b107e2 |
return -1;
|
|
|
b107e2 |
|
|
|
b107e2 |
/* single spawn, no symlinks */
|
|
|
b107e2 |
*src = slnkname;
|
|
|
b107e2 |
*dst = dest ? 0 : dstfile;
|
|
|
b107e2 |
|
|
|
b107e2 |
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
|
|
|
b107e2 |
if (slbt_output_install(dctx,ectx))
|
|
|
b107e2 |
return -1;
|
|
|
b107e2 |
|
|
|
b107e2 |
if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
|
|
|
b107e2 |
return -1;
|
|
|
b107e2 |
|
|
|
b107e2 |
return 0;
|
|
|
b107e2 |
}
|
|
|
258073 |
|
|
|
258073 |
/* srcfile: .libs/libfoo.so.x.y.z */
|
|
|
258073 |
slash = strrchr(srcfile,'/');
|
|
|
258073 |
strcpy(++slash,target);
|
|
|
258073 |
|
|
|
258073 |
/* dstfile */
|
|
|
258073 |
if (!dest)
|
|
|
258073 |
if ((size_t)snprintf(dstfile,sizeof(dstfile),"%s/%s",
|
|
|
258073 |
dstdir,target) >= sizeof(dstfile))
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
/* spawn */
|
|
|
258073 |
*src = srcfile;
|
|
|
258073 |
*dst = dest ? 0 : dstfile;
|
|
|
258073 |
|
|
|
258073 |
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
|
|
|
258073 |
if (slbt_output_install(dctx,ectx))
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
/* destination symlink: dstdir/libfoo.so */
|
|
|
258073 |
if ((size_t)snprintf(dlnkname,sizeof(dlnkname),"%s/%s",
|
|
|
258073 |
dstdir,base) >= sizeof(dlnkname))
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
/* create symlink: libfoo.so --> libfoo.so.x.y.z */
|
|
|
258073 |
if (slbt_create_symlink(
|
|
|
258073 |
dctx,ectx,
|
|
|
258073 |
target,dlnkname,
|
|
|
258073 |
false))
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
/* libfoo.so.x.y.z --> libfoo.so.x */
|
|
|
258073 |
strcpy(slnkname,target);
|
|
|
258073 |
|
|
|
258073 |
if ((dot = strrchr(slnkname,'.')))
|
|
|
258073 |
*dot = '\0';
|
|
|
258073 |
else
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
if ((dot = strrchr(slnkname,'.')))
|
|
|
258073 |
*dot = '\0';
|
|
|
258073 |
else
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
/* destination symlink: dstdir/libfoo.so.x */
|
|
|
258073 |
if ((size_t)snprintf(dlnkname,sizeof(dlnkname),"%s/%s",
|
|
|
258073 |
dstdir,slnkname) >= sizeof(dlnkname))
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
/* create symlink: libfoo.so.x --> libfoo.so.x.y.z */
|
|
|
258073 |
if (slbt_create_symlink(
|
|
|
258073 |
dctx,ectx,
|
|
|
258073 |
target,dlnkname,
|
|
|
258073 |
false))
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
return 0;
|
|
|
258073 |
}
|
|
|
258073 |
|
|
|
258073 |
int slbt_exec_install(
|
|
|
258073 |
const struct slbt_driver_ctx * dctx,
|
|
|
258073 |
struct slbt_exec_ctx * ectx)
|
|
|
258073 |
{
|
|
|
258073 |
int ret;
|
|
|
258073 |
char ** argv;
|
|
|
258073 |
char ** src;
|
|
|
258073 |
char ** dst;
|
|
|
258073 |
struct slbt_exec_ctx * actx;
|
|
|
258073 |
struct argv_meta * meta;
|
|
|
258073 |
struct argv_entry * entry;
|
|
|
258073 |
struct argv_entry * copy;
|
|
|
258073 |
struct argv_entry * dest;
|
|
|
258073 |
struct argv_entry * last;
|
|
|
258073 |
char dstdir[PATH_MAX];
|
|
|
258073 |
const struct argv_option * options = slbt_install_options;
|
|
|
258073 |
|
|
|
258073 |
/* context */
|
|
|
258073 |
if (ectx)
|
|
|
258073 |
actx = 0;
|
|
|
258073 |
else if ((ret = slbt_get_exec_ctx(dctx,&ectx)))
|
|
|
258073 |
return ret;
|
|
|
258073 |
else
|
|
|
258073 |
actx = ectx;
|
|
|
258073 |
|
|
|
258073 |
/* initial state, install mode skin */
|
|
|
258073 |
slbt_reset_arguments(ectx);
|
|
|
258073 |
slbt_disable_placeholders(ectx);
|
|
|
258073 |
argv = ectx->cargv;
|
|
|
258073 |
|
|
|
258073 |
/* missing arguments? */
|
|
|
258073 |
if (!argv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE))
|
|
|
258073 |
return slbt_install_usage(dctx->program,0,options,0);
|
|
|
258073 |
|
|
|
258073 |
/* <install> argv meta */
|
|
|
258073 |
if (!(meta = argv_get(
|
|
|
258073 |
argv,
|
|
|
258073 |
options,
|
|
|
258073 |
dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS
|
|
|
258073 |
? ARGV_VERBOSITY_ERRORS
|
|
|
258073 |
: ARGV_VERBOSITY_NONE)))
|
|
|
258073 |
return slbt_exec_install_fail(actx,meta);
|
|
|
258073 |
|
|
|
258073 |
/* dest, alternate argument vector options */
|
|
|
258073 |
argv = ectx->altv;
|
|
|
258073 |
copy = meta->entries;
|
|
|
258073 |
dest = 0;
|
|
|
258073 |
last = 0;
|
|
|
258073 |
|
|
|
258073 |
*argv++ = ectx->cargv[0];
|
|
|
258073 |
|
|
|
258073 |
for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
|
|
|
258073 |
if (entry->fopt) {
|
|
|
258073 |
switch (entry->tag) {
|
|
|
258073 |
case TAG_INSTALL_COPY:
|
|
|
258073 |
*argv++ = "-c";
|
|
|
258073 |
copy = entry;
|
|
|
258073 |
break;
|
|
|
258073 |
|
|
|
258073 |
case TAG_INSTALL_MKDIR:
|
|
|
258073 |
*argv++ = "-d";
|
|
|
258073 |
copy = 0;
|
|
|
258073 |
break;
|
|
|
258073 |
|
|
|
258073 |
case TAG_INSTALL_TARGET_MKDIR:
|
|
|
258073 |
*argv++ = "-D";
|
|
|
258073 |
copy = 0;
|
|
|
258073 |
break;
|
|
|
258073 |
|
|
|
258073 |
case TAG_INSTALL_STRIP:
|
|
|
258073 |
*argv++ = "-s";
|
|
|
258073 |
break;
|
|
|
258073 |
|
|
|
258073 |
case TAG_INSTALL_PRESERVE:
|
|
|
258073 |
*argv++ = "-p";
|
|
|
258073 |
break;
|
|
|
258073 |
|
|
|
258073 |
case TAG_INSTALL_USER:
|
|
|
258073 |
*argv++ = "-o";
|
|
|
258073 |
break;
|
|
|
258073 |
|
|
|
258073 |
case TAG_INSTALL_GROUP:
|
|
|
258073 |
*argv++ = "-g";
|
|
|
258073 |
break;
|
|
|
258073 |
|
|
|
258073 |
case TAG_INSTALL_MODE:
|
|
|
258073 |
*argv++ = "-m";
|
|
|
258073 |
break;
|
|
|
258073 |
|
|
|
258073 |
case TAG_INSTALL_DSTDIR:
|
|
|
258073 |
*argv++ = "-t";
|
|
|
258073 |
dest = entry;
|
|
|
258073 |
break;
|
|
|
258073 |
}
|
|
|
258073 |
|
|
|
258073 |
if (entry->fval)
|
|
|
258073 |
*argv++ = (char *)entry->arg;
|
|
|
258073 |
} else
|
|
|
258073 |
last = entry;
|
|
|
258073 |
}
|
|
|
258073 |
|
|
|
258073 |
/* install */
|
|
|
258073 |
if (copy) {
|
|
|
258073 |
/* using alternate argument vector */
|
|
|
258073 |
ectx->argv = ectx->altv;
|
|
|
258073 |
ectx->program = ectx->altv[0];
|
|
|
258073 |
|
|
|
258073 |
/* marks */
|
|
|
258073 |
src = argv++;
|
|
|
258073 |
dst = argv++;
|
|
|
258073 |
|
|
|
258073 |
/* dstdir */
|
|
|
258073 |
if (slbt_exec_install_init_dstdir(dest,last,dstdir))
|
|
|
258073 |
return slbt_exec_install_fail(actx,meta);
|
|
|
258073 |
|
|
|
258073 |
/* install entries one at a time */
|
|
|
258073 |
for (entry=meta->entries; entry->fopt || entry->arg; entry++)
|
|
|
258073 |
if (!entry->fopt && (dest || (entry != last)))
|
|
|
258073 |
if (slbt_exec_install_entry(
|
|
|
258073 |
dctx,ectx,
|
|
|
258073 |
entry,last,
|
|
|
258073 |
dest,dstdir,
|
|
|
258073 |
src,dst))
|
|
|
258073 |
return slbt_exec_install_fail(actx,meta);
|
|
|
258073 |
} else {
|
|
|
258073 |
/* using original argument vector */
|
|
|
258073 |
ectx->argv = ectx->cargv;
|
|
|
258073 |
ectx->program = ectx->cargv[0];
|
|
|
258073 |
|
|
|
258073 |
/* spawn */
|
|
|
258073 |
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
|
|
|
258073 |
if (slbt_output_install(dctx,ectx))
|
|
|
258073 |
return -1;
|
|
|
258073 |
|
|
|
258073 |
if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
|
|
|
258073 |
return slbt_exec_install_fail(actx,meta);
|
|
|
258073 |
}
|
|
|
258073 |
|
|
|
258073 |
argv_free(meta);
|
|
|
258073 |
slbt_free_exec_ctx(actx);
|
|
|
258073 |
|
|
|
258073 |
return 0;
|
|
|
258073 |
}
|