-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
181 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,19 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <unistd.h> | ||
|
||
/** | ||
* @brief Reports the name of the library | ||
* | ||
* Please see the note above for considerations when creating shared libraries. | ||
*/ | ||
class [[gnu::visibility("default")]] exported_class { | ||
public: | ||
/** | ||
* @brief Initializes the name field to the name of the project | ||
*/ | ||
exported_class(); | ||
namespace redirect_to_os_log { | ||
|
||
/** | ||
* @brief Returns a non-owning pointer to the string stored in this class | ||
*/ | ||
auto name() const -> char const *; | ||
[[gnu::visibility("default")]] | ||
extern int exit_pipe[2]; | ||
|
||
private: | ||
std::string m_name; | ||
}; | ||
[[gnu::visibility("default")]] | ||
extern ssize_t safe_write(int fd, const void *__nonnull buf, ssize_t count); | ||
|
||
[[gnu::visibility("default")]] | ||
void *__nullable io_loop(void *__nonnull arg); | ||
|
||
[[gnu::visibility("default")]] | ||
void setup_io_redirection(const bool is_injected); | ||
|
||
} // namespace redirect_to_os_log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
add_library(redirect-to-os-log-inject SHARED redirect-to-os-log-inject-lib.cpp) | ||
target_compile_features(redirect-to-os-log-inject PRIVATE cxx_std_20) | ||
set_target_properties(redirect-to-os-log-inject PROPERTIES CXX_EXTENSIONS ON) | ||
target_compile_options(redirect-to-os-log-inject PRIVATE -Wall -Wextra -Wpedantic -Wno-gnu-line-marker) | ||
set_target_properties(redirect-to-os-log-inject PROPERTIES | ||
CXX_STANDARD 23 | ||
CXX_EXTENSIONS ON | ||
) | ||
target_compile_options(redirect-to-os-log-inject PRIVATE -Wall -Wextra -Wpedantic -Wno-nullability-extension -Wno-gnu-line-marker) | ||
target_link_libraries(redirect-to-os-log-inject PRIVATE redirect-to-os-log-lib) |
34 changes: 32 additions & 2 deletions
34
lib/redirect-to-os-log-inject/redirect-to-os-log-inject-lib.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,36 @@ | ||
#include <redirect-to-os-log/redirect-to-os-log.hpp> | ||
|
||
#include <cstdio> | ||
#include <pthread.h> | ||
#include <unistd.h> | ||
|
||
#undef NDEBUG | ||
#include <cassert> | ||
|
||
namespace redirect_to_os_log_inject { | ||
|
||
static pthread_t io_loop_thread; | ||
|
||
[[gnu::constructor]] | ||
void redirect_to_os_log_injector_ctor() { | ||
fprintf(stderr, "redirect_to_os_log_injector_ctor called\n"); | ||
static void redirect_to_os_log_injector_ctor() { | ||
redirect_to_os_log::setup_io_redirection(true); | ||
|
||
// Spawn the I/O loop thread | ||
pthread_create(&io_loop_thread, nullptr, redirect_to_os_log::io_loop, nullptr); | ||
} | ||
|
||
[[gnu::destructor]] | ||
static void redirect_to_os_log_injector_dtor() { | ||
// Signal the I/O loop thread to exit by writing to the pipe | ||
redirect_to_os_log::safe_write(redirect_to_os_log::exit_pipe[1], "x", | ||
1); // The actual value written is irrelevant | ||
|
||
// Wait for the thread to exit | ||
pthread_join(io_loop_thread, nullptr); | ||
|
||
// Close the pipe | ||
assert(!close(redirect_to_os_log::exit_pipe[0])); | ||
assert(!close(redirect_to_os_log::exit_pipe[1])); | ||
} | ||
|
||
} // namespace redirect_to_os_log_inject |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,123 @@ | ||
#include "redirect-to-os-log/redirect-to-os-log.hpp" | ||
|
||
exported_class::exported_class() : m_name{"redirect-to-os-log"} {} | ||
#include <cstdio> | ||
#include <cstdlib> | ||
#include <cstring> | ||
#include <mutex> | ||
#include <os/log.h> | ||
#include <pthread.h> | ||
#include <spawn.h> | ||
#include <sys/event.h> | ||
#include <sys/time.h> | ||
#include <sys/types.h> | ||
#include <sys/wait.h> | ||
#include <unistd.h> | ||
|
||
auto exported_class::name() const -> char const * { | ||
return m_name.c_str(); | ||
#undef NDEBUG | ||
#include <cassert> | ||
|
||
extern "C" const char *const *const environ; | ||
|
||
namespace redirect_to_os_log { | ||
|
||
static int stdout_pipe[2]; | ||
static int stderr_pipe[2]; | ||
int exit_pipe[2]; | ||
static int original_stdout; | ||
static int original_stderr; | ||
|
||
ssize_t safe_write(int fd, const void *__nonnull buf, ssize_t count) { | ||
const auto written = count; | ||
auto buffer = static_cast<const char *>(buf); | ||
assert(count >= 0); | ||
|
||
while (count > 0) { | ||
ssize_t res = write(fd, buffer, static_cast<size_t>(count)); | ||
if (res < 0) { | ||
if (errno == EINTR) { | ||
continue; // Interrupted by a signal, try again | ||
} else { | ||
assert(false && "safe_write failed"); | ||
} | ||
} | ||
buffer += res; | ||
count -= res; | ||
} | ||
return written; | ||
} | ||
|
||
void log_output(int fd, os_log_t logger, bool echo) { | ||
char buffer[1024]; | ||
ssize_t bytes_read; | ||
|
||
while ((bytes_read = read(fd, buffer, sizeof(buffer) - 1)) > 0) { | ||
buffer[bytes_read] = '\0'; | ||
if (echo) { | ||
safe_write(fd == STDOUT_FILENO ? STDOUT_FILENO : STDERR_FILENO, buffer, bytes_read); | ||
} | ||
os_log_with_type(logger, fd == STDOUT_FILENO ? OS_LOG_TYPE_DEFAULT : OS_LOG_TYPE_ERROR, | ||
"%{public}s", buffer); | ||
} | ||
} | ||
|
||
void setup_io_redirection(const bool is_injected) { | ||
// Create pipes for stdout and stderr | ||
assert(!pipe(stdout_pipe)); | ||
assert(!pipe(stderr_pipe)); | ||
if (is_injected) { | ||
assert(!pipe(exit_pipe)); | ||
} | ||
|
||
// Duplicate the original stdout and stderr | ||
original_stdout = dup(STDOUT_FILENO); | ||
assert(original_stdout >= 0); | ||
original_stderr = dup(STDERR_FILENO); | ||
assert(original_stderr >= 0); | ||
|
||
// Redirect stdout and stderr to the write ends of the pipes | ||
assert(dup2(stdout_pipe[1], STDOUT_FILENO) == STDOUT_FILENO); | ||
assert(dup2(stderr_pipe[1], STDERR_FILENO) == STDERR_FILENO); | ||
|
||
// Close the original write ends of the pipes | ||
assert(!close(stdout_pipe[1])); | ||
assert(!close(stderr_pipe[1])); | ||
} | ||
|
||
void *__nullable io_loop(void *__nonnull arg) { | ||
const auto is_injected = *reinterpret_cast<bool *>(arg); | ||
struct kevent kev[3]; | ||
int kq = kqueue(); | ||
assert(kq >= 0); | ||
|
||
// Set up the kevents to monitor the read ends of the pipes | ||
EV_SET(&kev[0], stdout_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL); | ||
EV_SET(&kev[1], stderr_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL); | ||
if (is_injected) { | ||
EV_SET(&kev[2], exit_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL); | ||
} | ||
kevent(kq, kev, 2 + is_injected, NULL, 0, NULL); | ||
|
||
while (true) { | ||
// Wait for events | ||
struct kevent event_list[2]; | ||
int nev = kevent(kq, NULL, 0, event_list, 2, NULL); | ||
for (int i = 0; i < nev; i++) { | ||
int fd = event_list[i].ident; | ||
if (fd == stdout_pipe[0] || fd == stderr_pipe[0]) { | ||
// Data is available to read, echo it to the original stdout or stderr | ||
char buffer[1024]; | ||
ssize_t bytes_read = read(fd, buffer, sizeof(buffer)); | ||
if (bytes_read > 0) { | ||
int output_fd = (fd == stdout_pipe[0]) ? original_stdout : original_stderr; | ||
safe_write(output_fd, buffer, bytes_read); | ||
} | ||
} | ||
} | ||
} | ||
|
||
close(kq); | ||
pthread_exit(nullptr); | ||
return nullptr; | ||
} | ||
|
||
} // namespace redirect_to_os_log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
add_executable(redirect-to-os-log-inject-lib-test redirect-to-os-log-inject-lib-test.cpp) | ||
target_compile_features(redirect-to-os-log-inject-lib-test PRIVATE cxx_std_20) | ||
set_target_properties(redirect-to-os-log-inject-lib-test PROPERTIES CXX_EXTENSIONS ON) | ||
target_compile_options(redirect-to-os-log-inject-lib-test PRIVATE -Wall -Wextra -Wpedantic -Wno-gnu-line-marker) | ||
target_compile_options(redirect-to-os-log-inject-lib-test PRIVATE -Wall -Wextra -Wpedantic -Wno-nullability-extension -Wno-gnu-line-marker) | ||
target_link_libraries(redirect-to-os-log-inject-lib-test PRIVATE test-helper) | ||
|
||
add_test(NAME redirect-to-os-log-inject-lib-test COMMAND redirect-to-os-log-inject-lib-test) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
add_executable(redirect-to-os-log-lib-test redirect-to-os-log-lib-test.cpp) | ||
target_compile_features(redirect-to-os-log-lib-test PRIVATE cxx_std_20) | ||
target_compile_features(redirect-to-os-log-lib-test PRIVATE cxx_std_23) | ||
set_target_properties(redirect-to-os-log-lib-test PROPERTIES CXX_EXTENSIONS ON) | ||
target_compile_options(redirect-to-os-log-lib-test PRIVATE -Wall -Wextra -Wpedantic -Wno-gnu-line-marker) | ||
target_compile_options(redirect-to-os-log-lib-test PRIVATE -Wall -Wextra -Wpedantic -Wno-nullability-extension -Wno-gnu-line-marker) | ||
target_link_libraries(redirect-to-os-log-lib-test PRIVATE redirect-to-os-log-lib) | ||
|
||
add_test(NAME redirect-to-os-log-lib-test COMMAND redirect-to-os-log-lib-test) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
add_executable(redirect-to-os-log redirect-to-os-log.cpp) | ||
target_compile_features(redirect-to-os-log PRIVATE cxx_std_20) | ||
set_target_properties(redirect-to-os-log PROPERTIES CXX_EXTENSIONS ON) | ||
target_compile_options(redirect-to-os-log PRIVATE -Wall -Wextra -Wpedantic -Wno-gnu-line-marker) | ||
target_compile_options(redirect-to-os-log PRIVATE -Wall -Wextra -Wpedantic -Wno-nullability-extension -Wno-gnu-line-marker) | ||
target_link_libraries(redirect-to-os-log PRIVATE redirect-to-os-log-lib) |