BUG: Update both RPATH and RUNPATH entries
During installation the RPATH and RUNPATH entries of ELF binaries are edited to match the user specification. Usually either one entry is present or both entries refer to the same string literal. In the case that they are both present and refer to separate string literals we need to update both. I have never seen this case in practice, but we should do this just in case.
This commit is contained in:
parent
2a85f8289f
commit
485c3faea7
@ -2329,6 +2329,16 @@ std::string::size_type cmSystemToolsFindRPath(std::string const& have,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CMAKE_USE_ELF_PARSER)
|
||||
struct cmSystemToolsRPathInfo
|
||||
{
|
||||
unsigned long Position;
|
||||
unsigned long Size;
|
||||
std::string Name;
|
||||
std::string Value;
|
||||
};
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool cmSystemTools::ChangeRPath(std::string const& file,
|
||||
std::string const& oldRPath,
|
||||
@ -2341,54 +2351,31 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
|
||||
{
|
||||
*changed = false;
|
||||
}
|
||||
unsigned long rpathPosition = 0;
|
||||
unsigned long rpathSize = 0;
|
||||
std::string rpathPrefix;
|
||||
std::string rpathSuffix;
|
||||
int rp_count = 0;
|
||||
cmSystemToolsRPathInfo rp[2];
|
||||
{
|
||||
// Parse the ELF binary.
|
||||
cmELF elf(file.c_str());
|
||||
|
||||
// Get the RPATH or RUNPATH entry from it.
|
||||
cmELF::StringEntry const* se = elf.GetRPath();
|
||||
if(!se)
|
||||
// Get the RPATH and RUNPATH entries from it.
|
||||
int se_count = 0;
|
||||
cmELF::StringEntry const* se[2] = {0, 0};
|
||||
const char* se_name[2] = {0, 0};
|
||||
if(cmELF::StringEntry const* se_rpath = elf.GetRPath())
|
||||
{
|
||||
se = elf.GetRunPath();
|
||||
se[se_count] = se_rpath;
|
||||
se_name[se_count] = "RPATH";
|
||||
++se_count;
|
||||
}
|
||||
|
||||
if(se)
|
||||
if(cmELF::StringEntry const* se_runpath = elf.GetRunPath())
|
||||
{
|
||||
// Make sure the current rpath contains the old rpath.
|
||||
std::string::size_type pos = cmSystemToolsFindRPath(se->Value, oldRPath);
|
||||
if(pos == std::string::npos)
|
||||
se[se_count] = se_runpath;
|
||||
se_name[se_count] = "RUNPATH";
|
||||
++se_count;
|
||||
}
|
||||
if(se_count == 0)
|
||||
{
|
||||
// If it contains the new rpath instead then it is okay.
|
||||
if(cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(emsg)
|
||||
{
|
||||
cmOStringStream e;
|
||||
e << "The current RPATH is:\n"
|
||||
<< " " << se->Value << "\n"
|
||||
<< "which does not contain:\n"
|
||||
<< " " << oldRPath << "\n"
|
||||
<< "as was expected.";
|
||||
*emsg = e.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store information about the entry.
|
||||
rpathPosition = se->Position;
|
||||
rpathSize = se->Size;
|
||||
|
||||
// Store the part of the path we must preserve.
|
||||
rpathPrefix = se->Value.substr(0, pos);
|
||||
rpathSuffix = se->Value.substr(pos+oldRPath.length(), oldRPath.npos);
|
||||
}
|
||||
else if(newRPath.empty())
|
||||
if(newRPath.empty())
|
||||
{
|
||||
// The new rpath is empty and there is no rpath anyway so it is
|
||||
// okay.
|
||||
@ -2398,29 +2385,82 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
|
||||
{
|
||||
if(emsg)
|
||||
{
|
||||
*emsg = "No valid ELF RPATH entry exists in the file; ";
|
||||
*emsg = "No valid ELF RPATH or RUNPATH entry exists in the file; ";
|
||||
*emsg += elf.GetErrorMessage();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Compute the full new rpath.
|
||||
std::string rpath = rpathPrefix;
|
||||
rpath += newRPath;
|
||||
rpath += rpathSuffix;
|
||||
|
||||
// Make sure there is enough room to store the new rpath and at
|
||||
// least one null terminator.
|
||||
if(rpathSize < rpath.length()+1)
|
||||
for(int i=0; i < se_count; ++i)
|
||||
{
|
||||
// If both RPATH and RUNPATH refer to the same string literal it
|
||||
// needs to be changed only once.
|
||||
if(rp_count && rp[0].Position == se[i]->Position)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure the current rpath contains the old rpath.
|
||||
std::string::size_type pos =
|
||||
cmSystemToolsFindRPath(se[i]->Value, oldRPath);
|
||||
if(pos == std::string::npos)
|
||||
{
|
||||
// If it contains the new rpath instead then it is okay.
|
||||
if(cmSystemToolsFindRPath(se[i]->Value, newRPath) != std::string::npos)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(emsg)
|
||||
{
|
||||
*emsg = "The replacement RPATH is too long.";
|
||||
cmOStringStream e;
|
||||
e << "The current " << se_name[i] << " is:\n"
|
||||
<< " " << se[i]->Value << "\n"
|
||||
<< "which does not contain:\n"
|
||||
<< " " << oldRPath << "\n"
|
||||
<< "as was expected.";
|
||||
*emsg = e.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open the file for update and seek to the RPATH position.
|
||||
// Store information about the entry in the file.
|
||||
rp[rp_count].Position = se[i]->Position;
|
||||
rp[rp_count].Size = se[i]->Size;
|
||||
rp[rp_count].Name = se_name[i];
|
||||
|
||||
// Construct the new value which preserves the part of the path
|
||||
// not being changed.
|
||||
rp[rp_count].Value = se[i]->Value.substr(0, pos);
|
||||
rp[rp_count].Value += newRPath;
|
||||
rp[rp_count].Value += se[i]->Value.substr(pos+oldRPath.length(),
|
||||
oldRPath.npos);
|
||||
|
||||
// Make sure there is enough room to store the new rpath and at
|
||||
// least one null terminator.
|
||||
if(rp[rp_count].Size < rp[rp_count].Value.length()+1)
|
||||
{
|
||||
if(emsg)
|
||||
{
|
||||
*emsg = "The replacement path is too long for the ";
|
||||
*emsg += se_name[i];
|
||||
*emsg += " entry.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// This entry is ready for update.
|
||||
++rp_count;
|
||||
}
|
||||
}
|
||||
|
||||
// If no runtime path needs to be changed, we are done.
|
||||
if(rp_count == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Open the file for update.
|
||||
std::ofstream f(file.c_str(),
|
||||
std::ios::in | std::ios::out | std::ios::binary);
|
||||
if(!f)
|
||||
@ -2431,40 +2471,49 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(!f.seekp(rpathPosition))
|
||||
|
||||
// Store the new RPATH and RUNPATH strings.
|
||||
for(int i=0; i < rp_count; ++i)
|
||||
{
|
||||
// Seek to the RPATH position.
|
||||
if(!f.seekp(rp[i].Position))
|
||||
{
|
||||
if(emsg)
|
||||
{
|
||||
*emsg = "Error seeking to RPATH position.";
|
||||
*emsg = "Error seeking to ";
|
||||
*emsg += rp[i].Name;
|
||||
*emsg += " position.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the new rpath. Follow it with enough null terminators to
|
||||
// fill the string table entry.
|
||||
f << rpath;
|
||||
for(unsigned long i=rpath.length(); i < rpathSize; ++i)
|
||||
f << rp[i].Value;
|
||||
for(unsigned long j=rp[i].Value.length(); j < rp[i].Size; ++j)
|
||||
{
|
||||
f << '\0';
|
||||
}
|
||||
|
||||
// Make sure everything was okay.
|
||||
if(f)
|
||||
// Make sure it wrote correctly.
|
||||
if(!f)
|
||||
{
|
||||
if(emsg)
|
||||
{
|
||||
*emsg = "Error writing the new ";
|
||||
*emsg += rp[i].Name;
|
||||
*emsg += " string to the file.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything was updated successfully.
|
||||
if(changed)
|
||||
{
|
||||
*changed = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(emsg)
|
||||
{
|
||||
*emsg = "Error writing the new rpath to the file.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
(void)file;
|
||||
(void)oldRPath;
|
||||
|
Loading…
x
Reference in New Issue
Block a user