/*******************************************************************/ /* slibtool: a skinny 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_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_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 [96]; char mrisrc [96]; char program[PATH_MAX]; /* 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 = 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) { 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); }