From 83eec5a997cd121158b7adb32a688dc5a63d6c9c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 30 May 2017 15:56:40 +0200 Subject: [PATCH] resolve-system-dependencies: Several fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes error: getting attributes of path ‘Versions/Current/CoreFoundation’: No such file or directory when /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation is a symlink. Also fixes a segfault when encounting a file that is not a MACH binary (such as /dev/null, which is included in __impureHostDeps in Nixpkgs). Possibly fixes #786. --- .../resolve-system-dependencies.cc | 122 ++++++++++-------- 1 file changed, 67 insertions(+), 55 deletions(-) diff --git a/src/resolve-system-dependencies/resolve-system-dependencies.cc b/src/resolve-system-dependencies/resolve-system-dependencies.cc index ae8ca36ba..615042986 100644 --- a/src/resolve-system-dependencies/resolve-system-dependencies.cc +++ b/src/resolve-system-dependencies/resolve-system-dependencies.cc @@ -17,59 +17,75 @@ using namespace nix; static auto cacheDir = Path{}; -Path resolveCacheFile(Path lib) { +Path resolveCacheFile(Path lib) +{ std::replace(lib.begin(), lib.end(), '/', '%'); return cacheDir + "/" + lib; } -std::set readCacheFile(const Path & file) { +std::set readCacheFile(const Path & file) +{ return tokenizeString>(readFile(file), "\n"); } -void writeCacheFile(const Path & file, std::set & deps) { +void writeCacheFile(const Path & file, std::set & deps) +{ std::ofstream fp; fp.open(file); - for (auto & d : deps) { + for (auto & d : deps) fp << d << "\n"; - } fp.close(); } -std::string findDylibName(bool should_swap, ptrdiff_t dylib_command_start) { +std::string findDylibName(bool should_swap, ptrdiff_t dylib_command_start) +{ struct dylib_command *dylc = (struct dylib_command*)dylib_command_start; return std::string((char*)(dylib_command_start + DO_SWAP(should_swap, dylc->dylib.name.offset))); } -std::set runResolver(const Path & filename) { - int fd = open(filename.c_str(), O_RDONLY); - struct stat s; - fstat(fd, &s); - void *obj = mmap(NULL, s.st_size, PROT_READ, MAP_SHARED, fd, 0); +std::set runResolver(const Path & filename) +{ + AutoCloseFD fd = open(filename.c_str(), O_RDONLY); + if (!fd) + throw SysError("opening ‘%s’", filename); + + struct stat st; + if (fstat(fd.get(), &st)) + throw SysError("statting ‘%s’", filename); + + if (st.st_size < sizeof(mach_header_64)) { + printError("file ‘%s’ is too short for a MACH binary", filename); + return {}; + } + + void *obj = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd.get(), 0); + if (!obj) + throw SysError("mmapping ‘%s’", filename); ptrdiff_t mach64_offset = 0; - uint32_t magic = ((struct mach_header_64*)obj)->magic; - if(magic == FAT_CIGAM || magic == FAT_MAGIC) { + uint32_t magic = ((struct mach_header_64*) obj)->magic; + if (magic == FAT_CIGAM || magic == FAT_MAGIC) { bool should_swap = magic == FAT_CIGAM; uint32_t narches = DO_SWAP(should_swap, ((struct fat_header*)obj)->nfat_arch); - for(uint32_t iter = 0; iter < narches; iter++) { + for (uint32_t iter = 0; iter < narches; iter++) { ptrdiff_t header_offset = (ptrdiff_t)obj + sizeof(struct fat_header) * (iter + 1); struct fat_arch* arch = (struct fat_arch*)header_offset; - if(DO_SWAP(should_swap, arch->cputype) == CPU_TYPE_X86_64) { + if (DO_SWAP(should_swap, arch->cputype) == CPU_TYPE_X86_64) { mach64_offset = (ptrdiff_t)DO_SWAP(should_swap, arch->offset); break; } } if (mach64_offset == 0) { printError(format("Could not find any mach64 blobs in file ‘%1%’, continuing...") % filename); - return std::set(); + return {}; } } else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) { mach64_offset = 0; } else { printError(format("Object file has unknown magic number ‘%1%’, skipping it...") % magic); - return std::set(); + return {}; } ptrdiff_t mach_header_offset = (ptrdiff_t)obj + mach64_offset; @@ -94,30 +110,28 @@ std::set runResolver(const Path & filename) { return libs; } -bool isSymlink(const Path & path) { +bool isSymlink(const Path & path) +{ struct stat st; - if(lstat(path.c_str(), &st)) - throw SysError(format("getting attributes of path ‘%1%’") % path); + if (lstat(path.c_str(), &st) == -1) + throw SysError("getting attributes of path ‘%1%’", path); return S_ISLNK(st.st_mode); } -Path resolveSymlink(const Path & path) { - char buf[PATH_MAX]; - ssize_t len = readlink(path.c_str(), buf, sizeof(buf) - 1); - if(len != -1) { - buf[len] = 0; - return Path(buf); - } else { - throw SysError(format("readlink('%1%')") % path); - } +Path resolveSymlink(const Path & path) +{ + auto target = readLink(path); + return hasPrefix(target, "/") + ? target + : dirOf(path) + "/" + target; } -std::set resolveTree(const Path & path, PathSet & deps) { +std::set resolveTree(const Path & path, PathSet & deps) +{ std::set results; - if(deps.find(path) != deps.end()) { - return std::set(); - } + if (deps.count(path)) + return {}; deps.insert(path); for (auto & lib : runResolver(path)) { results.insert(lib); @@ -128,32 +142,33 @@ std::set resolveTree(const Path & path, PathSet & deps) { return results; } -std::set getPath(const Path & path) { - Path cacheFile = resolveCacheFile(path); - if(pathExists(cacheFile)) { - return readCacheFile(cacheFile); - } +std::set getPath(const Path & path) +{ + if (hasPrefix(path, "/dev")) return {}; - std::set deps; - std::set paths; + Path cacheFile = resolveCacheFile(path); + if (pathExists(cacheFile)) + return readCacheFile(cacheFile); + + std::set deps, paths; paths.insert(path); - Path next_path = Path(path); - while(isSymlink(next_path)) { - next_path = resolveSymlink(next_path); - paths.insert(next_path); + Path nextPath(path); + while (isSymlink(nextPath)) { + nextPath = resolveSymlink(nextPath); + paths.insert(nextPath); } - for(auto & t : resolveTree(next_path, deps)) { + for (auto & t : resolveTree(nextPath, deps)) paths.insert(t); - } writeCacheFile(cacheFile, paths); return paths; } -int main(int argc, char ** argv) { +int main(int argc, char ** argv) +{ return handleExceptions(argv[0], [&]() { initNix(); @@ -177,18 +192,15 @@ int main(int argc, char ** argv) { auto drv = store->derivationFromPath(Path(argv[1])); Strings impurePaths = tokenizeString(get(drv.env, "__impureHostDeps")); - std::set all_paths; + std::set allPaths; - for (auto & path : impurePaths) { - for(auto & p : getPath(path)) { - all_paths.insert(p); - } - } + for (auto & path : impurePaths) + for (auto & p : getPath(path)) + allPaths.insert(p); std::cout << "extra-chroot-dirs" << std::endl; - for(auto & path : all_paths) { + for (auto & path : allPaths) std::cout << path << std::endl; - } std::cout << std::endl; }); }