Blame src/logic/slbt_exec_install.c

258073
/*******************************************************************/
258073
/*  slibtool: a skinny libtool implementation, written in C        */
49181b
/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
258073
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
258073
/*******************************************************************/
258073
50fd60
#include <fcntl.h>
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
#include <slibtool/slibtool.h>
d58d2f
#include "slibtool_driver_impl.h"
258073
#include "slibtool_install_impl.h"
50fd60
#include "slibtool_mapfile_impl.h"
e8159c
#include "slibtool_readlink_impl.h"
258073
#include "slibtool_spawn_impl.h"
258073
#include "slibtool_symlink_impl.h"
8a1cbd
#include "slibtool_errinfo_impl.h"
19022e
#include "slibtool_snprintf_impl.h"
258073
#include "argv/argv.h"
258073
258073
static int slbt_install_usage(
a82cc2
	int				fdout,
258073
	const char *			program,
258073
	const char *			arg,
d58d2f
	const struct argv_option **	optv,
611918
	struct argv_meta *		meta,
611918
	int				noclr)
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
611918
	switch (noclr) {
611918
		case 0:
a05389
			slbt_argv_usage(fdout,header,optv,arg);
611918
			break;
611918
611918
		default:
a05389
			slbt_argv_usage_plain(fdout,header,optv,arg);
611918
			break;
611918
	}
611918
a05389
	slbt_argv_free(meta);
258073
258073
	return SLBT_USAGE;
258073
}
258073
258073
static int slbt_exec_install_fail(
2e30eb
	struct slbt_exec_ctx *	ectx,
8a1cbd
	struct argv_meta *	meta,
8a1cbd
	int			ret)
258073
{
a05389
	slbt_argv_free(meta);
2e30eb
	slbt_ectx_free_exec_ctx(ectx);
8a1cbd
	return ret;
258073
}
258073
258073
static int slbt_exec_install_init_dstdir(
8a1cbd
	const struct slbt_driver_ctx *	dctx,
258073
	struct argv_entry *	dest,
258073
	struct argv_entry *	last,
258073
	char *			dstdir)
258073
{
7ae5c1
	int		fdcwd;
061d4a
	struct stat	st;
258073
	char *		slash;
258073
	size_t		len;
258073
7ae5c1
	/* fdcwd */
7ae5c1
	fdcwd = slbt_driver_fdcwd(dctx);
8a1cbd
7ae5c1
	/* last */
258073
	if (dest)
258073
		last = dest;
258073
258073
	/* dstdir: initial string */
19022e
	if (slbt_snprintf(dstdir,PATH_MAX,
19022e
			"%s",last->arg) < 0)
8a1cbd
		return SLBT_BUFFER_ERROR(dctx);
258073
258073
	/* dstdir might end with a slash */
258073
	len = strlen(dstdir);
258073
258073
	if (dstdir[--len] == '/')
239674
		dstdir[len] = 0;
258073
061d4a
	/* -t DSTDIR? */
061d4a
	if (dest)
061d4a
		return 0;
061d4a
061d4a
	/* is DEST a directory? */
7ae5c1
	if (!fstatat(fdcwd,dstdir,&st,0))
061d4a
		if (S_ISDIR(st.st_mode))
061d4a
			return 0;
061d4a
258073
	/* remove last path component */
061d4a
	if ((slash = strrchr(dstdir,'/')))
239674
		*slash = 0;
258073
258073
	return 0;
258073
}
258073
c6e3d1
static int slbt_exec_install_import_libraries(
c6e3d1
	const struct slbt_driver_ctx *	dctx,
c6e3d1
	struct slbt_exec_ctx *		ectx,
c6e3d1
	char *				srcdso,
c6e3d1
	char *				dstdir)
