2 * Hook output functions (like printf(3)) with LD_PRELOAD to color stderr (or
3 * other file descriptors).
5 * Copyright (C) 2013 Simon Ruderich
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /* Must be loaded before the following headers. */
24 #include "ldpreload.h"
37 /* Conflicting declaration in glibc. */
38 #undef fwrite_unlocked
41 /* Used by various functions, including debug(). */
42 static ssize_t (*real_write)(int, void const *, size_t);
43 static int (*real_close)(int);
44 static size_t (*real_fwrite)(void const *, size_t, size_t, FILE *);
46 /* Did we already (try to) parse the environment and setup the necessary
48 static int initialized;
49 /* Force hooked writes even when not writing to a tty. Used for tests. */
50 static int force_write_to_non_tty;
53 #include "constants.h"
58 #include "hookmacros.h"
63 /* See hookmacros.h for the decision if a function call is colored. */
66 static void dup_fd(int oldfd, int newfd) {
68 debug("%3d -> %3d\t\t\t[%d]\n", oldfd, newfd, getpid());
72 init_from_environment();
75 /* We are already tracking this file descriptor, add newfd to the list as
76 * it will reference the same descriptor. */
77 if (tracked_fds_find(oldfd)) {
78 if (!tracked_fds_find(newfd)) {
79 tracked_fds_add(newfd);
81 /* We are not tracking this file descriptor, remove newfd from the list
84 tracked_fds_remove(newfd);
88 static void close_fd(int fd) {
90 debug("%3d -> .\t\t\t[%d]\n", fd, getpid());
94 init_from_environment();
97 tracked_fds_remove(fd);
101 /* "Action" handlers called when a file descriptor is matched. */
103 static char const *pre_string;
104 static size_t pre_string_size;
105 static char const *post_string;
106 static size_t post_string_size;
108 /* Load alternative pre/post strings from the environment if available, fall
109 * back to default values. */
110 inline static void init_pre_post_string(void) {
111 pre_string = getenv(ENV_NAME_PRE_STRING);
113 pre_string = DEFAULT_PRE_STRING;
115 pre_string_size = strlen(pre_string);
117 post_string = getenv(ENV_NAME_POST_STRING);
119 post_string = DEFAULT_POST_STRING;
121 post_string_size = strlen(post_string);
124 static void handle_fd_pre(int fd) {
125 int saved_errno = errno;
127 if (!pre_string || !post_string) {
128 init_pre_post_string();
131 DLSYM_FUNCTION(real_write, "write");
132 real_write(fd, pre_string, pre_string_size);
136 static void handle_fd_post(int fd) {
137 int saved_errno = errno;
139 /* write() already loaded above in handle_fd_pre(). */
140 real_write(fd, post_string, post_string_size);
145 static void handle_file_pre(FILE *stream) {
146 int saved_errno = errno;
148 if (!pre_string || !post_string) {
149 init_pre_post_string();
152 DLSYM_FUNCTION(real_fwrite, "fwrite");
153 real_fwrite(pre_string, pre_string_size, 1, stream);
157 static void handle_file_post(FILE *stream) {
158 int saved_errno = errno;
160 /* fwrite() already loaded above in handle_file_pre(). */
161 real_fwrite(post_string, post_string_size, 1, stream);
168 /* Hook all important output functions to manipulate their output. */
170 HOOK_FD3(ssize_t, write, fd,
171 int, fd, void const *, buf, size_t, count)
172 HOOK_FILE4(size_t, fwrite, stream,
173 void const *, ptr, size_t, size, size_t, nmemb, FILE *, stream)
176 HOOK_FILE2(int, fputs, stream,
177 char const *, s, FILE *, stream)
178 HOOK_FILE2(int, fputc, stream,
179 int, c, FILE *, stream)
180 HOOK_FILE2(int, putc, stream,
181 int, c, FILE *, stream)
182 HOOK_FILE1(int, putchar, stdout,
184 HOOK_FILE1(int, puts, stdout,
187 /* printf(3), excluding all s*() and vs*() functions (no output) */
188 HOOK_VAR_FILE1(int, printf, stdout, vprintf,
189 char const *, format)
190 HOOK_VAR_FILE2(int, fprintf, stream, vfprintf,
191 FILE *, stream, char const *, format)
192 HOOK_FILE2(int, vprintf, stdout,
193 char const *, format, va_list, ap)
194 HOOK_FILE3(int, vfprintf, stream,
195 FILE *, stream, char const *, format, va_list, ap)
196 /* Hardening functions (-D_FORTIFY_SOURCE=2), only functions from above */
197 HOOK_VAR_FILE2(int, __printf_chk, stdout, __vprintf_chk,
198 int, flag, char const *, format)
199 HOOK_VAR_FILE3(int, __fprintf_chk, fp, __vfprintf_chk,
200 FILE *, fp, int, flag, char const *, format)
201 HOOK_FILE3(int, __vprintf_chk, stdout,
202 int, flag, char const *, format, va_list, ap)
203 HOOK_FILE4(int, __vfprintf_chk, stream,
204 FILE *, stream, int, flag, char const *, format, va_list, ap)
206 /* unlocked_stdio(3), only functions from above are hooked */
207 HOOK_FILE4(size_t, fwrite_unlocked, stream,
208 void const *, ptr, size_t, size, size_t, nmemb, FILE *, stream)
209 HOOK_FILE2(int, fputs_unlocked, stream,
210 char const *, s, FILE *, stream)
211 HOOK_FILE2(int, fputc_unlocked, stream,
212 int, c, FILE *, stream)
213 HOOK_FILE2(int, putc_unlocked, stream,
214 int, c, FILE *, stream)
215 HOOK_FILE1(int, putchar_unlocked, stdout,
219 HOOK_VOID1(void, perror, STDERR_FILENO,
224 static void error_vararg(int status, int errnum,
225 char const *filename, unsigned int linenum,
226 char const *format, va_list ap) {
227 static char const *last_filename;
228 static unsigned int last_linenum;
230 /* Skip this error message if requested and if there was already an error
231 * in the same file/line. */
232 if (error_one_per_line
233 && filename != NULL && linenum != 0
234 && filename == last_filename && linenum == last_linenum) {
237 last_filename = filename;
238 last_linenum = linenum;
240 error_message_count++;
244 if (error_print_progname) {
245 error_print_progname();
247 fprintf(stderr, "%s:", program_invocation_name);
249 if (filename != NULL && linenum != 0) {
250 fprintf(stderr, "%s:%u:", filename, linenum);
251 if (error_print_progname) {
252 fprintf(stderr, " ");
255 if (!error_print_progname) {
256 fprintf(stderr, " ");
260 vfprintf(stderr, format, ap);
263 fprintf(stderr, ": %s", strerror(errnum));
266 fprintf(stderr, "\n");
272 void error_at_line(int status, int errnum,
273 char const *filename, unsigned int linenum,
274 char const *format, ...) {
277 va_start(ap, format);
278 error_vararg(status, errnum, filename, linenum, format, ap);
281 void error(int status, int errnum, char const *format, ...) {
284 va_start(ap, format);
285 error_vararg(status, errnum, NULL, 0, format, ap);
291 /* Hook functions which duplicate file descriptors to track them. */
293 static int (*real_dup)(int);
294 static int (*real_dup2)(int, int);
295 static int (*real_dup3)(int, int, int);
299 DLSYM_FUNCTION(real_dup, "dup");
301 newfd = real_dup(oldfd);
303 dup_fd(oldfd, newfd);
308 int dup2(int oldfd, int newfd) {
309 DLSYM_FUNCTION(real_dup2, "dup2");
311 newfd = real_dup2(oldfd, newfd);
313 dup_fd(oldfd, newfd);
318 int dup3(int oldfd, int newfd, int flags) {
319 DLSYM_FUNCTION(real_dup3, "dup3");
321 newfd = real_dup3(oldfd, newfd, flags);
323 dup_fd(oldfd, newfd);
329 static int (*real_fcntl)(int, int, ...);
330 int fcntl(int fd, int cmd, ...) {
334 DLSYM_FUNCTION(real_fcntl, "fcntl");
336 /* fcntl() takes different types of arguments depending on the cmd type
337 * (int, void and pointers are used at the moment). Handling these
338 * arguments for different systems and with possible changes in the future
341 * Therefore always retrieve a void-pointer from our arguments (even if it
342 * wasn't there) and pass it to real_fcntl(). This shouldn't cause any
343 * problems because a void-pointer is most-likely bigger than an int
344 * (something which is not true in reverse) and shouldn't cause
345 * truncation. For register based calling conventions an invalid register
346 * content is passed, but ignored by real_fcntl(). Not perfect, but should
350 result = real_fcntl(fd, cmd, va_arg(ap, void *));
353 /* We only care about duping fds. */
354 if (cmd == F_DUPFD && result != -1) {
361 static int (*real_close)(int);
363 DLSYM_FUNCTION(real_close, "close");
366 return real_close(fd);
368 static int (*real_fclose)(FILE *);
369 int fclose(FILE *fp) {
370 DLSYM_FUNCTION(real_fclose, "fclose");
372 close_fd(fileno(fp));
373 return real_fclose(fp);
377 /* Hook functions which are necessary for correct tracking. */
379 #if defined(HAVE_VFORK) && defined(HAVE_FORK)
381 /* vfork() is similar to fork() but the address space is shared between
382 * father and child. It's designed for fork()/exec() usage because it's
383 * faster than fork(). However according to the POSIX standard the "child"
384 * isn't allowed to perform any memory-modifications before the exec()
385 * (except the pid_t result variable of vfork()).
387 * As some programs don't adhere to the standard (e.g. the "child" closes
388 * or dups a descriptor before the exec()) and this breaks our tracking of
389 * file descriptors (e.g. it gets closed in the parent as well), we just
390 * fork() instead. This is in compliance with the POSIX standard and as
391 * most systems use copy-on-write anyway not a performance issue. */
397 /* Hook execve() and the other exec*() functions. Some shells use exec*() with
398 * a custom environment which doesn't necessarily contain our updates to
399 * ENV_NAME_FDS. It's also faster to update the environment only when
400 * necessary, right before the exec() to pass it to the new process. */
402 static int (*real_execve)(char const *filename, char * const argv[], char * const env[]);
403 int execve(char const *filename, char * const argv[], char * const env[]) {
404 DLSYM_FUNCTION(real_execve, "execve");
409 /* Count arguments and search for existing ENV_NAME_FDS environment
412 char * const *x = env;
414 if (!strncmp(*x, ENV_NAME_FDS "=", strlen(ENV_NAME_FDS) + 1)) {
422 /* Terminating NULL. */
425 char *env_copy[count + 1 /* space for our new entry if necessary */];
426 memcpy(env_copy, env, count * sizeof(char *));
428 /* Make sure the information from the environment is loaded. We can't just
429 * do nothing (like update_environment()) because the caller might pass a
430 * different environment which doesn't include any of our settings. */
432 init_from_environment();
435 char fds_env[strlen(ENV_NAME_FDS) + 1 + update_environment_buffer_size()];
436 strcpy(fds_env, ENV_NAME_FDS "=");
437 update_environment_buffer(fds_env + strlen(ENV_NAME_FDS) + 1);
440 env_copy[index] = fds_env;
442 /* If the process removed ENV_NAME_FDS from the environment, re-add
444 env_copy[count-1] = fds_env;
445 env_copy[count] = NULL;
448 return real_execve(filename, argv, env_copy);
451 #define EXECL_COPY_VARARGS_START(args) \
455 /* Count arguments. */ \
456 size_t count = 1; /* arg */ \
458 while (va_arg(ap, char const *)) { \
463 /* Copy varargs. */ \
464 char *args[count + 1 /* terminating NULL */]; \
465 args[0] = (char *)arg; \
469 while ((x = va_arg(ap, char *))) { \
473 #define EXECL_COPY_VARARGS_END(args) \
475 #define EXECL_COPY_VARARGS(args) \
476 EXECL_COPY_VARARGS_START(args); \
477 EXECL_COPY_VARARGS_END(args);
479 int execl(char const *path, char const *arg, ...) {
480 EXECL_COPY_VARARGS(args);
482 update_environment();
483 return execv(path, args);
486 int execlp(char const *file, char const *arg, ...) {
487 EXECL_COPY_VARARGS(args);
489 update_environment();
490 return execvp(file, args);
493 int execle(char const *path, char const *arg, ... /*, char * const envp[] */) {
494 EXECL_COPY_VARARGS_START(args);
495 /* Get envp[] located after arguments. */
496 char * const *envp = va_arg(ap, char * const *);
497 EXECL_COPY_VARARGS_END(args);
499 return execve(path, args, envp);
502 static int (*real_execv)(char const *path, char * const argv[]);
503 int execv(char const *path, char * const argv[]) {
504 DLSYM_FUNCTION(real_execv, "execv");
506 update_environment();
507 return real_execv(path, argv);
510 static int (*real_execvp)(char const *path, char * const argv[]);
511 int execvp(char const *path, char * const argv[]) {
512 DLSYM_FUNCTION(real_execvp, "execvp");
514 update_environment();
515 return real_execvp(path, argv);