Verified Commit 99805139 authored by Tommaso Tocci's avatar Tommaso Tocci
Browse files

Bypass early interceptions

The library intercepts IO functions from others library constructors
before our constructor have been executed.

All the interceptions triggered before that our constructor have been
executed are now forwarded to the glibc.

By moving the logger initialization outside of the passthrough
initialization we will be able to implements fopen interceptions.
parent 332081b6
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -5,9 +5,6 @@
#ifndef IFS_PASSTHROUGH_HPP
#define IFS_PASSTHROUGH_HPP

#include <preload/preload.hpp>
#include <iostream>

// function pointer for preloading
extern void* libc;

+4 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ class PreloadContext {
    std::shared_ptr<FsConfig> fs_conf_;

    std::string mountdir_;
    bool initialized_;

    public:
    static PreloadContext* getInstance() {
@@ -63,6 +64,9 @@ class PreloadContext {

    const std::shared_ptr<OpenFileMap>& file_map() const;
    const std::shared_ptr<FsConfig>& fs_conf() const;

    void initialized(const bool& flag);
    bool initialized() const;
};


+263 −189
Original line number Diff line number Diff line
@@ -13,25 +13,28 @@ using namespace std;

int open(const char* path, int flags, ...) {
    init_passthrough_if_needed();
    CTX->log()->trace("{}() called with path {}", __func__, path);

    mode_t mode = 0;
    if (flags & O_CREAT) {
        va_list vl;
        va_start(vl, flags);
        mode = static_cast<mode_t>(va_arg(vl, int));
        va_end(vl);
    }

    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        if(flags & O_DIRECTORY){
            CTX->log()->error("{}() called with `O_DIRECTORY` flag on {}", __func__, path);
            errno = ENOTSUP;
            return -1;
        }

    if (flags & O_CREAT) {
        va_list vl;
        va_start(vl, flags);
        mode = static_cast<mode_t>(va_arg(vl, int));
        va_end(vl);
    }
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            return adafs_open(rel_path, mode, flags);
        }
    }
    return (reinterpret_cast<decltype(&open)>(libc_open))(path, flags, mode);
}

@@ -39,7 +42,6 @@ int open(const char* path, int flags, ...) {

int open64(const char* path, int flags, ...) {
    init_passthrough_if_needed();
    CTX->log()->trace("{}() called with path {}", __func__, path);
    mode_t mode = 0;
    if (flags & O_CREAT) {
        va_list ap;
@@ -68,7 +70,9 @@ int open64(const char* path, int flags, ...) {

int creat(const char* path, mode_t mode) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {} with mode {}", __func__, path, mode);
    }
    return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
}

@@ -76,22 +80,27 @@ int creat(const char* path, mode_t mode) {

int creat64(const char* path, mode_t mode) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {} with mode {}", __func__, path, mode);
    }
    return open(path, O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE, mode);
}

int mkdir(const char* path, mode_t mode) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {} with mode {}", __func__, path, mode);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            return adafs_mk_node(rel_path, mode | S_IFDIR);
        }
    }
    return (reinterpret_cast<decltype(&mkdir)>(libc_mkdir))(path, mode);
}

int mkdirat(int dirfd, const char* path, mode_t mode) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {} with mode {} with dirfd {}", __func__, path, mode, dirfd);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
@@ -100,37 +109,44 @@ int mkdirat(int dirfd, const char* path, mode_t mode) __THROW {
            errno = EBUSY;
            return -1;
        }
    }
    return (reinterpret_cast<decltype(&mkdirat)>(libc_mkdirat))(dirfd, path, mode);
}


int unlink(const char* path) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            return adafs_rm_node(rel_path);
        }
    }
    return (reinterpret_cast<decltype(&unlink)>(libc_unlink))(path);
}

int rmdir(const char* path) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            return adafs_rmdir(rel_path);
        }
    }
    return (reinterpret_cast<decltype(&rmdir)>(libc_rmdir))(path);
}

int close(int fd) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            // No call to the daemon is required
            CTX->file_map()->remove(fd);
            return 0;
        }
    }
    return (reinterpret_cast<decltype(&close)>(libc_close))(fd);
}

@@ -144,16 +160,19 @@ int remove(const char* path) {

int access(const char* path, int mask) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called path {} mask {}", __func__, path, mask);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            return adafs_access(rel_path, mask);
        }
    }
    return (reinterpret_cast<decltype(&access)>(libc_access))(path, mask);
}

