]> ruderich.org/simon Gitweb - coloredstderr/coloredstderr.git/blob - src/coloredstderr.c
update copyright year
[coloredstderr/coloredstderr.git] / src / coloredstderr.c
1 /*
2  * Hook output functions (like printf(3)) with LD_PRELOAD to color stderr (or
3  * other file descriptors).
4  *
5  * Copyright (C) 2013-2015  Simon Ruderich
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 #include <config.h>
22
23 #include "compiler.h"
24
25 /* Must be loaded before the following headers. */
26 #include "ldpreload.h"
27
28 /* Disable assert()s if not compiled with --enable-debug. */
29 #ifndef DEBUG
30 # define NDEBUG
31 #endif
32
33 #ifndef TLS
34 # define TLS
35 #endif
36
37 #include <assert.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <sys/stat.h>
44 #include <unistd.h>
45
46 #ifdef HAVE_ERR_H
47 # include <err.h>
48 #endif
49 #ifdef HAVE_ERROR_H
50 # include <error.h>
51 #endif
52 #ifdef HAVE_STRUCT__IO_FILE__FILENO
53 # include <libio.h>
54 #endif
55
56 /* The following functions may be macros. Undefine them or they cause build
57  * failures when used in our hook macros below. */
58
59 /* In glibc, real fwrite_unlocked() is called in macro. */
60 #ifdef HAVE_FWRITE_UNLOCKED
61 # undef fwrite_unlocked
62 #endif
63 /* In Clang when compiling with hardening flags (fortify) on Debian Wheezy. */
64 #undef printf
65 #undef fprintf
66 /* On FreeBSD (9.1), __swbuf() is used instead of these macros. */
67 #ifdef HAVE___SWBUF
68 # undef putc
69 # undef putc_unlocked
70 # undef putchar
71 # undef putchar_unlocked
72 #endif
73
74
75 /* Used by various functions, including debug(). */
76 static ssize_t (*real_write)(int, void const *, size_t);
77 static int (*real_close)(int);
78 static size_t (*real_fwrite)(void const *, size_t, size_t, FILE *);
79
80 /* Did we already (try to) parse the environment and setup the necessary
81  * variables? */
82 static int initialized;
83 /* Force hooked writes even when not writing to a tty. Used for tests. */
84 static int force_write_to_non_tty;
85 /* Was ENV_NAME_FDS found and used when init_from_environment() was called?
86  * This is not true if the process set it manually after initialization. */
87 static int used_fds_set_by_user;
88 /* Was any of our handle_*_pre()/handle_*_post() functions called recursively?
89  * If so don't print the pre/post string for the recursive calls. This is
90  * necessary on some systems (e.g. FreeBSD 9.1) which call multiple hooked
91  * functions while printing a string (e.g. a FILE * and a fd hook function is
92  * called). This is not thread-safe if TLS is not available. */
93 static TLS int handle_recursive;
94
95
96 #include "constants.h"
97 #ifdef WARNING
98 # include "debug.h"
99 #endif
100
101 #include "hookmacros.h"
102 #include "trackfds.h"
103
104
105
106 /* See hookmacros.h for the decision if a function call is colored. */
107
108
109 /* Prevent inlining into hook functions because it may increase the number of
110  * spilled registers unnecessarily. As it's not called very often accept the
111  * additional call. */
112 static int isatty_noinline(int fd) noinline;
113 static int isatty_noinline(int fd) {
114     assert(fd >= 0);
115
116     int saved_errno = errno;
117     int result = isatty(fd);
118     errno = saved_errno;
119
120     return result;
121 }
122
123
124 static void dup_fd(int oldfd, int newfd) {
125 #ifdef DEBUG
126     debug("%3d -> %3d\t\t\t[%d]\n", oldfd, newfd, getpid());
127 #endif
128
129     assert(oldfd >= 0 && newfd >= 0);
130
131     if (unlikely(!initialized)) {
132         init_from_environment();
133     }
134
135     /* We are already tracking this file descriptor, add newfd to the list as
136      * it will reference the same descriptor. */
137     if (tracked_fds_find(oldfd)) {
138         if (!tracked_fds_find(newfd)) {
139             tracked_fds_add(newfd);
140         }
141     /* We are not tracking this file descriptor, remove newfd from the list
142      * (if present). */
143     } else {
144         tracked_fds_remove(newfd);
145     }
146 }
147
148 static void close_fd(int fd) {
149 #ifdef DEBUG
150     debug("%3d ->   .\t\t\t[%d]\n", fd, getpid());
151 #endif
152
153     assert(fd >= 0);
154
155     if (unlikely(!initialized)) {
156         init_from_environment();
157     }
158
159     tracked_fds_remove(fd);
160 }
161
162
163 /* "Action" handlers called when a file descriptor is matched. */
164
165 static char const *pre_string;
166 static size_t pre_string_size;
167 static char const *post_string;
168 static size_t post_string_size;
169
170 /* Load alternative pre/post strings from the environment if available, fall
171  * back to default values. */
172 static void init_pre_post_string(void) {
173     pre_string = getenv(ENV_NAME_PRE_STRING);
174     if (!pre_string) {
175         pre_string = DEFAULT_PRE_STRING;
176     }
177     pre_string_size = strlen(pre_string);
178
179     post_string = getenv(ENV_NAME_POST_STRING);
180     if (!post_string) {
181         post_string = DEFAULT_POST_STRING;
182     }
183     post_string_size = strlen(post_string);
184 }
185
186 /* Don't inline any of the pre/post functions. Keep the hook function as small
187  * as possible for speed reasons. */
188 static void handle_fd_pre(int fd) noinline;
189 static void handle_fd_post(int fd) noinline;
190 static void handle_file_pre(FILE *stream) noinline;
191 static void handle_file_post(FILE *stream) noinline;
192
193 static void handle_fd_pre(int fd) {
194     if (handle_recursive++ > 0) {
195         return;
196     }
197
198     int saved_errno = errno;
199
200     if (unlikely(!pre_string)) {
201         init_pre_post_string();
202     }
203
204     DLSYM_FUNCTION(real_write, "write");
205     real_write(fd, pre_string, pre_string_size);
206
207     errno = saved_errno;
208 }
209 static void handle_fd_post(int fd) {
210     if (--handle_recursive > 0) {
211         return;
212     }
213
214     int saved_errno = errno;
215
216     /* write() already loaded above in handle_fd_pre(). */
217     real_write(fd, post_string, post_string_size);
218
219     errno = saved_errno;
220 }
221
222 static void handle_file_pre(FILE *stream) {
223     if (handle_recursive++ > 0) {
224         return;
225     }
226
227     int saved_errno = errno;
228
229     if (unlikely(!pre_string)) {
230         init_pre_post_string();
231     }
232
233     DLSYM_FUNCTION(real_fwrite, "fwrite");
234     real_fwrite(pre_string, pre_string_size, 1, stream);
235
236     errno = saved_errno;
237 }
238 static void handle_file_post(FILE *stream) {
239     if (--handle_recursive > 0) {
240         return;
241     }
242
243     int saved_errno = errno;
244
245     /* fwrite() already loaded above in handle_file_pre(). */
246     real_fwrite(post_string, post_string_size, 1, stream);
247
248     errno = saved_errno;
249 }
250
251
252
253 /* Hook all important output functions to manipulate their output. */
254
255 HOOK_FD3(ssize_t, write, fd,
256          int, fd, void const *, buf, size_t, count)
257 HOOK_FILE4(size_t, fwrite, stream,
258            void const *, ptr, size_t, size, size_t, nmemb, FILE *, stream)
259
260 /* puts(3) */
261 HOOK_FILE2(int, fputs, stream,
262            char const *, s, FILE *, stream)
263 HOOK_FILE2(int, fputc, stream,
264            int, c, FILE *, stream)
265 HOOK_FILE2(int, putc, stream,
266            int, c, FILE *, stream)
267 /* The glibc uses a macro for putc() which expands to _IO_putc(). However
268  * sometimes the raw putc() is used as well, not sure why. Make sure to hook
269  * it too. */
270 #ifdef putc
271 # undef putc
272 HOOK_FILE2(int, putc, stream,
273            int, c, FILE *, stream)
274 #endif
275 HOOK_FILE1(int, putchar, stdout,
276            int, c)
277 HOOK_FILE1(int, puts, stdout,
278            char const *, s)
279
280 /* printf(3), excluding all s*() and vs*() functions (no output) */
281 HOOK_VAR_FILE1(int, printf, stdout, vprintf,
282                char const *, format)
283 HOOK_VAR_FILE2(int, fprintf, stream, vfprintf,
284                FILE *, stream, char const *, format)
285 HOOK_FILE2(int, vprintf, stdout,
286            char const *, format, va_list, ap)
287 HOOK_FILE3(int, vfprintf, stream,
288            FILE *, stream, char const *, format, va_list, ap)
289 /* Hardening functions (-D_FORTIFY_SOURCE=2), only functions from above */
290 HOOK_VAR_FILE2(int, __printf_chk, stdout, __vprintf_chk,
291                int, flag, char const *, format)
292 HOOK_VAR_FILE3(int, __fprintf_chk, fp, __vfprintf_chk,
293                FILE *, fp, int, flag, char const *, format)
294 HOOK_FILE3(int, __vprintf_chk, stdout,
295            int, flag, char const *, format, va_list, ap)
296 HOOK_FILE4(int, __vfprintf_chk, stream,
297            FILE *, stream, int, flag, char const *, format, va_list, ap)
298
299 /* unlocked_stdio(3), only functions from above are hooked */
300 #ifdef HAVE_FWRITE_UNLOCKED
301 HOOK_FILE4(size_t, fwrite_unlocked, stream,
302            void const *, ptr, size_t, size, size_t, nmemb, FILE *, stream)
303 #endif
304 #ifdef HAVE_FPUTS_UNLOCKED
305 HOOK_FILE2(int, fputs_unlocked, stream,
306            char const *, s, FILE *, stream)
307 #endif
308 #ifdef HAVE_FPUTC_UNLOCKED
309 HOOK_FILE2(int, fputc_unlocked, stream,
310            int, c, FILE *, stream)
311 #endif
312 HOOK_FILE2(int, putc_unlocked, stream,
313            int, c, FILE *, stream)
314 HOOK_FILE1(int, putchar_unlocked, stdout,
315            int, c)
316 /* glibc defines (_IO_)putc_unlocked() to a macro which either updates the
317  * output buffer or calls __overflow(). As this code is inlined we can't
318  * handle the first case, but if __overflow() is called we can color that
319  * part. As writes to stderr are never buffered, __overflow() is always called
320  * and everything works fine. This is only a problem if stdout is dupped to
321  * stderr (which shouldn't be the case too often). */
322 #if defined(HAVE_STRUCT__IO_FILE__FILENO) && defined(HAVE___OVERFLOW)
323 /* _IO_FILE is glibc's representation of FILE. */
324 HOOK_FILE2(int, __overflow, f, _IO_FILE *, f, int, ch)
325 #endif
326 /* Same for FreeBSD's libc. However it's more aggressive: The inline writing
327  * and __swbuf() are also used for normal output (e.g. putc()). Writing to
328  * stderr is still fine; it always calls __swbuf() as stderr is always
329  * unbuffered. */
330 #ifdef HAVE___SWBUF
331 HOOK_FILE2(int, __swbuf, f, int, c, FILE *, f)
332 #endif
333
334 /* perror(3) */
335 HOOK_VOID1(void, perror, STDERR_FILENO,
336            char const *, s)
337
338 /* err(3), non standard BSD extension */
339 #ifdef HAVE_ERR_H
340 HOOK_VAR_VOID2(void, err, STDERR_FILENO, verr,
341                int, eval, char const *, fmt)
342 HOOK_VAR_VOID2(void, errx, STDERR_FILENO, verrx,
343                int, eval, char const *, fmt)
344 HOOK_VAR_VOID1(void, warn, STDERR_FILENO, vwarn,
345                char const *, fmt)
346 HOOK_VAR_VOID1(void, warnx, STDERR_FILENO, vwarnx,
347                char const *, fmt)
348 HOOK_FUNC_SIMPLE3(void, verr, int, eval, const char *, fmt, va_list, args) {
349     /* Can't use verr() directly as it terminates the process which prevents
350      * the post string from being printed. */
351     vwarn(fmt, args);
352     exit(eval);
353 }
354 HOOK_FUNC_SIMPLE3(void, verrx, int, eval, const char *, fmt, va_list, args) {
355     /* See verr(). */
356     vwarnx(fmt, args);
357     exit(eval);
358 }
359 HOOK_VOID2(void, vwarn, STDERR_FILENO,
360            char const *, fmt, va_list, args)
361 HOOK_VOID2(void, vwarnx, STDERR_FILENO,
362            char const *, fmt, va_list, args)
363 #endif
364
365 /* error(3), non-standard GNU extension */
366 #ifdef HAVE_ERROR_H
367 static void error_vararg(int status, int errnum,
368                          char const *filename, unsigned int linenum,
369                          char const *format, va_list ap) {
370     static char const *last_filename;
371     static unsigned int last_linenum;
372
373     /* Skip this error message if requested and if there was already an error
374      * in the same file/line. */
375     if (error_one_per_line
376             && filename != NULL && linenum != 0
377             && filename == last_filename && linenum == last_linenum) {
378         goto out;
379     }
380     last_filename = filename;
381     last_linenum  = linenum;
382
383     error_message_count++;
384
385     fflush(stdout);
386
387     if (error_print_progname) {
388         error_print_progname();
389     } else {
390         fprintf(stderr, "%s:", program_invocation_name);
391     }
392     if (filename != NULL && linenum != 0) {
393         fprintf(stderr, "%s:%u:", filename, linenum);
394         if (error_print_progname) {
395             fprintf(stderr, " ");
396         }
397     }
398     if (!error_print_progname) {
399         fprintf(stderr, " ");
400     }
401
402
403     vfprintf(stderr, format, ap);
404
405     if (errnum != 0) {
406         fprintf(stderr, ": %s", strerror(errnum));
407     }
408
409     fprintf(stderr, "\n");
410
411 out:
412     if (status != 0) {
413         exit(status);
414     }
415 }
416 void error_at_line(int status, int errnum,
417                    char const *filename, unsigned int linenum,
418                    char const *format, ...) {
419     va_list ap;
420
421     va_start(ap, format);
422     error_vararg(status, errnum, filename, linenum, format, ap);
423     va_end(ap);
424 }
425 void error(int status, int errnum, char const *format, ...) {
426     va_list ap;
427
428     va_start(ap, format);
429     error_vararg(status, errnum, NULL, 0, format, ap);
430     va_end(ap);
431 }
432 #endif
433
434
435 /* Hook functions which duplicate file descriptors to track them. */
436
437 /* int dup(int) */
438 HOOK_FUNC_DEF1(int, dup, int, oldfd) {
439     int newfd;
440
441     DLSYM_FUNCTION(real_dup, "dup");
442
443     newfd = real_dup(oldfd);
444     if (newfd > -1) {
445         dup_fd(oldfd, newfd);
446     }
447
448     return newfd;
449 }
450 /* int dup2(int, int) */
451 HOOK_FUNC_DEF2(int, dup2, int, oldfd, int, newfd) {
452     DLSYM_FUNCTION(real_dup2, "dup2");
453
454     newfd = real_dup2(oldfd, newfd);
455     if (newfd > -1) {
456         dup_fd(oldfd, newfd);
457     }
458
459     return newfd;
460 }
461 /* int dup3(int, int, int) */
462 HOOK_FUNC_DEF3(int, dup3, int, oldfd, int, newfd, int, flags) {
463     DLSYM_FUNCTION(real_dup3, "dup3");
464
465     newfd = real_dup3(oldfd, newfd, flags);
466     if (newfd > -1) {
467         dup_fd(oldfd, newfd);
468     }
469
470     return newfd;
471 }
472
473 /* int fcntl(int, int, ...) */
474 HOOK_FUNC_VAR_DEF2(int, fcntl, int, fd, int, cmd /*, ... */) {
475     int result;
476     va_list ap;
477
478     DLSYM_FUNCTION(real_fcntl, "fcntl");
479
480     /* fcntl() takes different types of arguments depending on the cmd type
481      * (int, void and pointers are used at the moment). Handling these
482      * arguments for different systems and with possible changes in the future
483      * is error prone.
484      *
485      * Therefore always retrieve a void-pointer from our arguments (even if it
486      * wasn't there) and pass it to real_fcntl(). This shouldn't cause any
487      * problems because a void-pointer is most-likely bigger than an int
488      * (something which is not true in reverse) and shouldn't cause
489      * truncation. For register based calling conventions an invalid register
490      * content is passed, but ignored by real_fcntl(). Not perfect, but should
491      * work fine.
492      */
493     va_start(ap, cmd);
494     result = real_fcntl(fd, cmd, va_arg(ap, void *));
495     va_end(ap);
496
497     /* We only care about duping fds. */
498     if (cmd == F_DUPFD && result > -1) {
499         dup_fd(fd, result);
500     }
501
502     return result;
503 }
504
505 /* int close(int) */
506 HOOK_FUNC_DEF1(int, close, int, fd) {
507     DLSYM_FUNCTION(real_close, "close");
508
509     if (fd >= 0) {
510         close_fd(fd);
511     }
512     return real_close(fd);
513 }
514 /* int fclose(FILE *) */
515 HOOK_FUNC_DEF1(int, fclose, FILE *, fp) {
516     int fd;
517
518     DLSYM_FUNCTION(real_fclose, "fclose");
519
520     if (fp != NULL && (fd = fileno(fp)) >= 0) {
521         close_fd(fd);
522     }
523     return real_fclose(fp);
524 }
525
526
527 /* Hook functions which are necessary for correct tracking. */
528
529 #if defined(HAVE_VFORK) && defined(HAVE_FORK)
530 pid_t vfork(void) {
531     /* vfork() is similar to fork() but the address space is shared between
532      * father and child. It's designed for fork()/exec() usage because it's
533      * faster than fork(). However according to the POSIX standard the "child"
534      * isn't allowed to perform any memory-modifications before the exec()
535      * (except the pid_t result variable of vfork()).
536      *
537      * As we have to store changes to the file descriptors in memory (e.g. the
538      * "child" closes or dups a descriptor before the exec()) and this
539      * modifies the parent as well due to the semantics of vfork() - thus
540      * breaking the requirements of vfork(), we just use fork instead(). This
541      * is in compliance with the POSIX standard and as most systems use
542      * copy-on-write anyway not a performance issue. */
543     return fork();
544 }
545 #endif
546
547
548 /* Hook execve() and the other exec*() functions. Some shells use exec*() with
549  * a custom environment which doesn't necessarily contain our updates to
550  * ENV_NAME_PRIVATE_FDS. It's also faster to update the environment only when
551  * necessary, right before the exec(), to pass it to the new program. */
552
553 /* int execve(char const *, char * const [], char * const []) */
554 HOOK_FUNC_DEF3(int, execve, char const *, filename, char * const *, argv, char * const *, env) {
555     DLSYM_FUNCTION(real_execve, "execve");
556
557     /* Count environment variables. */
558     size_t count = 0;
559     char * const *x = env;
560     while (*x++) {
561         count++;
562     }
563     /* Terminating NULL. */
564     count++;
565
566     char *env_copy[count + 1 /* space for our new entry if necessary */];
567
568     /* Make sure the information from the environment is loaded. We can't just
569      * do nothing (like update_environment()) because the caller might pass a
570      * different environment which doesn't include any of our settings. */
571     if (!initialized) {
572         init_from_environment();
573     }
574
575     char fds_env[strlen(ENV_NAME_PRIVATE_FDS)
576                  + 1 + update_environment_buffer_size()];
577     strcpy(fds_env, ENV_NAME_PRIVATE_FDS "=");
578     update_environment_buffer(fds_env + strlen(ENV_NAME_PRIVATE_FDS) + 1);
579
580     int found = 0;
581     char **x_copy = env_copy;
582
583     /* Copy the environment manually; allows skipping elements. */
584     x = env;
585     while ((*x_copy = *x)) {
586         /* Remove ENV_NAME_FDS if we've already used its value. The new
587          * program must use the updated list from ENV_NAME_PRIVATE_FDS. */
588         if (used_fds_set_by_user
589                 && !strncmp(*x, ENV_NAME_FDS "=", strlen(ENV_NAME_FDS) + 1)) {
590             x++;
591             continue;
592         /* Update ENV_NAME_PRIVATE_FDS. */
593         } else if (!strncmp(*x, ENV_NAME_PRIVATE_FDS "=",
594                             strlen(ENV_NAME_PRIVATE_FDS) + 1)) {
595             *x_copy = fds_env;
596             found = 1;
597         }
598
599         x++;
600         x_copy++;
601     }
602     /* The loop "condition" NULL-terminates env_copy. */
603
604     if (!found) {
605         /* If the process removed ENV_NAME_PRIVATE_FDS from the environment,
606          * re-add it. */
607         *x_copy++ = fds_env;
608         *x_copy++ = NULL;
609     }
610
611     return real_execve(filename, argv, env_copy);
612 }
613
614 #define EXECL_COPY_VARARGS_START(args) \
615     va_list ap; \
616     char *x; \
617     \
618     /* Count arguments. */ \
619     size_t count = 1; /* arg */ \
620     va_start(ap, arg); \
621     while (va_arg(ap, char *)) { \
622         count++; \
623     } \
624     va_end(ap); \
625     \
626     /* Copy varargs. */ \
627     char *args[count + 1 /* terminating NULL */]; \
628     args[0] = (char *)arg; /* there's no other way around the cast */ \
629     \
630     size_t i = 1; \
631     va_start(ap, arg); \
632     while ((x = va_arg(ap, char *))) { \
633         args[i++] = x; \
634     } \
635     args[i] = NULL;
636 #define EXECL_COPY_VARARGS_END(args) \
637     va_end(ap);
638 #define EXECL_COPY_VARARGS(args) \
639     EXECL_COPY_VARARGS_START(args); \
640     EXECL_COPY_VARARGS_END(args);
641
642 int execl(char const *path, char const *arg, ...) {
643     EXECL_COPY_VARARGS(args);
644
645     /* execv() updates the environment. */
646     return execv(path, args);
647 }
648 int execlp(char const *file, char const *arg, ...) {
649     EXECL_COPY_VARARGS(args);
650
651     /* execvp() updates the environment. */
652     return execvp(file, args);
653 }
654 int execle(char const *path, char const *arg, ... /*, char * const envp[] */) {
655     char * const *envp;
656
657     EXECL_COPY_VARARGS_START(args);
658     /* Get envp[] located after arguments. */
659     envp = va_arg(ap, char * const *);
660     EXECL_COPY_VARARGS_END(args);
661
662     /* execve() updates the environment. */
663     return execve(path, args, envp);
664 }
665
666 /* int execv(char const *, char * const []) */
667 HOOK_FUNC_DEF2(int, execv, char const *, path, char * const *, argv) {
668     DLSYM_FUNCTION(real_execv, "execv");
669
670     update_environment();
671     return real_execv(path, argv);
672 }
673
674 /* int execvp(char const *, char * const []) */
675 HOOK_FUNC_DEF2(int, execvp, char const *, file, char * const *, argv) {
676     DLSYM_FUNCTION(real_execvp, "execvp");
677
678     update_environment();
679     return real_execvp(file, argv);
680 }
681
682 #ifdef HAVE_EXECVPE
683 extern char **environ;
684 int execvpe(char const *file, char * const argv[], char * const envp[]) {
685     int result;
686     char **old_environ = environ;
687
688     /* Fake the environment so we can reuse execvp(). */
689     environ = (char **)envp;
690
691     /* execvp() updates the environment. */
692     result = execvp(file, argv);
693
694     environ = old_environ;
695     return result;
696 }
697 #endif