• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
extra_images()26 extra_images::extra_images()
27 	:
28 	uid(++suid)
29 {
30 }
31 
32 
populate(vector<string> const & paths,string const & prefix_path)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 
populate(vector<string> const & paths,string const & archive_path_,string const & root_path_)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 
find(string const & name) const73 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
find(extra_images::matcher const & match) const81 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:
module_matcher__anon058c28680111::module_matcher105 	explicit module_matcher(string const & s)
106 		: extra_images::matcher(s) {}
107 
operator ()__anon058c28680111::module_matcher108 	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 
locate_image(string const & image_name,image_error & error,bool fixup) const127 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 
find_image_path(string const & image_name,image_error & error,bool fixup) const161 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 
strip_path_prefix(string const & image) const226 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