summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan L. Stahlke <dan.stahlke@intel.com>2020-05-29 22:35:56 (GMT)
committerDan L. Stahlke <dan.stahlke@intel.com>2020-06-01 19:12:54 (GMT)
commit71ed4401273f56bde1ad9f09ba74b5bd6892b889 (patch)
treeadf706af8b23d73bd2e3619bc28d74d15ddc0137
parenta4676c66cedb45762acf6696a33722ab65c0ca1e (diff)
downloadpatchelf-71ed4401273f56bde1ad9f09ba74b5bd6892b889.zip
patchelf-71ed4401273f56bde1ad9f09ba74b5bd6892b889.tar.gz
patchelf-71ed4401273f56bde1ad9f09ba74b5bd6892b889.tar.bz2
Added --output flag
-rw-r--r--patchelf.13
-rw-r--r--src/patchelf.cc25
-rw-r--r--tests/Makefile.am3
-rwxr-xr-xtests/output-flag.sh38
4 files changed, 64 insertions, 5 deletions
diff --git a/patchelf.1 b/patchelf.1
index a51f726..8c998ad 100644
--- a/patchelf.1
+++ b/patchelf.1
@@ -83,6 +83,9 @@ option can be given multiple times.
Marks the object that the search for dependencies of this object will ignore any
default library search paths.
+.IP "--output FILE"
+Set the output file name. If not specified, the input will be modified in place.
+
.IP --debug
Prints details of the changes made to the input file.
diff --git a/src/patchelf.cc b/src/patchelf.cc
index f7643d0..d560587 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -46,6 +46,8 @@ static bool debugMode = false;
static bool forceRPath = false;
static std::vector<std::string> fileNames;
+static std::string outputFileName;
+static bool alwaysWrite = false;
static int pageSize = PAGESIZE;
typedef std::shared_ptr<std::vector<unsigned char>> FileContents;
@@ -497,7 +499,9 @@ void ElfFile<ElfFileParamNames>::sortShdrs()
static void writeFile(std::string fileName, FileContents contents)
{
- int fd = open(fileName.c_str(), O_TRUNC | O_WRONLY);
+ debug("writing %s\n", fileName.c_str());
+
+ int fd = open(fileName.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0777);
if (fd == -1)
error("open");
@@ -1567,7 +1571,7 @@ static bool printNeeded = false;
static bool noDefaultLib = false;
template<class ElfFile>
-static void patchElf2(ElfFile && elfFile, std::string fileName)
+static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, std::string fileName)
{
if (printInterpreter)
printf("%s\n", elfFile.getInterpreter().c_str());
@@ -1603,6 +1607,9 @@ static void patchElf2(ElfFile && elfFile, std::string fileName)
if (elfFile.isChanged()){
elfFile.rewriteSections();
writeFile(fileName, elfFile.fileContents);
+ } else if (alwaysWrite) {
+ debug("not modified, but alwaysWrite=true\n");
+ writeFile(fileName, fileContents);
}
}
@@ -1616,11 +1623,12 @@ static void patchElf()
debug("Kernel page size is %u bytes\n", getPageSize());
auto fileContents = readFile(fileName);
+ std::string outputFileName2 = outputFileName.empty() ? fileName : outputFileName;
if (getElfType(fileContents).is32Bit)
- patchElf2(ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed>(fileContents), fileName);
+ patchElf2(ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed>(fileContents), fileContents, outputFileName2);
else
- patchElf2(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed>(fileContents), fileName);
+ patchElf2(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed>(fileContents), fileContents, outputFileName2);
}
}
@@ -1644,6 +1652,7 @@ void showHelp(const std::string & progName)
[--replace-needed LIBRARY NEW_LIBRARY]\n\
[--print-needed]\n\
[--no-default-lib]\n\
+ [--output FILE]\n\
[--debug]\n\
[--version]\n\
FILENAME...\n", progName.c_str());
@@ -1730,6 +1739,11 @@ int mainWrapped(int argc, char * * argv)
neededLibsToReplace[ argv[i+1] ] = argv[i+2];
i += 2;
}
+ else if (arg == "--output") {
+ if (++i == argc) error("missing argument");
+ outputFileName = argv[i];
+ alwaysWrite = true;
+ }
else if (arg == "--debug") {
debugMode = true;
}
@@ -1751,6 +1765,9 @@ int mainWrapped(int argc, char * * argv)
if (fileNames.empty()) error("missing filename");
+ if (!outputFileName.empty() && fileNames.size() != 1)
+ error("--output option only allowed with single input file");
+
patchElf();
return 0;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 32218e8..8ad7f20 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -21,7 +21,8 @@ no_rpath_arch_TESTS = \
src_TESTS = \
plain-fail.sh plain-run.sh shrink-rpath.sh set-interpreter-short.sh \
set-interpreter-long.sh set-rpath.sh no-rpath.sh big-dynstr.sh \
- set-rpath-library.sh soname.sh shrink-rpath-with-allowed-prefixes.sh
+ set-rpath-library.sh soname.sh shrink-rpath-with-allowed-prefixes.sh \
+ output-flag.sh
build_TESTS = \
$(no_rpath_arch_TESTS)
diff --git a/tests/output-flag.sh b/tests/output-flag.sh
new file mode 100755
index 0000000..5da26b5
--- /dev/null
+++ b/tests/output-flag.sh
@@ -0,0 +1,38 @@
+#! /bin/sh -e
+SCRATCH=scratch/$(basename $0 .sh)
+
+rm -rf ${SCRATCH}
+mkdir -p ${SCRATCH}
+mkdir -p ${SCRATCH}/libsA
+mkdir -p ${SCRATCH}/libsB
+
+cp main ${SCRATCH}/
+cp libfoo.so ${SCRATCH}/libsA/
+cp libbar.so ${SCRATCH}/libsB/
+
+oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main)
+if test -z "$oldRPath"; then oldRPath="/oops"; fi
+
+../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main --output ${SCRATCH}/main2
+# make sure it copies even when there is nothing to do (because rpath is already set)
+../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main2 --output ${SCRATCH}/main3
+
+if test "$(uname)" = FreeBSD; then
+ export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB
+fi
+
+exitCode=0
+(cd ${SCRATCH} && ./main2) || exitCode=$?
+
+if test "$exitCode" != 46; then
+ echo "bad exit code!"
+ exit 1
+fi
+
+exitCode=0
+(cd ${SCRATCH} && ./main3) || exitCode=$?
+
+if test "$exitCode" != 46; then
+ echo "bad exit code!"
+ exit 1
+fi