| 27 | using process::Owned; |
| 28 | |
| 29 | Try<hashset<string>> ldd( |
| 30 | const string& path, |
| 31 | const vector<ldcache::Entry>& cache) |
| 32 | { |
| 33 | hashset<string> dependencies; |
| 34 | |
| 35 | // Keep a queue of paths that are candidates to have their |
| 36 | // ELF dependencies scanned. Once we actually scan something, |
| 37 | // we push it into the dependencies set. This lets us avoid |
| 38 | // scanning paths more than once. |
| 39 | vector<string> candidates; |
| 40 | |
| 41 | // The first candidate is the input path. |
| 42 | candidates.push_back(path); |
| 43 | |
| 44 | while (!candidates.empty()) { |
| 45 | // Take the next candidate from the back of the |
| 46 | // queue. There's no special significance to this, other |
| 47 | // than it avoids unnecessary copies that would occur if |
| 48 | // we popped the front. |
| 49 | const string candidate = candidates.back(); |
| 50 | candidates.pop_back(); |
| 51 | |
| 52 | // If we already have this path, don't scan it again. |
| 53 | if (dependencies.contains(candidate)) { |
| 54 | continue; |
| 55 | } |
| 56 | |
| 57 | Try<elf::File*> load = elf::File::load(candidate); |
| 58 | if (load.isError()) { |
| 59 | return Error(load.error()); |
| 60 | } |
| 61 | |
| 62 | Owned<elf::File> elf(load.get()); |
| 63 | |
| 64 | Try<vector<string>> _dependencies = |
| 65 | elf->get_dynamic_strings(elf::DynamicTag::NEEDED); |
| 66 | if (_dependencies.isError()) { |
| 67 | return Error(_dependencies.error()); |
| 68 | } |
| 69 | |
| 70 | // Collect the ELF dependencies of this path into the needed |
| 71 | // list, scanning the ld.so cache to find the actual path of |
| 72 | // each needed library. |
| 73 | foreach (const string& dependency, _dependencies.get()) { |
| 74 | auto entry = std::find_if( |
| 75 | cache.begin(), |
| 76 | cache.end(), |
| 77 | [&dependency](const ldcache::Entry& e) { |
| 78 | return e.name == dependency; |
| 79 | }); |
| 80 | |
| 81 | if (entry == cache.end()) { |
| 82 | return Error("'" + dependency + "' is not in the ld.so cache"); |
| 83 | } |
| 84 | |
| 85 | // If this ELF object has an interpreter (e.g. ld-linux-x86-64.so.2), |
| 86 | // inspect that too. We need both to be able to run an executable program. |