int faccessat(int dirfd, const char* path, int mode, int flags) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called path {} mode {} dirfd {} flags {}", __func__, path, mode, dirfd, flags);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
@@ -161,103 +180,123 @@ int faccessat(int dirfd, const char* path, int mode, int flags) __THROW {
            CTX->log()->trace("{}() not implemented.", __func__);
            return -1;
        }
    }
    return (reinterpret_cast<decltype(&faccessat)>(libc_faccessat))(dirfd, path, mode, flags);
}


int stat(const char* path, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            return adafs_stat(rel_path, buf);
        }
    }
    return (reinterpret_cast<decltype(&stat)>(libc_stat))(path, buf);
}

int fstat(int fd, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with fd {}", __func__, fd);
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            auto path = CTX->file_map()->get(fd)->path();
            return adafs_stat(path, buf);
        }
    }
    return (reinterpret_cast<decltype(&fstat)>(libc_fstat))(fd, buf);
}

int lstat(const char* path, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            CTX->log()->warn("{}() No symlinks are supported. Stats will always target the given path", __func__);
            return adafs_stat(rel_path, buf);
        }
    }
    return (reinterpret_cast<decltype(&lstat)>(libc_lstat))(path, buf);
}

int __xstat(int ver, const char* path, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            return adafs_stat(rel_path, buf);
        }
    }
    return (reinterpret_cast<decltype(&__xstat)>(libc___xstat))(ver, path, buf);
}

int __xstat64(int ver, const char* path, struct stat64* buf) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            return adafs_stat64(rel_path, buf);
        }
    }
    return (reinterpret_cast<decltype(&__xstat64)>(libc___xstat64))(ver, path, buf);
}

int __fxstat(int ver, int fd, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with fd {}", __func__, fd);
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            auto path = CTX->file_map()->get(fd)->path();
            return adafs_stat(path, buf);
        }
    }
    return (reinterpret_cast<decltype(&__fxstat)>(libc___fxstat))(ver, fd, buf);
}

int __fxstat64(int ver, int fd, struct stat64* buf) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with fd {}", __func__, fd);
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            auto path = CTX->file_map()->get(fd)->path();
            return adafs_stat64(path, buf);
        }
    }
    return (reinterpret_cast<decltype(&__fxstat64)>(libc___fxstat64))(ver, fd, buf);
}

int __lxstat(int ver, const char* path, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            return adafs_stat(rel_path, buf);
        }
    }
    return (reinterpret_cast<decltype(&__lxstat)>(libc___lxstat))(ver, path, buf);
}

int __lxstat64(int ver, const char* path, struct stat64* buf) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
            return adafs_stat64(rel_path, buf);
        }
    }
    return (reinterpret_cast<decltype(&__lxstat64)>(libc___lxstat64))(ver, path, buf);
}

int statfs(const char* path, struct statfs* buf) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
@@ -269,11 +308,13 @@ int statfs(const char* path, struct statfs* buf) __THROW {
                return ret;
            return adafs_statfs(rel_path, buf, realfs);
        }
    }
    return (reinterpret_cast<decltype(&statfs)>(libc_statfs))(path, buf);
}

int fstatfs(int fd, struct statfs* buf) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with fd {}", __func__, fd);
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            auto adafs_fd = CTX->file_map()->get(fd);
@@ -285,6 +326,7 @@ int fstatfs(int fd, struct statfs* buf) {
                return ret;
            return adafs_statfs(adafs_fd->path(), buf, realfs);
        }
    }
    return (reinterpret_cast<decltype(&fstatfs)>(libc_fstatfs))(fd, buf);
}

@@ -294,6 +336,7 @@ int puts(const char* str) {

ssize_t write(int fd, const void* buf, size_t count) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            CTX->log()->trace("{}() called with fd {}", __func__, fd);
            auto adafs_fd = CTX->file_map()->get(fd);
@@ -307,29 +350,35 @@ ssize_t write(int fd, const void* buf, size_t count) {
            }
            return ret;
        }
    }
    return (reinterpret_cast<decltype(&write)>(libc_write))(fd, buf, count);
}

ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            CTX->log()->trace("{}() called with fd {}", __func__, fd);
            return adafs_pwrite_ws(fd, buf, count, offset);
        }
    }
    return (reinterpret_cast<decltype(&pwrite)>(libc_pwrite))(fd, buf, count, offset);
}

ssize_t pwrite64(int fd, const void* buf, size_t count, __off64_t offset) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            CTX->log()->trace("{}() called with fd {}", __func__, fd);
            return adafs_pwrite_ws(fd, buf, count, offset);
        }
    }
    return (reinterpret_cast<decltype(&pwrite64)>(libc_pwrite64))(fd, buf, count, offset);
}

