summaryrefslogtreecommitdiff
path: root/src/fallback/slbt_archive_import_mri.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fallback/slbt_archive_import_mri.c')
-rw-r--r--src/fallback/slbt_archive_import_mri.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/fallback/slbt_archive_import_mri.c b/src/fallback/slbt_archive_import_mri.c
new file mode 100644
index 0000000..320d6d1
--- /dev/null
+++ b/src/fallback/slbt_archive_import_mri.c
@@ -0,0 +1,190 @@
+/*******************************************************************/
+/* slibtool: a strong libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <limits.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <slibtool/slibtool.h>
+#include "slibtool_driver_impl.h"
+#include "slibtool_spawn_impl.h"
+#include "slibtool_dprintf_impl.h"
+#include "slibtool_symlink_impl.h"
+#include "slibtool_readlink_impl.h"
+#include "slibtool_realpath_impl.h"
+#include "slibtool_snprintf_impl.h"
+#include "slibtool_errinfo_impl.h"
+
+#define PPRIX64 "%"PRIx64
+
+static char * slbt_mri_argument(
+ int fdat,
+ char * arg,
+ char * buf)
+{
+ char * lnk;
+ char * target;
+ char mricwd[PATH_MAX];
+ char dstbuf[PATH_MAX];
+
+ if ((!(strchr(arg,'+'))) && (!(strchr(arg,'-'))))
+ return arg;
+
+ if (arg[0] == '/') {
+ target = arg;
+ } else {
+ if (slbt_realpath(
+ fdat,".",O_DIRECTORY,
+ mricwd,sizeof(mricwd)) < 0)
+ return 0;
+
+ if (slbt_snprintf(dstbuf,sizeof(dstbuf),
+ "%s/%s",mricwd,arg) < 0)
+ return 0;
+
+ target = dstbuf;
+ }
+
+ lnk = 0;
+
+ {
+ struct stat st;
+
+ if (fstatat(fdat,target,&st,0) < 0)
+ return 0;
+
+ sprintf(buf,
+ ".mri.tmplnk"
+ ".dev."PPRIX64
+ ".inode."PPRIX64
+ ".size."PPRIX64
+ ".tmp",
+ st.st_dev,
+ st.st_ino,
+ st.st_size);
+
+ unlinkat(fdat,buf,0);
+
+ if (!(symlinkat(target,fdat,buf)))
+ lnk = buf;
+ }
+
+ return lnk;
+}
+
+static void slbt_util_import_archive_child(
+ char * program,
+ int fd[2])
+{
+ char * argv[3];
+
+ argv[0] = program;
+ argv[1] = "-M";
+ argv[2] = 0;
+
+ close(fd[1]);
+
+ if (dup2(fd[0],0) == 0)
+ execvp(program,argv);
+
+ _exit(EXIT_FAILURE);
+}
+
+int slbt_util_import_archive_mri(
+ struct slbt_exec_ctx * ectx,
+ char * dstarchive,
+ char * srcarchive)
+{
+ int fdcwd;
+ pid_t pid;
+ pid_t rpid;
+ int fd[2];
+ char * dst;
+ char * src;
+ char * fmt;
+ char mridst [96];
+ char mrisrc [96];
+ char program[PATH_MAX];
+
+ const struct slbt_driver_ctx * dctx;
+
+ /* driver context */
+ dctx = (slbt_get_exec_ictx(ectx))->dctx;
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* not needed? */
+ if (slbt_symlink_is_a_placeholder(fdcwd,srcarchive))
+ return 0;
+
+ /* program */
+ if (slbt_snprintf(program,sizeof(program),
+ "%s",dctx->cctx->host.ar) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* fork */
+ if (pipe(fd))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if ((pid = slbt_fork()) < 0) {
+ close(fd[0]);
+ close(fd[1]);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ /* child */
+ if (pid == 0)
+ slbt_util_import_archive_child(
+ program,
+ fd);
+
+ /* parent */
+ close(fd[0]);
+
+ ectx->pid = pid;
+
+ dst = slbt_mri_argument(fdcwd,dstarchive,mridst);
+ src = slbt_mri_argument(fdcwd,srcarchive,mrisrc);
+
+ if (!dst || !src) {
+ close(fd[1]);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ fmt = "OPEN %s\n"
+ "ADDLIB %s\n"
+ "SAVE\n"
+ "END\n";
+
+ if (slbt_dprintf(fd[1],fmt,dst,src) < 0) {
+ close(fd[1]);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ close(fd[1]);
+
+ rpid = waitpid(
+ pid,
+ &ectx->exitcode,
+ 0);
+
+ if (dst == mridst)
+ unlinkat(fdcwd,dst,0);
+
+ if (src == mrisrc)
+ unlinkat(fdcwd,src,0);
+
+ return (rpid == pid) && (ectx->exitcode == 0)
+ ? 0 : SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_ARCHIVE_IMPORT);
+}