X-Git-Url: https://ruderich.org/simon/gitweb/?a=blobdiff_plain;f=src%2Fcoloredstderr.c;h=53916f5729c47f79fd1146a33fed2ff4c345613c;hb=4d10935aeebc7c46d5d018abb93bfec17d653b53;hp=c1522186592a91bbfece42a510c5e77018d9257b;hpb=7c5d6fce3a6f52243948e3eae452acb968d78469;p=coloredstderr%2Fcoloredstderr.git diff --git a/src/coloredstderr.c b/src/coloredstderr.c index c152218..53916f5 100644 --- a/src/coloredstderr.c +++ b/src/coloredstderr.c @@ -62,6 +62,9 @@ static int check_handle_fd(int fd) { if (!initialized) { init_from_environment(); } + if (tracked_fds_count == 0) { + return 0; + } /* Never touch anything not going to a terminal - unless we are explicitly * asked to do so. */ @@ -69,15 +72,12 @@ static int check_handle_fd(int fd) { return 0; } - if (tracked_fds_count == 0) { - return 0; - } return tracked_fds_find(fd); } static void dup_fd(int oldfd, int newfd) { #ifdef DEBUG - debug("%d -> %d\t\t\t[%d]\n", oldfd, newfd, getpid()); + debug("%3d -> %3d\t\t\t[%d]\n", oldfd, newfd, getpid()); #endif if (!initialized) { @@ -92,29 +92,26 @@ static void dup_fd(int oldfd, int newfd) { if (tracked_fds_find(oldfd)) { if (!tracked_fds_find(newfd)) { tracked_fds_add(newfd); - update_environment(); } /* We are not tracking this file descriptor, remove newfd from the list * (if present). */ } else { - if (tracked_fds_remove(newfd)) { - update_environment(); - } + tracked_fds_remove(newfd); } } static void close_fd(int fd) { #ifdef DEBUG - debug("%d -> .\t\t\t[%d]\n", fd, getpid()); + debug("%3d -> .\t\t\t[%d]\n", fd, getpid()); #endif if (!initialized) { init_from_environment(); } - if (tracked_fds_count == 0) { return; } + tracked_fds_remove(fd); } @@ -206,7 +203,7 @@ HOOK_FILE2(int, vprintf, stdout, const char *, format, va_list, ap) HOOK_FILE3(int, vfprintf, stream, FILE *, stream, const char *, format, va_list, ap) -/* Hardening functions (-D_FORTIFY_SOURCE=2). */ +/* Hardening functions (-D_FORTIFY_SOURCE=2), only functions from above */ HOOK_VAR_FILE2(int, __printf_chk, stdout, __vprintf_chk, int, flag, const char *, format) HOOK_VAR_FILE3(int, __fprintf_chk, fp, __vfprintf_chk, @@ -302,6 +299,7 @@ int fcntl(int fd, int cmd, ...) { va_start(ap, cmd); result = real_fcntl(fd, cmd, va_arg(ap, void *)); va_end(ap); + /* We only care about duping fds. */ if (cmd == F_DUPFD && result != -1) { int saved_errno = errno; @@ -346,3 +344,125 @@ pid_t vfork(void) { return fork(); } #endif + + +/* Hook execve() and the other exec*() functions. Some shells use exec*() with + * a custom environment which doesn't necessarily contain our updates to + * ENV_NAME_FDS. It's also faster to update the environment only when + * necessary, right before the exec() to pass it to the new process. */ + +static int (*real_execve)(const char *filename, char *const argv[], char *const env[]); +int execve(const char *filename, char *const argv[], char *const env[]) { + DLSYM_FUNCTION(real_execve, "execve"); + + int found = 0; + size_t index = 0; + + /* Count arguments and search for existing ENV_NAME_FDS environment + * variable. */ + size_t count = 0; + char * const *x = env; + while (*x) { + if (!strncmp(*x, ENV_NAME_FDS "=", strlen(ENV_NAME_FDS) + 1)) { + found = 1; + index = count; + } + + x++; + count++; + } + /* Terminating NULL. */ + count++; + + char *env_copy[count + 1 /* space for our new entry if necessary */]; + memcpy(env_copy, env, count * sizeof(char *)); + + /* Make sure the information from the environment is loaded. We can't just + * do nothing (like update_environment()) because the caller might pass a + * different environment which doesn't include any of our settings. */ + if (!initialized) { + init_from_environment(); + } + + char fds_env[strlen(ENV_NAME_FDS) + 1 + update_environment_buffer_size()]; + strcpy(fds_env, ENV_NAME_FDS "="); + update_environment_buffer(fds_env + strlen(ENV_NAME_FDS) + 1); + + if (found) { + env_copy[index] = fds_env; + } else { + /* If the process removed ENV_NAME_FDS from the environment, re-add + * it. */ + env_copy[count-1] = fds_env; + env_copy[count] = NULL; + } + + return real_execve(filename, argv, env_copy); +} + +#define EXECL_COPY_VARARGS_START(args) \ + va_list ap; \ + char *x; \ + \ + /* Count arguments. */ \ + size_t count = 1; /* arg */ \ + va_start(ap, arg); \ + while (va_arg(ap, const char *)) { \ + count++; \ + } \ + va_end(ap); \ + \ + /* Copy varargs. */ \ + char *args[count + 1 /* terminating NULL */]; \ + args[0] = (char *)arg; \ + \ + size_t i = 1; \ + va_start(ap, arg); \ + while ((x = va_arg(ap, char *))) { \ + args[i++] = x; \ + } \ + args[i] = NULL; +#define EXECL_COPY_VARARGS_END(args) \ + va_end(ap); +#define EXECL_COPY_VARARGS(args) \ + EXECL_COPY_VARARGS_START(args); \ + EXECL_COPY_VARARGS_END(args); + +int execl(const char *path, const char *arg, ...) { + EXECL_COPY_VARARGS(args); + + update_environment(); + return execv(path, args); +} + +int execlp(const char *file, const char *arg, ...) { + EXECL_COPY_VARARGS(args); + + update_environment(); + return execvp(file, args); +} + +int execle(const char *path, const char *arg, ... /*, char *const envp[] */) { + EXECL_COPY_VARARGS_START(args); + /* Get envp[] located after arguments. */ + char * const *envp = va_arg(ap, char * const *); + EXECL_COPY_VARARGS_END(args); + + return execve(path, args, envp); +} + +static int (*real_execv)(const char *path, char *const argv[]); +int execv(const char *path, char *const argv[]) { + DLSYM_FUNCTION(real_execv, "execv"); + + update_environment(); + return real_execv(path, argv); +} + +static int (*real_execvp)(const char *path, char *const argv[]); +int execvp(const char *path, char *const argv[]) { + DLSYM_FUNCTION(real_execvp, "execvp"); + + update_environment(); + return real_execvp(path, argv); +}