c6e3d1
{
c6e3d1
	char *	slash;
c6e3d1
	char *	dot;
c6e3d1
	char *	mark;
c6e3d1
	char	srcbuf [PATH_MAX];
c6e3d1
	char	implib [PATH_MAX];
c6e3d1
	char	hostlnk[PATH_MAX];
c6e3d1
	char	major  [128];
c6e3d1
	char	minor  [128];
c6e3d1
	char	rev    [128];
c6e3d1
c6e3d1
	/* .libs/libfoo.so.x.y.z */
19022e
	if (slbt_snprintf(srcbuf,sizeof(srcbuf),
19022e
			"%s",srcdso) <0)
8a1cbd
		return SLBT_BUFFER_ERROR(dctx);
c6e3d1
c6e3d1
	/* (dso is under .libs) */
c6e3d1
	if (!(slash = strrchr(srcbuf,'/')))
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
c6e3d1
c6e3d1
	/* libfoo.so.x.y.z */
19022e
	const char * impsuffix = dctx->cctx->settings.impsuffix;
19022e
19022e
	if (slbt_snprintf(implib,
19022e
			sizeof(implib) - strlen(impsuffix),
19022e
			"%s",++slash) < 0)
8a1cbd
		return SLBT_BUFFER_ERROR(dctx);
c6e3d1
Kylie McClain 7ce25c
	/* guard against an infinitely long version */
c6e3d1
	mark = srcbuf + strlen(srcbuf);
c6e3d1
465de6
	if (dctx->cctx->asettings.osdfussix[0]) {
465de6
		if (!(dot = strrchr(srcbuf,'.')))
465de6
			return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
465de6
465de6
		*dot = 0;
465de6
	}
465de6
c6e3d1
	/* rev */
c6e3d1
	if (!(dot = strrchr(srcbuf,'.')))
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
c6e3d1
	else if ((size_t)(mark - dot) > sizeof(rev))
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_REV);
c6e3d1
	else {
c6e3d1
		strcpy(rev,dot);
239674
		*dot = 0;
c6e3d1
	}
c6e3d1
c6e3d1
	/* minor */
c6e3d1
	if (!(dot = strrchr(srcbuf,'.')))
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
c6e3d1
	else if ((size_t)(mark - dot) > sizeof(minor))
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_REV);
c6e3d1
	else {
c6e3d1
		strcpy(minor,dot);
239674
		*dot = 0;
c6e3d1
	}
c6e3d1
c6e3d1
	/* major */
c6e3d1
	if (!(dot = strrchr(srcbuf,'.')))
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
c6e3d1
	else if ((size_t)(mark - dot) > sizeof(major))
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_REV);
c6e3d1
	else {
c6e3d1
		strcpy(major,dot);
239674
		*dot = 0;
c6e3d1
	}
c6e3d1
465de6
	if (!dctx->cctx->asettings.osdfussix[0])
465de6
		if (!(dot = strrchr(srcbuf,'.')))
465de6
			return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
c6e3d1
c6e3d1
	/* .libs/libfoo.x.y.z.lib.a */
c6e3d1
	sprintf(dot,"%s%s%s%s",
c6e3d1
		major,minor,rev,
c6e3d1
		dctx->cctx->asettings.impsuffix);
c6e3d1
c6e3d1
	/* copy: .libs/libfoo.x.y.z.lib.a --> dstdir */
fc7ad9
	if (slbt_util_copy_file(ectx,srcbuf,dstdir))
8a1cbd
		return SLBT_NESTED_ERROR(dctx);
c6e3d1
c6e3d1
	/* .libs/libfoo.x.lib.a */
c6e3d1
	sprintf(dot,"%s%s",
c6e3d1
		major,
c6e3d1
		dctx->cctx->asettings.impsuffix);
c6e3d1
c6e3d1
	/* copy: .libs/libfoo.x.lib.a --> dstdir */
fc7ad9
	if (slbt_util_copy_file(ectx,srcbuf,dstdir))
8a1cbd
		return SLBT_NESTED_ERROR(dctx);
c6e3d1
c6e3d1
	/* /dstdir/libfoo.lib.a */
c6e3d1
	strcpy(implib,slash);
c6e3d1
	strcpy(dot,dctx->cctx->asettings.impsuffix);
c6e3d1
19022e
	if (slbt_snprintf(hostlnk,sizeof(hostlnk),
19022e
			"%s/%s",dstdir,slash) <0)
8a1cbd
		return SLBT_BUFFER_ERROR(dctx);
c6e3d1
c6e3d1
	if (slbt_create_symlink(
c6e3d1
			dctx,ectx,
c6e3d1
			implib,
c6e3d1
			hostlnk,
cc0827
			SLBT_SYMLINK_DEFAULT))
8a1cbd
		return SLBT_NESTED_ERROR(dctx);
c6e3d1
c6e3d1
	return 0;
