Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jevinskie committed Mar 29, 2024
1 parent 58408e1 commit 71fd47e
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 39 deletions.
33 changes: 14 additions & 19 deletions include/redirect-to-os-log/redirect-to-os-log.hpp
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
7 changes: 5 additions & 2 deletions lib/redirect-to-os-log-inject/CMakeLists.txt
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 lib/redirect-to-os-log-inject/redirect-to-os-log-inject-lib.cpp
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
4 changes: 3 additions & 1 deletion lib/redirect-to-os-log/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ add_library(redirect-to-os-log-lib STATIC redirect-to-os-log-lib.cpp ${CMAKE_CUR
set_target_properties(
redirect-to-os-log-lib PROPERTIES
PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/../../include/redirect-to-os-log/redirect-to-os-log.hpp
CXX_STANDARD 23
CXX_EXTENSIONS ON
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN YES
VERSION "${PROJECT_VERSION}"
SOVERSION "${PROJECT_VERSION_MAJOR}"
EXPORT_NAME redirect-to-os-log
OUTPUT_NAME redirect-to-os-log
)
target_compile_options(redirect-to-os-log-lib PRIVATE -Wall -Wextra -Wpedantic -Wno-gnu-line-marker)
target_compile_options(redirect-to-os-log-lib PRIVATE -Wall -Wextra -Wpedantic -Wno-nullability-extension -Wno-gnu-line-marker)
target_include_directories(redirect-to-os-log-lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
122 changes: 119 additions & 3 deletions lib/redirect-to-os-log/redirect-to-os-log-lib.cpp
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
2 changes: 1 addition & 1 deletion test/lib/redirect-to-os-log-inject/CMakeLists.txt
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)
4 changes: 2 additions & 2 deletions test/lib/redirect-to-os-log/CMakeLists.txt
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)
6 changes: 1 addition & 5 deletions test/lib/redirect-to-os-log/redirect-to-os-log-lib-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,4 @@

#include "redirect-to-os-log/redirect-to-os-log.hpp"

auto main() -> int {
auto const exported = exported_class{};

return std::string("redirect-to-os-log") == exported.name() ? 0 : 1;
}
auto main() -> int {}
2 changes: 1 addition & 1 deletion test/test-helper/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ set_target_properties(
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN YES
)
target_compile_options(test-helper PRIVATE -Wall -Wextra -Wpedantic -Wno-gnu-line-marker)
target_compile_options(test-helper PRIVATE -Wall -Wextra -Wpedantic -Wno-nullability-extension -Wno-gnu-line-marker)
target_include_directories(test-helper PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
4 changes: 2 additions & 2 deletions test/tool/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
add_executable(redirect-to-os-log-tool-test-subprocess redirect-to-os-log-tool-test-subprocess.cpp)
target_compile_features(redirect-to-os-log-tool-test-subprocess PRIVATE cxx_std_20)
set_target_properties(redirect-to-os-log-tool-test-subprocess PROPERTIES CXX_EXTENSIONS ON)
target_compile_options(redirect-to-os-log-tool-test-subprocess PRIVATE -Wall -Wextra -Wpedantic -Wno-gnu-line-marker)
target_compile_options(redirect-to-os-log-tool-test-subprocess PRIVATE -Wall -Wextra -Wpedantic -Wno-nullability-extension -Wno-gnu-line-marker)
target_link_libraries(redirect-to-os-log-tool-test-subprocess PRIVATE test-helper)
add_dependencies(redirect-to-os-log-tool-test-subprocess redirect-to-os-log)

Expand All @@ -11,7 +11,7 @@ add_test(NAME redirect-to-os-log-tool-test-subprocess COMMAND redirect-to-os-log
add_executable(redirect-to-os-log-tool-test redirect-to-os-log-tool-test.cpp)
target_compile_features(redirect-to-os-log-tool-test PRIVATE cxx_std_20)
set_target_properties(redirect-to-os-log-tool-test PROPERTIES CXX_EXTENSIONS ON)
target_compile_options(redirect-to-os-log-tool-test PRIVATE -Wall -Wextra -Wpedantic -Wno-gnu-line-marker)
target_compile_options(redirect-to-os-log-tool-test PRIVATE -Wall -Wextra -Wpedantic -Wno-nullability-extension -Wno-gnu-line-marker)
add_dependencies(redirect-to-os-log-tool-test redirect-to-os-log redirect-to-os-log-tool-test-subprocess)

add_test(NAME redirect-to-os-log-tool-test COMMAND redirect-to-os-log-tool-test)
2 changes: 1 addition & 1 deletion tool/CMakeLists.txt
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)

0 comments on commit 71fd47e

Please sign in to comment.