ssize_t read(int fd, void* buf, size_t count) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            auto adafs_fd = CTX->file_map()->get(fd);
            auto pos = adafs_fd->pos(); //retrieve the current offset
@@ -341,29 +390,35 @@ ssize_t read(int fd, void* buf, size_t count) {
            }
            return ret;
        }
    }
    return (reinterpret_cast<decltype(&read)>(libc_read))(fd, buf, count);
}

ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            CTX->log()->trace("{}() called with fd {}", __func__, fd);
            return adafs_pread_ws(fd, buf, count, offset);
        }
    }
    return (reinterpret_cast<decltype(&pread)>(libc_pread))(fd, buf, count, offset);
}

ssize_t pread64(int fd, void* buf, size_t count, __off64_t offset) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            CTX->log()->trace("{}() called with fd {}", __func__, fd);
            return adafs_pread_ws(fd, buf, count, offset);
        }
    }
    return (reinterpret_cast<decltype(&pread64)>(libc_pread64))(fd, buf, count, offset);
}

off_t lseek(int fd, off_t offset, int whence) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            CTX->log()->trace("{}() called with path {} with mode {}", __func__, fd, offset, whence);
            auto off_ret = adafs_lseek(fd, static_cast<off64_t>(offset), whence);
@@ -374,34 +429,41 @@ off_t lseek(int fd, off_t offset, int whence) __THROW {
                return off_ret;
            }
        }
    }
   return (reinterpret_cast<decltype(&lseek)>(libc_lseek))(fd, offset, whence);
}

#undef lseek64
off64_t lseek64(int fd, off64_t offset, int whence) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            CTX->log()->trace("{}() called with path {} with mode {}", __func__, fd, offset, whence);
            return adafs_lseek(fd, offset, whence);
        }
    }
    return (reinterpret_cast<decltype(&lseek64)>(libc_lseek64))(fd, offset, whence);
}

int fsync(int fd) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            CTX->log()->trace("{}() called with fd {} path {}", __func__, fd, CTX->file_map()->get(fd)->path());
            return 0; // This is a noop for us atm. fsync is called implicitly because each chunk is closed after access
        }
    }
    return (reinterpret_cast<decltype(&fsync)>(libc_fsync))(fd);
}

int fdatasync(int fd) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            CTX->log()->trace("{}() called with fd {} path {}", __func__, fd, CTX->file_map()->get(fd)->path());
            return 0; // This is a noop for us atm. fsync is called implicitly because each chunk is closed after access
        }
    }
    return (reinterpret_cast<decltype(&fdatasync)>(libc_fdatasync))(fd);
}

@@ -417,24 +479,29 @@ int ftruncate(int fd, off_t length) __THROW {

int dup(int oldfd) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(oldfd)) {
            CTX->log()->trace("{}() called with oldfd {}", __func__, oldfd);
            return adafs_dup(oldfd);
        }
    }
    return (reinterpret_cast<decltype(&dup)>(libc_dup))(oldfd);
}

int dup2(int oldfd, int newfd) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(oldfd)) {
            CTX->log()->trace("{}() called with oldfd {} newfd {}", __func__, oldfd, newfd);
            return adafs_dup2(oldfd, newfd);
        }
    }
    return (reinterpret_cast<decltype(&dup2)>(libc_dup2))(oldfd, newfd);
}

int dup3(int oldfd, int newfd, int flags) __THROW {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if (ld_is_aux_loaded() && CTX->file_map()->exist(oldfd)) {
            // TODO implement O_CLOEXEC flag first which is used with fcntl(2)
            // It is in glibc since kernel 2.9. So maybe not that important :)
@@ -442,6 +509,7 @@ int dup3(int oldfd, int newfd, int flags) __THROW {
            errno = EBUSY;
            return -1;
        }
    }
    return (reinterpret_cast<decltype(&dup3)>(libc_dup3))(oldfd, newfd, flags);
}

@@ -459,6 +527,7 @@ inline DIR* fd_to_dirp(const int fd){

DIR* opendir(const char* path){
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        CTX->log()->trace("{}() called with path {}", __func__, path);
        std::string rel_path(path);
        if (CTX->relativize_path(rel_path)) {
@@ -468,11 +537,13 @@ DIR* opendir(const char* path){
            }
            return fd_to_dirp(fd);
        }
    }
    return (reinterpret_cast<decltype(&opendir)>(libc_opendir))(path);
}