c6e3d1
}
c6e3d1
5b5408
static int slbt_exec_install_library_wrapper(
5b5408
	const struct slbt_driver_ctx *	dctx,
5b5408
	struct slbt_exec_ctx *		ectx,
5b5408
	struct argv_entry *		entry,
5b5408
	char *				dstdir)
5b5408
{
5fac6c
	int			fdcwd;
50fd60
	int			fddst;
50fd60
	size_t			buflen;
50fd60
	const char *		base;
50fd60
	char *			srcline;
50fd60
	char *			dstline;
50fd60
	char			clainame[PATH_MAX];
50fd60
	char			instname[PATH_MAX];
50fd60
	char			cfgbuf  [PATH_MAX];
50fd60
	struct slbt_map_info *	mapinfo;
5b5408
5b5408
	/* base libfoo.la */
5b5408
	if ((base = strrchr(entry->arg,'/')))
5b5408
		base++;
5b5408
	else
5b5408
		base = entry->arg;
5b5408
5b5408
	/* /dstdir/libfoo.la */
19022e
	if (slbt_snprintf(instname,sizeof(instname),
19022e
			"%s/%s",dstdir,base) < 0)
8a1cbd
		return SLBT_BUFFER_ERROR(dctx);
5b5408
5b5408
	/* libfoo.la.slibtool.install */
19022e
	if (slbt_snprintf(clainame,sizeof(clainame),
19022e
			"%s.slibtool.install",
19022e
			entry->arg) < 0)
8a1cbd
		return SLBT_BUFFER_ERROR(dctx);
5b5408
5fac6c
	/* fdcwd */
5fac6c
	fdcwd = slbt_driver_fdcwd(dctx);
5fac6c
50fd60
	/* fddst (libfoo.la.slibtool.install, build directory) */
5fac6c
	if ((fddst = openat(fdcwd,clainame,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0)
6beda1
		return SLBT_SYSTEM_ERROR(dctx,clainame);
5b5408
50fd60
	/* mapinfo (libfoo.la, build directory) */
5fac6c
	if (!(mapinfo = slbt_map_file(fdcwd,entry->arg,SLBT_MAP_INPUT))) {
50fd60
		close(fddst);
6beda1
		return SLBT_SYSTEM_ERROR(dctx,entry->arg);
5b5408
	}
5b5408
50fd60
	/* srcline */
50fd60
	if (mapinfo->size < sizeof(cfgbuf)) {
50fd60
		buflen  = sizeof(cfgbuf);
50fd60
		srcline = cfgbuf;
50fd60
	} else {
50fd60
		buflen  = mapinfo->size;
50fd60
		srcline = malloc(++buflen);
5b5408
	}
5b5408
50fd60
	if (!srcline) {
50fd60
		close(fddst);
50fd60
		slbt_unmap_file(mapinfo);
6beda1
		return SLBT_SYSTEM_ERROR(dctx,0);
5b5408
	}
5b5408
50fd60
	/* copy config, installed=no --> installed=yes */
50fd60
	while (mapinfo->mark < mapinfo->cap) {
50fd60
		if (slbt_mapped_readline(dctx,mapinfo,srcline,buflen) < 0) {
50fd60
			close(fddst);
50fd60
			slbt_unmap_file(mapinfo);
50fd60
			return SLBT_NESTED_ERROR(dctx);
50fd60
		}
50fd60
50fd60
		dstline = strcmp(srcline,"installed=no\n")
50fd60
			? srcline
50fd60
			: "installed=yes\n";
50fd60
50fd60
		if (slbt_dprintf(fddst,"%s",dstline) < 0) {
50fd60
			close(fddst);
50fd60
			slbt_unmap_file(mapinfo);
6beda1
			return SLBT_SYSTEM_ERROR(dctx,0);
50fd60
		}
5b5408
	}
5b5408
5b5408
	if (srcline != cfgbuf)
5b5408
		free(srcline);
5b5408
50fd60
	/* close, unmap */
50fd60
	close(fddst);
50fd60
	slbt_unmap_file(mapinfo);
5b5408
fb4fd0
	/* cp libfoo.la.slibtool.install /dstdir/libfoo.la */
fc7ad9
	if (slbt_util_copy_file(ectx,clainame,instname))
8a1cbd
		return SLBT_NESTED_ERROR(dctx);
5b5408
5b5408
	return 0;
5b5408
}
5b5408
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
{
7ae5c1
	int		fdcwd;
70949a
	const char *	base;
258073
	char *		dot;
465de6
	char *		host;
fb9dae
	char *		mark;
258073
	char *		slash;
ca36f5
	char *		suffix;
87b0f7
	char *		dsosuffix;
87b0f7
	char		sobuf   [64];
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];
465de6
	char		hosttag [PATH_MAX];
aa8ca6
	char		lasource[PATH_MAX - 8];
5e5804
	bool		fexe = false;
1c05ca
	bool		fpe;
112a2b
	bool		frelease;
fb9dae
	bool		fdualver;
adb290
	bool		fstatic;
9a5f96
	bool		farchive;
87b0f7
	size_t		slen;
cccab5
	size_t		dlen;
5e5804
	struct stat	st;
5e5804
5e5804
	/* executable wrapper? */
70949a
	base = (slash = strrchr(entry->arg,'/'))
70949a
		? ++slash : entry->arg;
70949a
70949a
	strcpy(slnkname,entry->arg);
70949a
	mark = &slnkname[base - entry->arg];
70949a
	slen = sizeof(slnkname) - (mark - slnkname);
70949a
19022e
	if (slbt_snprintf(mark,slen,
70949a
			".libs/%s.exe.wrapper",
19022e
			base) < 0)
8a1cbd
		return SLBT_BUFFER_ERROR(dctx);
5e5804
7ae5c1
	/* fdcwd */
7ae5c1
	fdcwd = slbt_driver_fdcwd(dctx);
7ae5c1
7ae5c1
	/* fexe */
a7dc81
	fexe = !fstatat(fdcwd,slnkname,&st,0);
258073
7ae5c1
	/* argument suffix */
af8d17
	dot  = strrchr(entry->arg,'.');
af8d17
af8d17
	/* .lai --> .la */
af8d17
	if (!fexe && dot && !strcmp(dot,".lai"))
af8d17
		dot[3] = 0;
af8d17
258073
	/* srcfile */
258073
	if (strlen(entry->arg) + strlen(".libs/") >= (PATH_MAX-1))
8a1cbd
		return SLBT_BUFFER_ERROR(dctx);
258073
258073
	strcpy(lasource,entry->arg);
258073
258073
	if ((slash = strrchr(lasource,'/'))) {
239674
		*slash++ = 0;
258073
		sprintf(srcfile,"%s/.libs/%s",lasource,slash);
a7dc81
	} else {
258073
		sprintf(srcfile,".libs/%s",lasource);
a7dc81
	}
258073
185842
	/* executable? ordinary file? */
185842
	if (fexe || !dot || strcmp(dot,".la")) {
185842
		*src = fexe ? srcfile : (char *)entry->arg;
185842
		*dst = dest ? 0 : (char *)last->arg;
185842
185842
		if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
33a569
			if (slbt_output_install(ectx))
185842
				return SLBT_NESTED_ERROR(dctx);
185842
3056ff
		if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
3056ff
			return SLBT_SPAWN_ERROR(dctx);
3056ff
3056ff
		} else if (ectx->exitcode) {
3056ff
			return SLBT_CUSTOM_ERROR(
3056ff
				dctx,
3056ff
				SLBT_ERR_INSTALL_ERROR);
3056ff
		}
3056ff
3056ff
		return 0;
185842
	}
185842
87b0f7
	/* -shrext, dsosuffix */
87b0f7
	strcpy(sobuf,dctx->cctx->settings.dsosuffix);
87b0f7
	dsosuffix = sobuf;
87b0f7
19022e
	if (slbt_snprintf(slnkname,sizeof(slnkname),
19022e
			"%s.shrext",srcfile) < 0)
87b0f7
		return SLBT_BUFFER_ERROR(dctx);
87b0f7
7ae5c1
	if (!fstatat(fdcwd,slnkname,&st,0)) {
c81d16
		if (slbt_readlinkat(fdcwd,slnkname,target,sizeof(target)) < 0)
87b0f7
			return SLBT_SYSTEM_ERROR(dctx,slnkname);
87b0f7
87b0f7
		if (strncmp(lasource,target,(slen = strlen(lasource))))
87b0f7
			return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
87b0f7
87b0f7
		if (strncmp(&target[slen],".shrext",7))
87b0f7
			return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
87b0f7
87b0f7
		strcpy(sobuf,&target[slen+7]);
87b0f7
	}
87b0f7
e13a5c
	/* legabits? */
e13a5c
	if (dctx->cctx->drvflags & SLBT_DRIVER_LEGABITS)
e13a5c
		if (slbt_exec_install_library_wrapper(dctx,ectx,entry,dstdir))
8a1cbd
			return SLBT_NESTED_ERROR(dctx);
e13a5c
e13a5c
	/* *dst: consider: cp libfoo.la /dest/dir/libfoo.la */
e13a5c
	if ((*dst = dest ? 0 : (char *)last->arg))
e13a5c
		if ((dot = strrchr(last->arg,'.')))
e13a5c
			if (!(strcmp(dot,".la")))
e13a5c
				*dst = dstdir;
e13a5c
f38ea1
	/* libfoo.a */
f38ea1
	dot = strrchr(srcfile,'.');
f38ea1
	strcpy(dot,dctx->cctx->settings.arsuffix);
f38ea1
112a2b
	/* dot/suffix */
5e5804
	strcpy(slnkname,srcfile);
258073
	dot = strrchr(slnkname,'.');
112a2b
465de6
	/* .libs/libfoo.so.def.host */
465de6
	slen  = sizeof(slnkname);
465de6
	slen -= (dot - slnkname);
465de6
fb9dae
	/* detect -release, exclusively or alongside -version-info */
fb9dae
	frelease = false;
fb9dae
	fdualver = false;
adb290
	fstatic  = false;
adb290
	fpe      = false;
adb290
adb290
	/* static library only? */
adb290
	sprintf(dot,"%s",dsosuffix);
adb290
	fstatic = slbt_symlink_is_a_placeholder(fdcwd,slnkname);
fb9dae
cccab5
	/* libfoo.a --> libfoo.so.release */
adb290
	if (!fstatic) {
adb290
		sprintf(dot,"%s.release",dsosuffix);
adb290
		frelease = !fstatat(fdcwd,slnkname,&st,0);
adb290
	}
fb9dae
fb9dae
	/* libfoo.a --> libfoo.so.dualver */
adb290
	if (!fstatic && !frelease) {
fb9dae
		sprintf(dot,"%s.dualver",dsosuffix);
fb9dae
		fdualver = !fstatat(fdcwd,slnkname,&st,0);
fb9dae
	}
465de6
465de6
	/* libfoo.so.def.{flavor} */
adb290
	if (fstatic) {
adb290
		(void)0;
adb290
adb290
	} else if (frelease || fdualver) {
cccab5
		strcpy(dlnkname,slnkname);
cccab5
		slash = strrchr(dlnkname,'/');
cccab5
cccab5
		dlen  = sizeof(dlnkname);
cccab5
		dlen -= (++slash - dlnkname);
cccab5
		dlen -= 9;
cccab5
cccab5
		if (slbt_readlinkat(fdcwd,slnkname,slash,dlen))
cccab5
			return SLBT_SYSTEM_ERROR(dctx,slnkname);
cccab5
fb9dae
		if (fdualver) {
fb9dae
			/* remove .patch */
fb9dae
			if (!(mark = strrchr(dlnkname,'.')))
fb9dae
				return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
fb9dae
fb9dae
			*mark = 0;
fb9dae
fb9dae
			/* remove .minor */
fb9dae
			if (!(mark = strrchr(dlnkname,'.')))
fb9dae
				return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
fb9dae
fb9dae
			*mark = 0;
fb9dae
fb9dae
			/* remove .major */
fb9dae
			if (!(mark = strrchr(dlnkname,'.')))
fb9dae
				return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
fb9dae
		} else {
fb9dae
			mark = slash += strlen(slash);
fb9dae
		}
fb9dae
fb9dae
		strcpy(mark,".def.host");
cccab5
cccab5
		if (slbt_readlinkat(fdcwd,dlnkname,hosttag,sizeof(hosttag)))
cccab5
			return SLBT_SYSTEM_ERROR(dctx,slnkname);
cccab5
	} else {
19022e
		if (slbt_snprintf(dot,slen,"%s.def.host",dsosuffix) < 0)
cccab5
			return SLBT_BUFFER_ERROR(dctx);
cccab5
cccab5
		if (slbt_readlinkat(fdcwd,frelease ? dlnkname : slnkname,hosttag,sizeof(hosttag)))
cccab5
			return SLBT_SYSTEM_ERROR(dctx,slnkname);
cccab5
	}
465de6
465de6
	/* host/flabor */
adb290
	if (fstatic) {
adb290
		(void)0;
adb290
adb290
	} else if (!(host = strrchr(hosttag,'.'))) {
465de6
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
adb290
	} else {
465de6
		host++;
adb290
	}
465de6
465de6
	/* symlink-based alternate host */
adb290
	if (!fstatic) {
4373b8
		if (slbt_host_set_althost(dctx,host,host))
adb290
			return SLBT_NESTED_ERROR(dctx);
465de6
adb290
		fpe = !strcmp(dctx->cctx->asettings.imagefmt,"pe");
adb290
	}
e4090f
112a2b
	/* libfoo.a --> libfoo.so */
87b0f7
	strcpy(dot,dsosuffix);
258073
9a5f96
	/* libfoo.a installation */
9a5f96
	if (!(dctx->cctx->drvflags & SLBT_DRIVER_DISABLE_STATIC))
9a5f96
		farchive = true;
adb290
	else if (fstatic)
9a5f96
		farchive = true;
9a5f96
	else
9a5f96
		farchive = false;
9a5f96
9a5f96
	if (farchive)
fc7ad9
		if (slbt_util_copy_file(
fc7ad9
				ectx,
9a5f96
				srcfile,
9a5f96
				dest ? (char *)dest->arg : *dst))
9a5f96
			return SLBT_NESTED_ERROR(dctx);
9a5f96
258073
	/* basename */
258073
	if ((base = strrchr(slnkname,'/')))
258073
		base++;
258073
	else
258073
		base = slnkname;
258073
258073
	/* source (build) symlink target */
c81d16
	if (slbt_readlinkat(fdcwd,slnkname,target,sizeof(target)) < 0) {
2baf1c
		/* -all-static? */
adb290
		if (fstatic)
2baf1c
			return 0;
2baf1c
b107e2
		/* -avoid-version? */
7ae5c1
		if (fstatat(fdcwd,slnkname,&st,0))
6beda1
			return SLBT_SYSTEM_ERROR(dctx,slnkname);
b107e2
b107e2
		/* dstfile */
19022e
		if (slbt_snprintf(dstfile,sizeof(dstfile),
19022e
				"%s/%s",dstdir,base) < 0)
8a1cbd
			return SLBT_BUFFER_ERROR(dctx);
b107e2
b107e2
		/* single spawn, no symlinks */
b107e2
		*src = slnkname;
b107e2
		*dst = dest ? 0 : dstfile;
b107e2
b107e2
		if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
33a569
			if (slbt_output_install(ectx))
8a1cbd
				return SLBT_NESTED_ERROR(dctx);
b107e2
3056ff
		if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
8a1cbd
			return SLBT_SPAWN_ERROR(dctx);
b107e2
3056ff
		} else if (ectx->exitcode) {
3056ff
			return SLBT_CUSTOM_ERROR(
3056ff
				dctx,
3056ff
				SLBT_ERR_INSTALL_ERROR);
3056ff
		}
3056ff
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)
19022e
		if (slbt_snprintf(dstfile,sizeof(dstfile),
19022e
				"%s/%s",dstdir,target) < 0)
