aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Kummerlaender2015-10-18 15:34:14 +0200
committerAdrian Kummerlaender2015-10-18 15:34:14 +0200
commitf057a3e9116539cd96916cfd8fb790cf6a87de79 (patch)
tree6cc27fb1b2c456791e00478e21ffb16218db3b68
parentbc38a776d5b12beb84e7b8d3a852f9515e0b8330 (diff)
downloadchange-f057a3e9116539cd96916cfd8fb790cf6a87de79.tar
change-f057a3e9116539cd96916cfd8fb790cf6a87de79.tar.gz
change-f057a3e9116539cd96916cfd8fb790cf6a87de79.tar.bz2
change-f057a3e9116539cd96916cfd8fb790cf6a87de79.tar.lz
change-f057a3e9116539cd96916cfd8fb790cf6a87de79.tar.xz
change-f057a3e9116539cd96916cfd8fb790cf6a87de79.tar.zst
change-f057a3e9116539cd96916cfd8fb790cf6a87de79.zip
Implement support for sending logs to an arbitrary file
The `CHANGE_LOG_TARGET` environment variable enables passing the path of an arbitrary target file to the preloaded library. This may be used to e.g. print the log to a separate `cat` instance and is necessary for logging change events without altering the output of the wrapped process.
-rw-r--r--change_log.cc59
1 files changed, 53 insertions, 6 deletions
diff --git a/change_log.cc b/change_log.cc
index 03c4343..58ba0db 100644
--- a/change_log.cc
+++ b/change_log.cc
@@ -7,14 +7,51 @@
#include <fcntl.h>
#include <sys/stat.h>
+#include <ext/stdio_filebuf.h>
+
#include <cstring>
#include <iostream>
#include <utility>
#include <functional>
#include <unordered_set>
+#include <memory>
+
+struct FileDescriptorGuard {
+ FileDescriptorGuard(const std::string& path) {
+ this->fd = open(path.c_str(), O_WRONLY | O_APPEND);
+
+ if ( !this->fd ) {
+ this->fd = STDERR_FILENO;
+ }
+ }
+
+ ~FileDescriptorGuard() {
+ close(this->fd);
+ }
+
+ int fd;
+};
+
+class LogGuard {
+ public:
+ LogGuard(const int target_fd):
+ buffer(target_fd, std::ios::out),
+ stream(&this->buffer) { }
+
+ void append(const std::string& msg) {
+ this->stream << msg << std::endl;
+ }
+
+ private:
+ __gnu_cxx::stdio_filebuf<char> buffer;
+ std::ostream stream;
+};
static std::unordered_set<std::string> tracked_files;
+static std::unique_ptr<FileDescriptorGuard> fd_guard;
+static std::unique_ptr<LogGuard> log;
+
template <class Result, typename... Arguments>
std::function<Result(Arguments...)> get_real_function(
const std::string& symbol_name) {
@@ -27,6 +64,16 @@ std::function<Result(Arguments...)> get_real_function(
return std::function<Result(Arguments...)>(real_function);
}
+void init() __attribute__ ((constructor));
+void init() {
+ if ( getenv("CHANGE_LOG_TARGET") != NULL ) {
+ fd_guard = std::make_unique<FileDescriptorGuard>(getenv("CHANGE_LOG_TARGET"));
+ log = std::make_unique<LogGuard>(fd_guard->fd);
+ } else {
+ log = std::make_unique<LogGuard>(STDERR_FILENO);
+ }
+}
+
void exit(int status) {
get_real_function<void, int>("exit")(status);
}
@@ -71,7 +118,7 @@ ssize_t write(int fd, const void* buffer, size_t count) {
if ( !is_tracked_file(file_name) ) {
track_file(file_name);
- std::cerr << "wrote to '" << file_name << "'" << std::endl;
+ log->append("wrote to '" + file_name + "'");
}
}
@@ -81,7 +128,7 @@ ssize_t write(int fd, const void* buffer, size_t count) {
int rename(const char* old_path, const char* new_path) {
static auto real_rename = get_real_function<int, const char*, const char*>("rename");
- std::cerr << "renamed '" << old_path << "' to '" << new_path << "'" << std::endl;
+ log->append("renamed '" + std::string(old_path) + "' to '" + std::string(new_path) + "'");
return real_rename(old_path, new_path);
}
@@ -89,7 +136,7 @@ int rename(const char* old_path, const char* new_path) {
int rmdir(const char* path) {
static auto real_rmdir = get_real_function<int, const char*>("rmdir");
- std::cerr << "removed directory '" << path << "'" << std::endl;
+ log->append("removed directory '" + std::string(path) + "'");
return real_rmdir(path);
}
@@ -97,7 +144,7 @@ int rmdir(const char* path) {
int unlink(const char* path) {
static auto real_unlink = get_real_function<int, const char*>("unlink");
- std::cerr << "removed '" << path << "'" << std::endl;
+ log->append("removed '" + std::string(path) + "'");
return real_unlink(path);
}
@@ -106,9 +153,9 @@ int unlinkat(int dirfd, const char* path, int flags) {
static auto real_unlinkat = get_real_function<int, int, const char*, int>("unlinkat");
if ( dirfd == AT_FDCWD ) {
- std::cerr << "removed '" << path << "'" << std::endl;
+ log->append("removed '" + std::string(path) + "'");
} else {
- std::cerr << "removed '" << get_file_name(dirfd) << path << "'" << std::endl;
+ log->append("removed '" + get_file_name(dirfd) + path + "'");
}
return real_unlinkat(dirfd, path, flags);