struct dirent* intcp_readdir(DIR* dirp){
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if(dirp == nullptr){
            errno = EINVAL;
            return nullptr;
@@ -481,11 +552,13 @@ struct dirent* intcp_readdir(DIR* dirp){
        if(ld_is_aux_loaded() && CTX->file_map()->exist(fd)) {
            return adafs_readdir(fd);
        }
    }
    return (reinterpret_cast<decltype(&readdir)>(libc_readdir))(dirp);
}

int intcp_closedir(DIR* dirp) {
    init_passthrough_if_needed();
    if(CTX->initialized()) {
        if(dirp == nullptr){
            errno = EINVAL;
            return -1;
@@ -496,5 +569,6 @@ int intcp_closedir(DIR* dirp) {
            CTX->file_map()->remove(fd);
            return 0;
        }
    }
    return (reinterpret_cast<decltype(&closedir)>(libc_closedir))(dirp);
}
 No newline at end of file
+2 −22
Original line number Diff line number Diff line
@@ -2,8 +2,9 @@
 * All intercepted functions are mapped to a different function pointer prefixing <libc_>
 */
#include <preload/passthrough.hpp>
#include <global/configure.hpp>

#include <iostream>
#include <pthread.h>
#include <dlfcn.h>

static pthread_once_t init_lib_thread = PTHREAD_ONCE_INIT;
@@ -122,27 +123,6 @@ void init_passthrough_() {
    libc_opendir = dlsym(libc, "opendir");
    libc_readdir = dlsym(libc, "readdir");
    libc_closedir = dlsym(libc, "closedir");

    //set the spdlogger and initialize it with spdlog
    auto ld_logger = spdlog::basic_logger_mt("basic_logger", LOG_PRELOAD_PATH);
    // set logger format
    spdlog::set_pattern("[%C-%m-%d %H:%M:%S.%f] %P [%L] %v");
    // flush log when info, warning, error messages are encountered
    ld_logger->flush_on(spdlog::level::info);
#if defined(LOG_PRELOAD_TRACE)
    spdlog::set_level(spdlog::level::trace);
    ld_logger->flush_on(spdlog::level::trace);
#elif defined(LOG_PRELOAD_DEBUG)
    spdlog::set_level(spdlog::level::debug);
#elif defined(LOG_PRELOAD_INFO)
    spdlog::set_level(spdlog::level::info);
#else
    spdlog::set_level(spdlog::level::off);
#endif

    CTX->log(ld_logger);

    CTX->log()->debug("{}() Passthrough initialized.", __func__);
}

void init_passthrough_if_needed() {
+24 −2
Original line number Diff line number Diff line

#include <global/global_defs.hpp>
#include <global/configure.hpp>
#include <preload/preload.hpp>
#include <global/rpc/ipc_types.hpp>
#include <preload/margo_ipc.hpp>
@@ -254,14 +255,34 @@ void init_ld_env_if_needed() {
    pthread_once(&init_env_thread, init_ld_environment_);
}

void init_logging() {
    //set the spdlogger and initialize it with spdlog
    auto ld_logger = spdlog::basic_logger_mt("basic_logger", LOG_PRELOAD_PATH);
    // set logger format
    spdlog::set_pattern("[%C-%m-%d %H:%M:%S.%f] %P [%L] %v");
    // flush log when info, warning, error messages are encountered
    ld_logger->flush_on(spdlog::level::info);
#if defined(LOG_PRELOAD_TRACE)
    spdlog::set_level(spdlog::level::trace);
    ld_logger->flush_on(spdlog::level::trace);
#elif defined(LOG_PRELOAD_DEBUG)
    spdlog::set_level(spdlog::level::debug);
#elif defined(LOG_PRELOAD_INFO)
    spdlog::set_level(spdlog::level::info);
#else
    spdlog::set_level(spdlog::level::off);
#endif

    CTX->log(ld_logger);
}

/**
 * Called initially ONCE when preload library is used with the LD_PRELOAD environment variable
 */
void init_preload() {
    init_passthrough_if_needed();
    // The logger is initialized in init_passthrough. So we cannot log before that.
    CTX->log()->info("{}() enter", __func__);
    init_logging();
    CTX->log()->debug("Initialized logging subsystem");
    if (get_daemon_pid() == -1 || CTX->mountdir().empty()) {
        cerr << "ADA-FS daemon not running or mountdir could not be loaded. Check adafs_preload.log" << endl;
        CTX->log()->error("{}() Daemon not running or mountdir not set", __func__);
@@ -270,6 +291,7 @@ void init_preload() {
        CTX->log()->info("{}() mountdir \"{}\" loaded", __func__, CTX->mountdir());
        is_aux_loaded_ = true;
    }
    CTX->initialized(true);
    CTX->log()->debug("{}() exit", __func__);
}

Loading