aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Kummerlaender2015-10-10 21:42:30 +0200
committerAdrian Kummerlaender2015-10-10 21:42:30 +0200
commit5c7c4edfe45be83211d5c6217824dd4b9ec562d2 (patch)
tree25c0eb12c8cfd1d52e535ba6997d5cdf75c0fc26
downloadchange-5c7c4edfe45be83211d5c6217824dd4b9ec562d2.tar
change-5c7c4edfe45be83211d5c6217824dd4b9ec562d2.tar.gz
change-5c7c4edfe45be83211d5c6217824dd4b9ec562d2.tar.bz2
change-5c7c4edfe45be83211d5c6217824dd4b9ec562d2.tar.lz
change-5c7c4edfe45be83211d5c6217824dd4b9ec562d2.tar.xz
change-5c7c4edfe45be83211d5c6217824dd4b9ec562d2.tar.zst
change-5c7c4edfe45be83211d5c6217824dd4b9ec562d2.zip
Implement basic `read` and `write` interposition
The goal is to implement a shared library to be loaded using `LD_PRELOAD` that tracks all file changes performed by a process. This information is required to enable general purpose change logging inside a shell session. i.e. I want to be able to display diffs and before- / after-hashes of all changes performed by every single command without requiring every changed file to be known prior to execution.
-rw-r--r--change_log.cc76
1 files changed, 76 insertions, 0 deletions
diff --git a/change_log.cc b/change_log.cc
new file mode 100644
index 0000000..d4c3dc4
--- /dev/null
+++ b/change_log.cc
@@ -0,0 +1,76 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <unistd.h>
+#include <dlfcn.h>
+#include <sys/stat.h>
+
+#include <cstring>
+#include <iostream>
+#include <functional>
+
+template <class Result, typename... Arguments>
+std::function<Result(Arguments...)> get_real_function(
+ const std::string& symbol_name) {
+
+ Result (*real_function)(Arguments...) = nullptr;
+ const void* symbol_address = dlsym(RTLD_NEXT, symbol_name.c_str());
+
+ std::memcpy(&real_function, &symbol_address, sizeof(symbol_address));
+
+ return std::function<Result(Arguments...)>(real_function);
+}
+
+std::string get_file_name(int fd) {
+ char proc_link[20];
+ char file_name[256];
+
+ snprintf(proc_link, sizeof(proc_link), "/proc/self/fd/%d", fd);
+ const ssize_t name_size = readlink(proc_link, file_name, sizeof(file_name));
+
+ if ( name_size > 0 ) {
+ file_name[name_size] = '\0';
+
+ return std::string(file_name);
+ } else {
+ return std::string();
+ }
+}
+
+bool is_regular_file(int fd) {
+ struct stat fd_stat;
+ fstat(fd, &fd_stat);
+
+ return S_ISREG(fd_stat.st_mode);
+}
+
+ssize_t read(int fd, void *buffer, size_t count) {
+ static auto real_read = get_real_function<ssize_t, int, void*, size_t>("read");
+
+ const ssize_t result = real_read(fd, buffer, count);
+
+ if ( is_regular_file(fd) ) {
+ std::cerr << "read size "
+ << count
+ << " of "
+ << get_file_name(fd)
+ << std::endl;
+ }
+
+ return result;
+}
+
+ssize_t write(int fd, const void* buffer, size_t count) {
+ static auto real_write = get_real_function<ssize_t, int, const void*, size_t>("write");
+
+ if ( is_regular_file(fd) ) {
+ std::cerr << "write size "
+ << count
+ << " to "
+ << get_file_name(fd)
+ << std::endl;
+ }
+
+ return real_write(fd, buffer, count);
+}