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__anon9a4e24a80111::module_matcher105 explicit module_matcher(string const & s)
106 : extra_images::matcher(s) {}
107
operator ()__anon9a4e24a80111::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