aboutsummaryrefslogtreecommitdiff
path: root/libpp/locate_images.cpp
blob: 87c25a0a2da24a46f3dbfa75c9ae68e81bcbeb7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/**
 * @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;
}