8a1cbd
			return SLBT_BUFFER_ERROR(dctx);
258073
258073
	/* spawn */
258073
	*src = srcfile;
258073
	*dst = dest ? 0 : dstfile;
258073
258073
	if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
33a569
		if (slbt_output_install(ectx))
8a1cbd
			return SLBT_NESTED_ERROR(dctx);
258073
3056ff
	if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
8a1cbd
		return SLBT_SPAWN_ERROR(dctx);
258073
3056ff
	} else if (ectx->exitcode) {
3056ff
		return SLBT_CUSTOM_ERROR(
3056ff
			dctx,
3056ff
			SLBT_ERR_INSTALL_ERROR);
3056ff
	}
3056ff
258073
	/* destination symlink: dstdir/libfoo.so */
19022e
	if (slbt_snprintf(dlnkname,sizeof(dlnkname),
19022e
			"%s/%s",dstdir,base) < 0)
8a1cbd
		return SLBT_BUFFER_ERROR(dctx);
258073
258073
	/* create symlink: libfoo.so --> libfoo.so.x.y.z */
258073
	if (slbt_create_symlink(
258073
			dctx,ectx,
258073
			target,dlnkname,
cc0827
			SLBT_SYMLINK_DEFAULT))
8a1cbd
		return SLBT_NESTED_ERROR(dctx);
