summaryrefslogtreecommitdiffhomepage
path: root/src/fallback
diff options
context:
space:
mode:
Diffstat (limited to 'src/fallback')
-rw-r--r--src/fallback/slbt_archive_import_mri.c163
1 files changed, 163 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..fb880c2
--- /dev/null
+++ b/src/fallback/slbt_archive_import_mri.c
@@ -0,0 +1,163 @@
+/*******************************************************************/
+/* slibtool: a skinny libtool implementation, written in C */
+/* Copyright (C) 2016--2021 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 <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_errinfo_impl.h"
+
+static char * slbt_mri_argument(
+ int fdat,
+ char * arg,
+ char * buf)
+{
+ int i;
+ 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)))
+ return 0;
+
+ if ((size_t)snprintf(dstbuf,sizeof(dstbuf),"%s/%s",
+ mricwd,arg) >= sizeof(dstbuf))
+ return 0;
+
+ target = dstbuf;
+ }
+
+ for (i=0,lnk=0; i<1024 && !lnk; i++) {
+ if (!(tmpnam(buf)))
+ return 0;
+
+ if (!(symlinkat(target,fdat,buf)))
+ lnk = buf;
+ }
+
+ return lnk;
+}
+
+static void slbt_archive_import_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_archive_import_mri(
+ const struct slbt_driver_ctx * dctx,
+ 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 [L_tmpnam];
+ char mrisrc [L_tmpnam];
+ char program[PATH_MAX];
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* not needed? */
+ if (slbt_symlink_is_a_placeholder(fdcwd,srcarchive))
+ return 0;
+
+ /* program */
+ if ((size_t)snprintf(program,sizeof(program),
+ "%s",
+ dctx->cctx->host.ar)
+ >= sizeof(program))
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* fork */
+ if (pipe(fd))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if ((pid = fork()) < 0) {
+ close(fd[0]);
+ close(fd[1]);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ /* child */
+ if (pid == 0)
+ slbt_archive_import_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)
+ 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);
+}