X-Git-Url: https://ruderich.org/simon/gitweb/?p=coloredstderr%2Fcoloredstderr.git;a=blobdiff_plain;f=src%2Fcoloredstderr.c;h=9161fc34f3deff694dba52eb07923fdde19bc4c2;hp=66467b402e14d0a95b630dea38e1e3d59a77a7d7;hb=f78c0377c1fc1862aaa4103fc6de6cfbe3fd0725;hpb=d49cd5d92a07d708ddcb3c29cad67403cf8eb836 diff --git a/src/coloredstderr.c b/src/coloredstderr.c index 66467b4..9161fc3 100644 --- a/src/coloredstderr.c +++ b/src/coloredstderr.c @@ -2,7 +2,7 @@ * Hook output functions (like printf(3)) with LD_PRELOAD to color stderr (or * other file descriptors). * - * Copyright (C) 2013 Simon Ruderich + * Copyright (C) 2013-2018 Simon Ruderich * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +30,10 @@ # define NDEBUG #endif +#ifndef TLS +# define TLS +#endif + #include #include #include @@ -81,6 +85,12 @@ static int force_write_to_non_tty; /* Was ENV_NAME_FDS found and used when init_from_environment() was called? * This is not true if the process set it manually after initialization. */ static int used_fds_set_by_user; +/* Was any of our handle_*_pre()/handle_*_post() functions called recursively? + * If so don't print the pre/post string for the recursive calls. This is + * necessary on some systems (e.g. FreeBSD 9.1) which call multiple hooked + * functions while printing a string (e.g. a FILE * and a fd hook function is + * called). This is not thread-safe if TLS is not available. */ +static TLS int handle_recursive; #include "constants.h" @@ -181,9 +191,13 @@ static void handle_file_pre(FILE *stream) noinline; static void handle_file_post(FILE *stream) noinline; static void handle_fd_pre(int fd) { + if (handle_recursive++ > 0) { + return; + } + int saved_errno = errno; - if (unlikely(!pre_string || !post_string)) { + if (unlikely(!pre_string)) { init_pre_post_string(); } @@ -193,6 +207,10 @@ static void handle_fd_pre(int fd) { errno = saved_errno; } static void handle_fd_post(int fd) { + if (--handle_recursive > 0) { + return; + } + int saved_errno = errno; /* write() already loaded above in handle_fd_pre(). */ @@ -202,9 +220,13 @@ static void handle_fd_post(int fd) { } static void handle_file_pre(FILE *stream) { + if (handle_recursive++ > 0) { + return; + } + int saved_errno = errno; - if (unlikely(!pre_string || !post_string)) { + if (unlikely(!pre_string)) { init_pre_post_string(); } @@ -214,6 +236,10 @@ static void handle_file_pre(FILE *stream) { errno = saved_errno; } static void handle_file_post(FILE *stream) { + if (--handle_recursive > 0) { + return; + } + int saved_errno = errno; /* fwrite() already loaded above in handle_file_pre(). */ @@ -300,7 +326,7 @@ HOOK_FILE2(int, __overflow, f, _IO_FILE *, f, int, ch) /* Same for FreeBSD's libc. However it's more aggressive: The inline writing * and __swbuf() are also used for normal output (e.g. putc()). Writing to * stderr is still fine; it always calls __swbuf() as stderr is always - * unbufferd. */ + * unbuffered. */ #ifdef HAVE___SWBUF HOOK_FILE2(int, __swbuf, f, int, c, FILE *, f) #endif @@ -349,7 +375,7 @@ static void error_vararg(int status, int errnum, if (error_one_per_line && filename != NULL && linenum != 0 && filename == last_filename && linenum == last_linenum) { - return; + goto out; } last_filename = filename; last_linenum = linenum; @@ -382,6 +408,7 @@ static void error_vararg(int status, int errnum, fprintf(stderr, "\n"); +out: if (status != 0) { exit(status); } @@ -507,11 +534,12 @@ pid_t vfork(void) { * isn't allowed to perform any memory-modifications before the exec() * (except the pid_t result variable of vfork()). * - * As some programs don't adhere to the standard (e.g. the "child" closes - * or dups a descriptor before the exec()) and this breaks our tracking of - * file descriptors (e.g. it gets closed in the parent as well), we just - * fork() instead. This is in compliance with the POSIX standard and as - * most systems use copy-on-write anyway not a performance issue. */ + * As we have to store changes to the file descriptors in memory (e.g. the + * "child" closes or dups a descriptor before the exec()) and this + * modifies the parent as well due to the semantics of vfork() - thus + * breaking the requirements of vfork(), we just use fork instead(). This + * is in compliance with the POSIX standard and as most systems use + * copy-on-write anyway not a performance issue. */ return fork(); } #endif @@ -526,6 +554,11 @@ pid_t vfork(void) { HOOK_FUNC_DEF3(int, execve, char const *, filename, char * const *, argv, char * const *, env) { DLSYM_FUNCTION(real_execve, "execve"); + char * const fake_env[] = {NULL}; + if (env == NULL) { + env = fake_env; + } + /* Count environment variables. */ size_t count = 0; char * const *x = env;