diff --git a/pkgs/build-support/libredirect/default.nix b/pkgs/build-support/libredirect/default.nix index 42525ec98a7e..f87c6d23dd79 100644 --- a/pkgs/build-support/libredirect/default.nix +++ b/pkgs/build-support/libredirect/default.nix @@ -38,11 +38,11 @@ stdenv.mkDerivation rec { install -vD "$libName" "$out/lib/$libName" + # Provide a setup hook that injects our library into every process. mkdir -p "$hook/nix-support" cat < "$hook/nix-support/setup-hook" ${if stdenv.isDarwin then '' export DYLD_INSERT_LIBRARIES="$out/lib/$libName" - export DYLD_FORCE_FLAT_NAMESPACE=1 '' else '' export LD_PRELOAD="$out/lib/$libName" ''} diff --git a/pkgs/build-support/libredirect/libredirect.c b/pkgs/build-support/libredirect/libredirect.c index c7058ce123c5..7dac4684722f 100644 --- a/pkgs/build-support/libredirect/libredirect.c +++ b/pkgs/build-support/libredirect/libredirect.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,22 @@ #define MAX_REDIRECTS 128 +#ifdef __APPLE__ + struct dyld_interpose { + const void * replacement; + const void * replacee; + }; + #define WRAPPER(ret, name) static ret _libredirect_wrapper_##name + #define LOOKUP_REAL(name) &name + #define WRAPPER_DEF(name) \ + __attribute__((used)) static struct dyld_interpose _libredirect_interpose_##name \ + __attribute__((section("__DATA,__interpose"))) = { &_libredirect_wrapper_##name, &name }; +#else + #define WRAPPER(ret, name) ret name + #define LOOKUP_REAL(name) dlsym(RTLD_NEXT, #name) + #define WRAPPER_DEF(name) +#endif + static int nrRedirects = 0; static char * from[MAX_REDIRECTS]; static char * to[MAX_REDIRECTS]; @@ -80,9 +97,9 @@ static int open_needs_mode(int flags) it contains only what we needed for programs in Nixpkgs. Just add more functions as needed. */ -int open(const char * path, int flags, ...) +WRAPPER(int, open)(const char * path, int flags, ...) { - int (*open_real) (const char *, int, mode_t) = dlsym(RTLD_NEXT, "open"); + int (*open_real) (const char *, int, mode_t) = LOOKUP_REAL(open); mode_t mode = 0; if (open_needs_mode(flags)) { va_list ap; @@ -93,10 +110,12 @@ int open(const char * path, int flags, ...) char buf[PATH_MAX]; return open_real(rewrite(path, buf), flags, mode); } +WRAPPER_DEF(open) -int open64(const char * path, int flags, ...) +#ifndef __APPLE__ +WRAPPER(int, open64)(const char * path, int flags, ...) { - int (*open64_real) (const char *, int, mode_t) = dlsym(RTLD_NEXT, "open64"); + int (*open64_real) (const char *, int, mode_t) = LOOKUP_REAL(open64); mode_t mode = 0; if (open_needs_mode(flags)) { va_list ap; @@ -107,10 +126,12 @@ int open64(const char * path, int flags, ...) char buf[PATH_MAX]; return open64_real(rewrite(path, buf), flags, mode); } +WRAPPER_DEF(open64) +#endif -int openat(int dirfd, const char * path, int flags, ...) +WRAPPER(int, openat)(int dirfd, const char * path, int flags, ...) { - int (*openat_real) (int, const char *, int, mode_t) = dlsym(RTLD_NEXT, "openat"); + int (*openat_real) (int, const char *, int, mode_t) = LOOKUP_REAL(openat); mode_t mode = 0; if (open_needs_mode(flags)) { va_list ap; @@ -121,57 +142,73 @@ int openat(int dirfd, const char * path, int flags, ...) char buf[PATH_MAX]; return openat_real(dirfd, rewrite(path, buf), flags, mode); } +WRAPPER_DEF(openat) -FILE * fopen(const char * path, const char * mode) +WRAPPER(FILE *, fopen)(const char * path, const char * mode) { - FILE * (*fopen_real) (const char *, const char *) = dlsym(RTLD_NEXT, "fopen"); + FILE * (*fopen_real) (const char *, const char *) = LOOKUP_REAL(fopen); char buf[PATH_MAX]; return fopen_real(rewrite(path, buf), mode); } +WRAPPER_DEF(fopen) -FILE * __nss_files_fopen(const char * path) +#ifndef __APPLE__ +WRAPPER(FILE *, __nss_files_fopen)(const char * path) { - FILE * (*__nss_files_fopen_real) (const char *) = dlsym(RTLD_NEXT, "__nss_files_fopen"); + FILE * (*__nss_files_fopen_real) (const char *) = LOOKUP_REAL(__nss_files_fopen); char buf[PATH_MAX]; return __nss_files_fopen_real(rewrite(path, buf)); } +WRAPPER_DEF(__nss_files_fopen) +#endif -FILE * fopen64(const char * path, const char * mode) +#ifndef __APPLE__ +WRAPPER(FILE *, fopen64)(const char * path, const char * mode) { - FILE * (*fopen64_real) (const char *, const char *) = dlsym(RTLD_NEXT, "fopen64"); + FILE * (*fopen64_real) (const char *, const char *) = LOOKUP_REAL(fopen64); char buf[PATH_MAX]; return fopen64_real(rewrite(path, buf), mode); } +WRAPPER_DEF(fopen64) +#endif -int __xstat(int ver, const char * path, struct stat * st) +#ifndef __APPLE__ +WRAPPER(int, __xstat)(int ver, const char * path, struct stat * st) { - int (*__xstat_real) (int ver, const char *, struct stat *) = dlsym(RTLD_NEXT, "__xstat"); + int (*__xstat_real) (int ver, const char *, struct stat *) = LOOKUP_REAL(__xstat); char buf[PATH_MAX]; return __xstat_real(ver, rewrite(path, buf), st); } +WRAPPER_DEF(__xstat) +#endif -int __xstat64(int ver, const char * path, struct stat64 * st) +#ifndef __APPLE__ +WRAPPER(int, __xstat64)(int ver, const char * path, struct stat64 * st) { - int (*__xstat64_real) (int ver, const char *, struct stat64 *) = dlsym(RTLD_NEXT, "__xstat64"); + int (*__xstat64_real) (int ver, const char *, struct stat64 *) = LOOKUP_REAL(__xstat64); char buf[PATH_MAX]; return __xstat64_real(ver, rewrite(path, buf), st); } +WRAPPER_DEF(__xstat64) +#endif -int stat(const char * path, struct stat * st) +WRAPPER(int, stat)(const char * path, struct stat * st) { - int (*__stat_real) (const char *, struct stat *) = dlsym(RTLD_NEXT, "stat"); + int (*__stat_real) (const char *, struct stat *) = LOOKUP_REAL(stat); char buf[PATH_MAX]; return __stat_real(rewrite(path, buf), st); } +WRAPPER_DEF(stat) -int access(const char * path, int mode) +WRAPPER(int, access)(const char * path, int mode) { - int (*access_real) (const char *, int mode) = dlsym(RTLD_NEXT, "access"); + int (*access_real) (const char *, int mode) = LOOKUP_REAL(access); char buf[PATH_MAX]; return access_real(rewrite(path, buf), mode); } +WRAPPER_DEF(access) -int posix_spawn(pid_t * pid, const char * path, +WRAPPER(int, posix_spawn)(pid_t * pid, const char * path, const posix_spawn_file_actions_t * file_actions, const posix_spawnattr_t * attrp, char * const argv[], char * const envp[]) @@ -179,12 +216,13 @@ int posix_spawn(pid_t * pid, const char * path, int (*posix_spawn_real) (pid_t *, const char *, const posix_spawn_file_actions_t *, const posix_spawnattr_t *, - char * const argv[], char * const envp[]) = dlsym(RTLD_NEXT, "posix_spawn"); + char * const argv[], char * const envp[]) = LOOKUP_REAL(posix_spawn); char buf[PATH_MAX]; return posix_spawn_real(pid, rewrite(path, buf), file_actions, attrp, argv, envp); } +WRAPPER_DEF(posix_spawn) -int posix_spawnp(pid_t * pid, const char * file, +WRAPPER(int, posix_spawnp)(pid_t * pid, const char * file, const posix_spawn_file_actions_t * file_actions, const posix_spawnattr_t * attrp, char * const argv[], char * const envp[]) @@ -192,43 +230,48 @@ int posix_spawnp(pid_t * pid, const char * file, int (*posix_spawnp_real) (pid_t *, const char *, const posix_spawn_file_actions_t *, const posix_spawnattr_t *, - char * const argv[], char * const envp[]) = dlsym(RTLD_NEXT, "posix_spawnp"); + char * const argv[], char * const envp[]) = LOOKUP_REAL(posix_spawnp); char buf[PATH_MAX]; return posix_spawnp_real(pid, rewrite(file, buf), file_actions, attrp, argv, envp); } +WRAPPER_DEF(posix_spawnp) -int execv(const char * path, char * const argv[]) +WRAPPER(int, execv)(const char * path, char * const argv[]) { - int (*execv_real) (const char * path, char * const argv[]) = dlsym(RTLD_NEXT, "execv"); + int (*execv_real) (const char * path, char * const argv[]) = LOOKUP_REAL(execv); char buf[PATH_MAX]; return execv_real(rewrite(path, buf), argv); } +WRAPPER_DEF(execv) -int execvp(const char * path, char * const argv[]) +WRAPPER(int, execvp)(const char * path, char * const argv[]) { - int (*_execvp) (const char *, char * const argv[]) = dlsym(RTLD_NEXT, "execvp"); + int (*_execvp) (const char *, char * const argv[]) = LOOKUP_REAL(execvp); char buf[PATH_MAX]; return _execvp(rewrite(path, buf), argv); } +WRAPPER_DEF(execvp) -int execve(const char * path, char * const argv[], char * const envp[]) +WRAPPER(int, execve)(const char * path, char * const argv[], char * const envp[]) { - int (*_execve) (const char *, char * const argv[], char * const envp[]) = dlsym(RTLD_NEXT, "execve"); + int (*_execve) (const char *, char * const argv[], char * const envp[]) = LOOKUP_REAL(execve); char buf[PATH_MAX]; return _execve(rewrite(path, buf), argv, envp); } +WRAPPER_DEF(execve) -DIR * opendir(const char * path) +WRAPPER(DIR *, opendir)(const char * path) { char buf[PATH_MAX]; - DIR * (*_opendir) (const char*) = dlsym(RTLD_NEXT, "opendir"); + DIR * (*_opendir) (const char*) = LOOKUP_REAL(opendir); return _opendir(rewrite(path, buf)); } +WRAPPER_DEF(opendir) #define SYSTEM_CMD_MAX 512 -char *replace_substring(char * source, char * buf, char * replace_string, char * start_ptr, char * suffix_ptr) { +static char * replace_substring(char * source, char * buf, char * replace_string, char * start_ptr, char * suffix_ptr) { char head[SYSTEM_CMD_MAX] = {0}; strncpy(head, source, start_ptr - source); @@ -241,7 +284,7 @@ char *replace_substring(char * source, char * buf, char * replace_string, char * return buf; } -char *replace_string(char * buf, char * from, char * to) { +static char * replace_string(char * buf, char * from, char * to) { int num_matches = 0; char * matches[SYSTEM_CMD_MAX]; int from_len = strlen(from); @@ -264,32 +307,48 @@ char *replace_string(char * buf, char * from, char * to) { return buf; } -void rewriteSystemCall(const char * command, char * buf) { - strcpy(buf, command); +static void rewriteSystemCall(const char * command, char * buf) { + char * p = buf; + + #ifdef __APPLE__ + // The dyld environment variable is not inherited by the subprocess spawned + // by system(), so this hack redefines it. + Dl_info info; + dladdr(&rewriteSystemCall, &info); + p = stpcpy(p, "export DYLD_INSERT_LIBRARIES="); + p = stpcpy(p, info.dli_fname); + p = stpcpy(p, ";"); + #endif + + stpcpy(p, command); + for (int n = 0; n < nrRedirects; ++n) { replace_string(buf, from[n], to[n]); } } -int system(const char *command) +WRAPPER(int, system)(const char *command) { - int (*_system) (const char*) = dlsym(RTLD_NEXT, "system"); + int (*_system) (const char*) = LOOKUP_REAL(system); char newCommand[SYSTEM_CMD_MAX]; rewriteSystemCall(command, newCommand); return _system(newCommand); } +WRAPPER_DEF(system) -int mkdir(const char *path, mode_t mode) +WRAPPER(int, mkdir)(const char *path, mode_t mode) { - int (*mkdir_real) (const char *path, mode_t mode) = dlsym(RTLD_NEXT, "mkdir"); + int (*mkdir_real) (const char *path, mode_t mode) = LOOKUP_REAL(mkdir); char buf[PATH_MAX]; return mkdir_real(rewrite(path, buf), mode); } +WRAPPER_DEF(mkdir) -int mkdirat(int dirfd, const char *path, mode_t mode) +WRAPPER(int, mkdirat)(int dirfd, const char *path, mode_t mode) { - int (*mkdirat_real) (int dirfd, const char *path, mode_t mode) = dlsym(RTLD_NEXT, "mkdirat"); + int (*mkdirat_real) (int dirfd, const char *path, mode_t mode) = LOOKUP_REAL(mkdirat); char buf[PATH_MAX]; return mkdirat_real(dirfd, rewrite(path, buf), mode); } +WRAPPER_DEF(mkdirat)