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