| /** |
| * @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; |
| } |