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