258073
112a2b
	if (frelease)
112a2b
		return 0;
112a2b
ca36f5
	/* libfoo.so.x --> libfoo.so.x.y.z */
258073
	strcpy(slnkname,target);
258073
ca36f5
	if ((suffix = strrchr(slnkname,'.')))
ca36f5
		*suffix++ = 0;
258073
	else
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
258073
258073
	if ((dot = strrchr(slnkname,'.')))
ca36f5
		*dot++ = 0;
258073
	else
Kylie McClain 7ce25c
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
258073
ca36f5
	if ((*dot < '0') || (*dot > '9'))
ca36f5
		return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
ca36f5
ca36f5
	/* libfoo.x.y.z.so? */
ca36f5
	if ((suffix[0] < '0') || (suffix[0] > '9')) {
ca36f5
		if ((dot = strrchr(slnkname,'.')))
ca36f5
			dot++;
ca36f5
		else
ca36f5
			return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
ca36f5
ca36f5
		if ((*dot < '0') || (*dot > '9'))
ca36f5
			return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
ca36f5
ca36f5
		for (; *suffix; )
ca36f5
			*dot++ = *suffix++;
ca36f5
ca36f5
		*dot++ = 0;
ca36f5
	}
ca36f5
258073
	/* destination symlink: dstdir/libfoo.so.x */
