Blame src/fallback/slbt_archive_import_mri.c

65cb35
/*******************************************************************/
65cb35
/*  slibtool: a skinny libtool implementation, written in C        */
49181b
/*  Copyright (C) 2016--2024  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>
dd658d
#include <inttypes.h>
dd658d
#include <sys/stat.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"
19022e
#include "slibtool_snprintf_impl.h"
65cb35
#include "slibtool_errinfo_impl.h"
65cb35
dd658d
#define PPRIX64 "%"PRIx64
dd658d
65cb35
static char * slbt_mri_argument(
65cb35
	int	fdat,
65cb35
	char *	arg,
65cb35
	char *	buf)
65cb35
{
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
ee9cbe
	if (arg[0] == '/') {
65cb35
		target = arg;
ee9cbe
	} else {
ee9cbe
		if (slbt_realpath(
ee9cbe
				fdat,".",O_DIRECTORY,
ee9cbe
				mricwd,sizeof(mricwd)) < 0)
65cb35
			return 0;
65cb35
19022e
		if (slbt_snprintf(dstbuf,sizeof(dstbuf),
19022e
				"%s/%s",mricwd,arg) < 0)
65cb35
			return 0;
65cb35
65cb35
		target = dstbuf;
65cb35
	}
65cb35
dd658d
	lnk = 0;
dd658d
dd658d
	{
dd658d
		struct stat st;
dd658d
dd658d
		if (fstatat(fdat,target,&st,0) < 0)
65cb35
			return 0;
65cb35
dd658d
		sprintf(buf,
dd658d
			".mri.tmplnk"
dd658d
			".dev."PPRIX64
dd658d
			".inode."PPRIX64
dd658d
			".size."PPRIX64
dd658d
			".tmp",
dd658d
			st.st_dev,
dd658d
			st.st_ino,
dd658d
			st.st_size);
dd658d
dd658d
		unlinkat(fdat,buf,0);
dd658d
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;
dd658d
	char	mridst [96];
dd658d
	char	mrisrc [96];
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 */
19022e
	if (slbt_snprintf(program,sizeof(program),
19022e
			"%s",dctx->cctx->host.ar) < 0)
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
a8ca7c
	if (!dst || !src) {
a8ca7c
		close(fd[1]);
65cb35
		return SLBT_SYSTEM_ERROR(dctx,0);
a8ca7c
	}
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
}