Blame src/fallback/slbt_archive_import_mri.c

65cb35
/*******************************************************************/
65cb35
/*  slibtool: a skinny libtool implementation, written in C        */
65cb35
/*  Copyright (C) 2016--2021  SysDeer Technologies, LLC            */
65cb35
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
65cb35
/*******************************************************************/
65cb35
65cb35
#include <fcntl.h>
65cb35
#include <stdio.h>
65cb35
#include <limits.h>
65cb35
#include <unistd.h>
65cb35
#include <string.h>
65cb35
#include <stdlib.h>
65cb35
#include <stdbool.h>
65cb35
#include <sys/wait.h>
65cb35
65cb35
#include <slibtool/slibtool.h>
65cb35
#include "slibtool_driver_impl.h"
65cb35
#include "slibtool_spawn_impl.h"
65cb35
#include "slibtool_dprintf_impl.h"
65cb35
#include "slibtool_symlink_impl.h"
65cb35
#include "slibtool_readlink_impl.h"
65cb35
#include "slibtool_errinfo_impl.h"
65cb35
65cb35
static char * slbt_mri_argument(
65cb35
	int	fdat,
65cb35
	char *	arg,
65cb35
	char *	buf)
65cb35
{
65cb35
	int	i;
65cb35
	char *	lnk;
65cb35
	char *	target;
65cb35
	char 	mricwd[PATH_MAX];
65cb35
	char 	dstbuf[PATH_MAX];
65cb35
65cb35
	if ((!(strchr(arg,'+'))) && (!(strchr(arg,'-'))))
65cb35
		return arg;
65cb35
65cb35
	if (arg[0] == '/')
65cb35
		target = arg;
65cb35
	else {
65cb35
		if (slbt_realpath(fdat,".",O_DIRECTORY,mricwd,sizeof(mricwd)))
65cb35
			return 0;
65cb35
65cb35
		if ((size_t)snprintf(dstbuf,sizeof(dstbuf),"%s/%s",
65cb35
				mricwd,arg) >= sizeof(dstbuf))
65cb35
			return 0;
65cb35
65cb35
		target = dstbuf;
65cb35
	}
65cb35
65cb35
	for (i=0,lnk=0; i<1024 && !lnk; i++) {
65cb35
		if (!(tmpnam(buf)))
65cb35
			return 0;
65cb35
65cb35
		if (!(symlinkat(target,fdat,buf)))
65cb35
			lnk = buf;
65cb35
	}
65cb35
65cb35
	return lnk;
65cb35
}
65cb35
65cb35
static void slbt_archive_import_child(
65cb35
	char *	program,
65cb35
	int	fd[2])
65cb35
{
65cb35
	char *	argv[3];
65cb35
65cb35
	argv[0] = program;
65cb35
	argv[1] = "-M";
65cb35
	argv[2] = 0;
65cb35
65cb35
	close(fd[1]);
65cb35
65cb35
	if (dup2(fd[0],0) == 0)
65cb35
		execvp(program,argv);
65cb35
65cb35
	_exit(EXIT_FAILURE);
65cb35
}
65cb35
65cb35
int slbt_archive_import_mri(
65cb35
	const struct slbt_driver_ctx *	dctx,
65cb35
	struct slbt_exec_ctx *		ectx,
65cb35
	char *				dstarchive,
65cb35
	char *				srcarchive)
65cb35
{
65cb35
	int	fdcwd;
65cb35
	pid_t	pid;
65cb35
	pid_t	rpid;
65cb35
	int	fd[2];
65cb35
	char *	dst;
65cb35
	char *	src;
65cb35
	char *	fmt;
65cb35
	char	mridst [L_tmpnam];
65cb35
	char	mrisrc [L_tmpnam];
65cb35
	char	program[PATH_MAX];
65cb35
65cb35
	/* fdcwd */
65cb35
	fdcwd = slbt_driver_fdcwd(dctx);
65cb35
65cb35
	/* not needed? */
65cb35
	if (slbt_symlink_is_a_placeholder(fdcwd,srcarchive))
65cb35
		return 0;
65cb35
65cb35
	/* program */
65cb35
	if ((size_t)snprintf(program,sizeof(program),
65cb35
				"%s",
65cb35
				dctx->cctx->host.ar)
65cb35
			>= sizeof(program))
65cb35
		return SLBT_BUFFER_ERROR(dctx);
65cb35
65cb35
	/* fork */
65cb35
	if (pipe(fd))
65cb35
		return SLBT_SYSTEM_ERROR(dctx,0);
65cb35
65cb35
	if ((pid = fork()) < 0) {
65cb35
		close(fd[0]);
65cb35
		close(fd[1]);
65cb35
		return SLBT_SYSTEM_ERROR(dctx,0);
65cb35
	}
65cb35
65cb35
	/* child */
65cb35
	if (pid == 0)
65cb35
		slbt_archive_import_child(
65cb35
			program,
65cb35
			fd);
65cb35
65cb35
	/* parent */
65cb35
	close(fd[0]);
65cb35
65cb35
	ectx->pid = pid;
65cb35
65cb35
	dst = slbt_mri_argument(fdcwd,dstarchive,mridst);
65cb35
	src = slbt_mri_argument(fdcwd,srcarchive,mrisrc);
65cb35
65cb35
	if (!dst || !src)
65cb35
		return SLBT_SYSTEM_ERROR(dctx,0);
65cb35
65cb35
	fmt = "OPEN %s\n"
65cb35
	      "ADDLIB %s\n"
65cb35
	      "SAVE\n"
65cb35
	      "END\n";
65cb35
65cb35
	if (slbt_dprintf(fd[1],fmt,dst,src) < 0) {
65cb35
		close(fd[1]);
65cb35
		return SLBT_SYSTEM_ERROR(dctx,0);
65cb35
	}
65cb35
65cb35
	close(fd[1]);
65cb35
65cb35
	rpid = waitpid(
65cb35
		pid,
65cb35
		&ectx->exitcode,
65cb35
		0);
65cb35
65cb35
	if (dst == mridst)
65cb35
		unlinkat(fdcwd,dst,0);
65cb35
65cb35
	if (src == mrisrc)
65cb35
		unlinkat(fdcwd,src,0);
65cb35
65cb35
	return (rpid == pid) && (ectx->exitcode == 0)
65cb35
		? 0 : SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_ARCHIVE_IMPORT);
65cb35
}