19022e
	if (slbt_snprintf(dlnkname,sizeof(dlnkname),
19022e
			"%s/%s",dstdir,slnkname) < 0)
8a1cbd
		return SLBT_BUFFER_ERROR(dctx);
258073
1c05ca
	if (fpe) {
1c05ca
		/* copy: .libs/libfoo.so.x.y.z --> libfoo.so.x */
8dc63d
		if (slbt_util_copy_file(
fc7ad9
				ectx,
1c05ca
				srcfile,
1c05ca
				dlnkname))
8a1cbd
			return SLBT_NESTED_ERROR(dctx);
c6e3d1
c6e3d1
		/* import libraries */
c6e3d1
		if (slbt_exec_install_import_libraries(
c6e3d1
				dctx,ectx,
c6e3d1
				srcfile,
c6e3d1
				dstdir))
8a1cbd
			return SLBT_NESTED_ERROR(dctx);
1c05ca
	} else {
1c05ca
		/* create symlink: libfoo.so.x --> libfoo.so.x.y.z */
1c05ca
		if (slbt_create_symlink(
1c05ca
				dctx,ectx,
1c05ca
				target,dlnkname,
cc0827
				SLBT_SYMLINK_DEFAULT))
8a1cbd
			return SLBT_NESTED_ERROR(dctx);
1c05ca
	}
