234 lines
5.3 KiB
C++
234 lines
5.3 KiB
C++
/**
|
|
* @file locate_images.cpp
|
|
* Command-line helper
|
|
*
|
|
* @remark Copyright 2002 OProfile authors
|
|
* @remark Read the file COPYING
|
|
*
|
|
* @author Philippe Elie
|
|
* @author John Levon
|
|
*/
|
|
|
|
#include "file_manip.h"
|
|
#include "locate_images.h"
|
|
#include "string_manip.h"
|
|
|
|
#include <cerrno>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <cstdlib>
|
|
|
|
using namespace std;
|
|
|
|
|
|
int extra_images::suid;
|
|
|
|
extra_images::extra_images()
|
|
:
|
|
uid(++suid)
|
|
{
|
|
}
|
|
|
|
|
|
void extra_images::populate(vector<string> const & paths,
|
|
string const & prefix_path)
|
|
{
|
|
vector<string>::const_iterator cit = paths.begin();
|
|
vector<string>::const_iterator end = paths.end();
|
|
for (; cit != end; ++cit) {
|
|
string const path = op_realpath(prefix_path + *cit);
|
|
list<string> file_list;
|
|
create_file_list(file_list, path, "*", true);
|
|
list<string>::const_iterator lit = file_list.begin();
|
|
list<string>::const_iterator lend = file_list.end();
|
|
for (; lit != lend; ++lit) {
|
|
value_type v(op_basename(*lit), op_dirname(*lit));
|
|
images.insert(v);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void extra_images::populate(vector<string> const & paths,
|
|
string const & archive_path_,
|
|
string const & root_path_)
|
|
{
|
|
archive_path = archive_path_;
|
|
if (!archive_path.empty())
|
|
archive_path = op_realpath(archive_path);
|
|
|
|
root_path = op_realpath(root_path_);
|
|
if (!root_path.empty())
|
|
root_path = op_realpath(root_path);
|
|
|
|
if (root_path.empty() && archive_path.empty())
|
|
populate(paths, "");
|
|
if (!archive_path.empty())
|
|
populate(paths, archive_path);
|
|
if (!root_path.empty() && root_path != archive_path)
|
|
populate(paths, root_path);
|
|
}
|
|
|
|
|
|
vector<string> const extra_images::find(string const & name) const
|
|
{
|
|
extra_images::matcher match(name);
|
|
return find(match);
|
|
}
|
|
|
|
|
|
vector<string> const
|
|
extra_images::find(extra_images::matcher const & match) const
|
|
{
|
|
vector<string> matches;
|
|
|
|
const_iterator cit = images.begin();
|
|
const_iterator end = images.end();
|
|
|
|
for (; cit != end; ++cit) {
|
|
if (match(cit->first))
|
|
matches.push_back(cit->second + '/' + cit->first);
|
|
}
|
|
|
|
return matches;
|
|
}
|
|
|
|
|
|
namespace {
|
|
|
|
/**
|
|
* Function object for matching a module filename, which
|
|
* has its own special mangling rules in 2.6 kernels.
|
|
*/
|
|
struct module_matcher : public extra_images::matcher {
|
|
public:
|
|
explicit module_matcher(string const & s)
|
|
: extra_images::matcher(s) {}
|
|
|
|
virtual bool operator()(string const & candidate) const {
|
|
if (candidate.length() != value.length())
|
|
return false;
|
|
|
|
for (string::size_type i = 0 ; i < value.length() ; ++i) {
|
|
if (value[i] == candidate[i])
|
|
continue;
|
|
if (value[i] == '_' &&
|
|
(candidate[i] == ',' || candidate[i] == '-'))
|
|
continue;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
} // anon namespace
|
|
|
|
string const extra_images::locate_image(string const & image_name,
|
|
image_error & error, bool fixup) const
|
|
{
|
|
// Skip search since root_path can be non empty and we want
|
|
// to lookup only in root_path in this case.
|
|
if (!archive_path.empty()) {
|
|
string image = op_realpath(archive_path + image_name);
|
|
if (op_file_readable(image)) {
|
|
error = image_ok;
|
|
return fixup ? image : image_name;
|
|
}
|
|
|
|
if (errno == EACCES) {
|
|
error = image_unreadable;
|
|
return image_name;
|
|
}
|
|
}
|
|
|
|
// We catch a case where root_path.empty() since we skipped a
|
|
// search in "/" above when archive_path is empty. The case where
|
|
// root_path.empty() && archive_path.empty() is the normal one, none
|
|
// of --root or archive: as been given on command line.
|
|
if (!root_path.empty() || archive_path.empty()) {
|
|
string image = op_realpath(root_path + image_name);
|
|
if (op_file_readable(image)) {
|
|
error = image_ok;
|
|
return fixup ? image : image_name;
|
|
}
|
|
}
|
|
|
|
error = image_not_found;
|
|
return image_name;
|
|
}
|
|
|
|
string const extra_images::find_image_path(string const & image_name,
|
|
image_error & error, bool fixup) const
|
|
{
|
|
error = image_ok;
|
|
|
|
string const image = locate_image(image_name, error, fixup);
|
|
if (error != image_not_found)
|
|
return image;
|
|
|
|
string const base = op_basename(image);
|
|
|
|
vector<string> result = find(base);
|
|
|
|
// not found, try a module search
|
|
if (result.empty())
|
|
result = find(module_matcher(base + ".ko"));
|
|
|
|
if (result.empty()) {
|
|
error = image_not_found;
|
|
return image_name;
|
|
}
|
|
|
|
if (result.size() == 1) {
|
|
error = image_ok;
|
|
return fixup ? result[0] : image_name;
|
|
}
|
|
|
|
#ifdef ANDROID
|
|
// On Android, we often have both stripped and unstripped versions of the same
|
|
// library in the image path. Choose the first one found instead of issuing a
|
|
// multiple match error.
|
|
error = image_ok;
|
|
return fixup ? result[0] : image_name;
|
|
#else
|
|
// We can't get multiple result except if only one result is prefixed
|
|
// by archive_path or by root_path.
|
|
size_t count = 0;
|
|
size_t index = 0;
|
|
for (size_t i = 0; i < result.size() && count < 2; ++i) {
|
|
if (is_prefix(result[i], archive_path)) {
|
|
index = i;
|
|
++count;
|
|
}
|
|
}
|
|
|
|
if (count == 0) {
|
|
for (size_t i = 0; i < result.size() && count < 2; ++i) {
|
|
if (is_prefix(result[i], root_path)) {
|
|
index = i;
|
|
++count;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count == 1) {
|
|
error = image_ok;
|
|
return fixup ? result[index] : image_name;
|
|
}
|
|
|
|
error = image_multiple_match;
|
|
return image_name;
|
|
#endif
|
|
}
|
|
|
|
|
|
string extra_images::strip_path_prefix(string const & image) const
|
|
{
|
|
if (archive_path.length() && is_prefix(image, archive_path))
|
|
return image.substr(archive_path.size());
|
|
if (root_path.length() && is_prefix(image, root_path))
|
|
return image.substr(root_path.size());
|
|
return image;
|
|
}
|