From 7226a116a0bbc1f304d8160615525cb0aeb46096 Mon Sep 17 00:00:00 2001 From: Raito Bezarius Date: Wed, 26 Mar 2025 01:04:12 +0100 Subject: [PATCH] libutil: guess or invent a path from file descriptors This is useful for certain error recovery paths (no pun intended) that does not thread through the original path name. Change-Id: I2d800740cb4f9912e64c923120d3f977c58ccb7e Signed-off-by: Raito Bezarius --- src/libutil/file-descriptor.cc | 26 +++++++++++++++++++ .../include/nix/util/file-descriptor.hh | 17 ++++++++++++ src/libutil/meson.build | 2 ++ 3 files changed, 45 insertions(+) diff --git a/src/libutil/file-descriptor.cc b/src/libutil/file-descriptor.cc index 9e0827442..9193a30bb 100644 --- a/src/libutil/file-descriptor.cc +++ b/src/libutil/file-descriptor.cc @@ -1,5 +1,8 @@ #include "nix/util/serialise.hh" #include "nix/util/util.hh" +#include "nix/util/file-system.hh" + +#include "util-config-private.hh" #include #include @@ -74,6 +77,29 @@ Descriptor AutoCloseFD::get() const return fd; } +std::string guessOrInventPathFromFD(Descriptor fd) + { + assert(fd >= 0); + /* On Linux, there's no F_GETPATH available. + * But we can read /proc/ */ + #if defined(__linux__) + try { + return readLink(fmt("/proc/self/fd/%1%", fd)); + } catch (...) { + } + #elif defined (HAVE_F_GETPATH) && HAVE_F_GETPATH + std::string fdName(PATH_MAX, '\0'); + if (fcntl(fd, F_GETPATH, fdName.data()) != -1) { + fdName.resize(strlen(fdName.c_str())); + return fdName; + } + #else + #error "No implementation for retrieving file descriptors path." + #endif + + return fmt("", fd); + } + void AutoCloseFD::close() { diff --git a/src/libutil/include/nix/util/file-descriptor.hh b/src/libutil/include/nix/util/file-descriptor.hh index e2bcce2a2..35b359fb5 100644 --- a/src/libutil/include/nix/util/file-descriptor.hh +++ b/src/libutil/include/nix/util/file-descriptor.hh @@ -106,6 +106,14 @@ void drainFD( #endif ); + /* + * Will attempt to guess *A* path associated that might lead to the same file as used by this + * file descriptor. + * + * The returned string should NEVER be used as a valid path. + */ + std::string guessOrInventPathFromFD(Descriptor fd); + /** * Get [Standard Input](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin)) */ @@ -160,6 +168,15 @@ public: AutoCloseFD& operator =(const AutoCloseFD & fd) = delete; AutoCloseFD& operator =(AutoCloseFD&& fd); Descriptor get() const; + + /** + * Will attempt to guess *A* path associated that might lead to the same file as used by this + * file descriptor. + * + * The returned string should NEVER be used as a valid path. + */ + std::string guessOrInventPath() const { return guessOrInventPathFromFD(fd); } + explicit operator bool() const; Descriptor release(); void close(); diff --git a/src/libutil/meson.build b/src/libutil/meson.build index f5ad2b1f6..2203e2294 100644 --- a/src/libutil/meson.build +++ b/src/libutil/meson.build @@ -37,6 +37,8 @@ foreach funcspec : check_funcs configdata.set(define_name, define_value, description: funcspec[1]) endforeach +configdata.set('HAVE_F_GETPATH', cxx.has_header_symbol('fcntl.h', 'F_GETPATH').to_int()) + subdir('nix-meson-build-support/libatomic') if host_machine.system() == 'windows'