258073
258073
	return 0;
258073
}
258073
2e30eb
int slbt_exec_install(const struct slbt_driver_ctx * dctx)
258073
{
a82cc2
	int				fdout;
258073
	char **				argv;
668906
	char **				iargv;
258073
	char **				src;
258073
	char **				dst;
430840
	char *				slash;
430840
	char *				optsh;
430840
	char *				script;
15903b
	char *				shtool;
2e30eb
	struct slbt_exec_ctx *		ectx;
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;
d58d2f
	const struct argv_option *	optv[SLBT_OPTV_ELEMENTS];
258073
	char				dstdir[PATH_MAX];
258073
c4a389
	/* dry run */
c4a389
	if (dctx->cctx->drvflags & SLBT_DRIVER_DRY_RUN)
c4a389
		return 0;
c4a389
258073
	/* context */
2e30eb
	if (slbt_ectx_get_exec_ctx(dctx,&ectx) < 0)
2e30eb
		return SLBT_NESTED_ERROR(dctx);
258073
258073
	/* initial state, install mode skin */
f3d47a
	slbt_ectx_reset_arguments(ectx);
258073
	slbt_disable_placeholders(ectx);
668906
	iargv = ectx->cargv;
a82cc2
	fdout = slbt_driver_fdout(dctx);
430840
	optsh = 0;
430840
	script = 0;
668906
668906
	/* work around non-conforming uses of --mode=install */
430840
	if (iargv[1] && (slash = strrchr(iargv[1],'/'))) {
430840
		if (!strcmp(++slash,"install-sh")) {
430840
			optsh  = *iargv++;
430840
			script = *iargv;
430840
		}
15903b
	} else {
15903b
		slash  = strrchr(iargv[0],'/');
15903b
		shtool = slash ? ++slash : iargv[0];
15903b
		shtool = strcmp(shtool,"shtool") ? 0 : shtool;
15903b
15903b
		if (shtool && iargv[1] && !strcmp(iargv[1],"install")) {
15903b
			iargv++;
15903b
		} else if (shtool) {
15903b
			return slbt_install_usage(
15903b
				fdout,
15903b
				dctx->program,
611918
				0,optv,0,
611918
				dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER);
15903b
		}
430840
	}
258073
258073
	/* missing arguments? */
a05389
	slbt_optv_init(slbt_install_options,optv);
d58d2f
668906
	if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE))
