]> ruderich.org/simon Gitweb - coloredstderr/coloredstderr.git/blobdiff - src/coloredstderr.c
Only hook vfork() if it's available.
[coloredstderr/coloredstderr.git] / src / coloredstderr.c
index 3e5dac2c770ca1f44481529911effab60a7b092c..c1522186592a91bbfece42a510c5e77018d9257b 100644 (file)
@@ -42,6 +42,8 @@ static size_t (*real_fwrite)(const void *, size_t, size_t, FILE *);
 /* Did we already (try to) parse the environment and setup the necessary
  * variables? */
 static int initialized;
+/* Force hooked writes even when not writing to a tty. Used for tests. */
+static int force_write_to_non_tty;
 
 
 #include "constants.h"
@@ -56,16 +58,17 @@ static int initialized;
 
 /* Should the "action" handler be invoked for this file descriptor? */
 static int check_handle_fd(int fd) {
-    /* Never touch anything not going to a terminal. */
-    if (!isatty(fd)) {
-        return 0;
-    }
-
     /* Load state from environment. Only necessary once per process. */
     if (!initialized) {
         init_from_environment();
     }
 
+    /* Never touch anything not going to a terminal - unless we are explicitly
+     * asked to do so. */
+    if (!force_write_to_non_tty && !isatty(fd)) {
+        return 0;
+    }
+
     if (tracked_fds_count == 0) {
         return 0;
     }
@@ -227,6 +230,10 @@ HOOK_FILE1(int, putchar_unlocked, stdout,
 HOOK_FILE1(int, puts_unlocked, stdout,
            const char *, s)
 
+/* perror(3) */
+HOOK_VOID1(void, perror, STDERR_FILENO,
+           const char *, s)
+
 
 /* Hook functions which duplicate file descriptors to track them. */
 
@@ -319,3 +326,23 @@ int fclose(FILE *fp) {
     close_fd(fileno(fp));
     return real_fclose(fp);
 }
+
+
+/* Hook functions which are necessary for correct tracking. */
+
+#if defined(HAVE_VFORK) && defined(HAVE_FORK)
+pid_t vfork(void) {
+    /* vfork() is similar to fork() but the address space is shared between
+     * father and child. It's designed for fork()/exec() usage because it's
+     * faster than fork(). However according to the POSIX standard the "child"
+     * 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. */
+    return fork();
+}
+#endif