Home | History | Annotate | Download | only in libpp
      1 /**
      2  * @file locate_images.cpp
      3  * Command-line helper
      4  *
      5  * @remark Copyright 2002 OProfile authors
      6  * @remark Read the file COPYING
      7  *
      8  * @author Philippe Elie
      9  * @author John Levon
     10  */
     11 
     12 #include "file_manip.h"
     13 #include "locate_images.h"
     14 #include "string_manip.h"
     15 
     16 #include <cerrno>
     17 #include <iostream>
     18 #include <sstream>
     19 #include <cstdlib>
     20 
     21 using namespace std;
     22 
     23 
     24 int extra_images::suid;
     25 
     26 extra_images::extra_images()
     27 	:
     28 	uid(++suid)
     29 {
     30 }
     31 
     32 
     33 void extra_images::populate(vector<string> const & paths,
     34 			    string const & prefix_path)
     35 {
     36 	vector<string>::const_iterator cit = paths.begin();
     37 	vector<string>::const_iterator end = paths.end();
     38 	for (; cit != end; ++cit) {
     39 		string const path = op_realpath(prefix_path + *cit);
     40 		list<string> file_list;
     41 		create_file_list(file_list, path, "*", true);
     42 		list<string>::const_iterator lit = file_list.begin();
     43 		list<string>::const_iterator lend = file_list.end();
     44 		for (; lit != lend; ++lit) {
     45 			value_type v(op_basename(*lit), op_dirname(*lit));
     46 			images.insert(v);
     47 		}
     48 	}
     49 }
     50 
     51 
     52 void extra_images::populate(vector<string> const & paths,
     53 			    string const & archive_path_,
     54 			    string const & root_path_)
     55 {
     56 	archive_path = archive_path_;
     57 	if (!archive_path.empty())
     58 		archive_path = op_realpath(archive_path);
     59 
     60 	root_path = op_realpath(root_path_);
     61 	if (!root_path.empty())
     62 		root_path = op_realpath(root_path);
     63 
     64 	if (root_path.empty() && archive_path.empty())
     65 		populate(paths, "");
     66 	if (!archive_path.empty())
     67 		populate(paths, archive_path);
     68 	if (!root_path.empty() && root_path != archive_path)
     69 		populate(paths, root_path);
     70 }
     71 
     72 
     73 vector<string> const extra_images::find(string const & name) const
     74 {
     75 	extra_images::matcher match(name);
     76 	return find(match);
     77 }
     78 
     79 
     80 vector<string> const
     81 extra_images::find(extra_images::matcher const & match) const
     82 {
     83 	vector<string> matches;
     84 
     85 	const_iterator cit = images.begin();
     86 	const_iterator end = images.end();
     87 
     88 	for (; cit != end; ++cit) {
     89 		if (match(cit->first))
     90 			matches.push_back(cit->second + '/' + cit->first);
     91 	}
     92 
     93 	return matches;
     94 }
     95 
     96 
     97 namespace {
     98 
     99 /**
    100  * Function object for matching a module filename, which
    101  * has its own special mangling rules in 2.6 kernels.
    102  */
    103 struct module_matcher : public extra_images::matcher {
    104 public:
    105 	explicit module_matcher(string const & s)
    106 		: extra_images::matcher(s) {}
    107 
    108 	virtual bool operator()(string const & candidate) const {
    109 		if (candidate.length() != value.length())
    110 			return false;
    111 
    112 		for (string::size_type i = 0 ; i < value.length() ; ++i) {
    113 			if (value[i] == candidate[i])
    114 				continue;
    115 			if (value[i] == '_' &&
    116 				(candidate[i] == ',' || candidate[i] == '-'))
    117 				continue;
    118 			return false;
    119 		}
    120 
    121 		return true;
    122 	}
    123 };
    124 
    125 } // anon namespace
    126 
    127 string const extra_images::locate_image(string const & image_name,
    128 			   image_error & error, bool fixup) const
    129 {
    130 	// Skip search since root_path can be non empty and we want
    131 	// to lookup only in root_path in this case.
    132 	if (!archive_path.empty()) {
    133 		string image = op_realpath(archive_path + image_name);
    134 		if (op_file_readable(image)) {
    135 			error = image_ok;
    136 			return fixup ? image : image_name;
    137 		}
    138 
    139 		if (errno == EACCES) {
    140 			error = image_unreadable;
    141 			return image_name;
    142 		}
    143 	}
    144 
    145 	// We catch a case where root_path.empty() since we skipped a
    146 	// search in "/" above when archive_path is empty. The case where
    147 	// root_path.empty() && archive_path.empty() is the normal one, none
    148 	// of --root or archive: as been given on command line.
    149 	if (!root_path.empty() || archive_path.empty()) {
    150 		string image = op_realpath(root_path + image_name);
    151 		if (op_file_readable(image)) {
    152 			error = image_ok;
    153 			return fixup ? image : image_name;
    154 		}
    155 	}
    156 
    157 	error = image_not_found;
    158 	return image_name;
    159 }
    160 
    161 string const extra_images::find_image_path(string const & image_name,
    162 	image_error & error, bool fixup) const
    163 {
    164 	error = image_ok;
    165 
    166 	string const image = locate_image(image_name, error, fixup);
    167 	if (error != image_not_found)
    168 		return image;
    169 
    170 	string const base = op_basename(image);
    171 
    172 	vector<string> result = find(base);
    173 
    174 	// not found, try a module search
    175 	if (result.empty())
    176 		result = find(module_matcher(base + ".ko"));
    177 
    178 	if (result.empty()) {
    179 		error = image_not_found;
    180 		return image_name;
    181 	}
    182 
    183 	if (result.size() == 1) {
    184 		error = image_ok;
    185 		return fixup ? result[0] : image_name;
    186 	}
    187 
    188 #ifdef ANDROID
    189 	// On Android, we often have both stripped and unstripped versions of the same
    190 	// library in the image path.  Choose the first one found instead of issuing a
    191 	// multiple match error.
    192 	error = image_ok;
    193 	return fixup ? result[0] : image_name;
    194 #else
    195 	// We can't get multiple result except if only one result is prefixed
    196 	// by archive_path or by root_path.
    197 	size_t count = 0;
    198 	size_t index = 0;
    199 	for (size_t i = 0; i < result.size() && count < 2; ++i) {
    200 		if (is_prefix(result[i], archive_path)) {
    201 			index = i;
    202 			++count;
    203 		}
    204 	}
    205 
    206 	if (count == 0) {
    207 		for (size_t i = 0; i < result.size() && count < 2; ++i) {
    208 			if (is_prefix(result[i], root_path)) {
    209 				index = i;
    210 				++count;
    211 			}
    212 		}
    213 	}
    214 
    215 	if (count == 1) {
    216 		error = image_ok;
    217 		return fixup ? result[index] : image_name;
    218 	}
    219 
    220 	error = image_multiple_match;
    221 	return image_name;
    222 #endif
    223 }
    224 
    225 
    226 string extra_images::strip_path_prefix(string const & image) const
    227 {
    228 	if (archive_path.length() && is_prefix(image, archive_path))
    229 		return image.substr(archive_path.size());
    230 	if (root_path.length() && is_prefix(image, root_path))
    231 		return image.substr(root_path.size());
    232 	return image;
    233 }
    234