a82cc2
		return slbt_install_usage(
a82cc2
			fdout,
a82cc2
			dctx->program,
611918
			0,optv,0,
611918
			dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER);
258073
258073
	/* <install> argv meta */
a05389
	if (!(meta = slbt_argv_get(
a82cc2
			iargv,optv,
258073
			dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS
258073
				? ARGV_VERBOSITY_ERRORS
93f9e4
				: ARGV_VERBOSITY_NONE,
a82cc2
			fdout)))
8a1cbd
		return slbt_exec_install_fail(
2e30eb
			ectx,meta,
Kylie McClain 7ce25c
			SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FAIL));
258073
258073
	/* dest, alternate argument vector options */
258073
	argv = ectx->altv;
258073
	copy = meta->entries;
258073
	dest = 0;
258073
	last = 0;
258073
430840
	if (optsh)
430840
		*argv++ = script;
430840
668906
	*argv++ = iargv[0];
258073
258073
	for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
258073
		if (entry->fopt) {
258073
			switch (entry->tag) {
04b5c8
				case TAG_INSTALL_SYSROOT:
04b5c8
					break;
04b5c8
258073
				case TAG_INSTALL_COPY:
258073
					*argv++ = "-c";
258073
					copy = entry;
258073
					break;
258073
f8ac22
				case TAG_INSTALL_FORCE:
f8ac22
					*argv++ = "-f";
f8ac22
					break;
f8ac22
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
04b5c8
			if (entry->tag == TAG_INSTALL_SYSROOT) {
04b5c8
				(void)0;
04b5c8
04b5c8
			} else if (entry->fval) {
258073
				*argv++ = (char *)entry->arg;
04b5c8
			}
258073
		} else
258073
			last = entry;
258073
	}
258073
258073
	/* install */
258073
	if (copy) {
258073
		/* using alternate argument vector */
430840
		if (optsh)
430840
			ectx->altv[0] = optsh;
430840
258073
		ectx->argv    = ectx->altv;
258073
		ectx->program = ectx->altv[0];
258073
258073
		/* marks */
258073
		src = argv++;
258073
		dst = argv++;
258073
258073
		/* dstdir */
8a1cbd
		if (slbt_exec_install_init_dstdir(dctx,dest,last,dstdir))
8a1cbd
			return slbt_exec_install_fail(
2e30eb
				ectx,meta,
8a1cbd
				SLBT_NESTED_ERROR(dctx));
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))
8a1cbd
					return slbt_exec_install_fail(
2e30eb
						ectx,meta,
8a1cbd
						SLBT_NESTED_ERROR(dctx));
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))
33a569
			if (slbt_output_install(ectx))
8a1cbd
				return SLBT_NESTED_ERROR(dctx);
258073
3056ff
		if ((slbt_spawn(ectx,true) < 0) && (ectx->pid < 0)) {
8a1cbd
			return slbt_exec_install_fail(
2e30eb
				ectx,meta,
8a1cbd
				SLBT_SPAWN_ERROR(dctx));
3056ff
3056ff
		} else if (ectx->exitcode) {
3056ff
			return slbt_exec_install_fail(
2e30eb
				ectx,meta,
3056ff
				SLBT_CUSTOM_ERROR(
3056ff
					dctx,
3056ff
					SLBT_ERR_INSTALL_ERROR));
3056ff
		}
258073
	}
258073
a05389
	slbt_argv_free(meta);
2e30eb
	slbt_ectx_free_exec_ctx(ectx);
258073
258073
	return 0;
258073
}