]> ruderich.org/simon Gitweb - coloredstderr/coloredstderr.git/commitdiff
Hook BSD err(), errx(), warn(), warnx(), etc. functions.
authorSimon Ruderich <simon@ruderich.org>
Sat, 15 Jun 2013 00:39:52 +0000 (02:39 +0200)
committerSimon Ruderich <simon@ruderich.org>
Sat, 15 Jun 2013 00:39:52 +0000 (02:39 +0200)
err(), errx(), warn(), warnx(), verr(), verrx(), vwarn(), vwarnx() are
hooked.

.gitignore
configure.ac
src/coloredstderr.c
src/hookmacros.h
tests/Makefile.am
tests/example.h [new file with mode: 0644]
tests/example_err.c [new file with mode: 0644]
tests/example_err.expected [new file with mode: 0644]
tests/test_err.sh [new file with mode: 0755]

index 989a2406bb303d457bc722bd4b866288f31b623f..a279991267fb9ded380eb2ff8f8f74d93b672f5d 100644 (file)
@@ -23,6 +23,8 @@
 /tests/Makefile.in
 /tests/example
 /tests/example.o
+/tests/example_err
+/tests/example_err.o
 /tests/example_error
 /tests/example_error.o
 /tests/example_exec
@@ -31,6 +33,8 @@
 /tests/example_vfork.o
 /tests/test_environment.sh.log
 /tests/test_environment.sh.trs
+/tests/test_err.sh.log
+/tests/test_err.sh.trs
 /tests/test_error.sh.log
 /tests/test_error.sh.trs
 /tests/test_example.sh.log
index 0a8f2a86cb732bdfc40ccf59d0eb213d46db0a18..a96edb40a419d394c41d8b28c12caede103c2422 100644 (file)
@@ -36,7 +36,7 @@ if test "x$GCC" = xyes; then
     CFLAGS="-Wall -Wextra -Wconversion $CFLAGS"
 fi
 
-AC_CHECK_HEADERS([error.h])
+AC_CHECK_HEADERS([err.h error.h])
 AC_CHECK_HEADERS([fcntl.h],
                  [],[AC_MSG_ERROR([header is required])])
 
@@ -81,6 +81,7 @@ AC_ARG_ENABLE([debug],
                fi])
 
 dnl Used in tests/Makefile.am to build the test only if function is available.
+AM_CONDITIONAL([HAVE_ERR_H],[test "x$ac_cv_header_err_h" = xyes])
 AM_CONDITIONAL([HAVE_ERROR_H],[test "x$ac_cv_header_error_h" = xyes])
 AM_CONDITIONAL([HAVE_VFORK],[test "x$ac_cv_func_vfork_works" = xyes])
 
index eb9d92cc3c1148d6160e87c4aade4171d8fd2c91..247bd06ecc0d78cfd085574a7665a53b3a40b328 100644 (file)
@@ -38,6 +38,9 @@
 #include <string.h>
 #include <unistd.h>
 
+#ifdef HAVE_ERR_H
+# include <err.h>
+#endif
 #ifdef HAVE_ERROR_H
 # include <error.h>
 #endif
@@ -265,6 +268,33 @@ HOOK_FD2(int, __overflow, f->_fileno, _IO_FILE *, f, int, ch)
 HOOK_VOID1(void, perror, STDERR_FILENO,
            char const *, s)
 
+/* err(3), non standard BSD extension */
+#ifdef HAVE_ERR_H
+HOOK_VAR_VOID2(void, err, STDERR_FILENO, verr,
+               int, eval, char const *, fmt)
+HOOK_VAR_VOID2(void, errx, STDERR_FILENO, verrx,
+               int, eval, char const *, fmt)
+HOOK_VAR_VOID1(void, warn, STDERR_FILENO, vwarn,
+               char const *, fmt)
+HOOK_VAR_VOID1(void, warnx, STDERR_FILENO, vwarnx,
+               char const *, fmt)
+HOOK_FUNC_SIMPLE3(void, verr, int, eval, const char *, fmt, va_list, args) {
+    /* Can't use verr() directly as it terminates the process which prevents
+     * the post string from being printed. */
+    vwarn(fmt, args);
+    exit(eval);
+}
+HOOK_FUNC_SIMPLE3(void, verrx, int, eval, const char *, fmt, va_list, args) {
+    /* See verr(). */
+    vwarnx(fmt, args);
+    exit(eval);
+}
+HOOK_VOID2(void, vwarn, STDERR_FILENO,
+           char const *, fmt, va_list, args)
+HOOK_VOID2(void, vwarnx, STDERR_FILENO,
+           char const *, fmt, va_list, args)
+#endif
+
 /* error(3), non-standard GNU extension */
 #ifdef HAVE_ERROR_H
 static void error_vararg(int status, int errnum,
index 9ee05dbaeff98aeabdbed00485d108220f3f5efc..18a828e30554a569294f6dc59b59cd28ca67059e 100644 (file)
     static type (*real_ ## name)(type1, type2, ...); \
     type name(type1 arg1, type2 arg2, ...)
 
+#define HOOK_FUNC_SIMPLE3(type, name, type1, arg1, type2, arg2, type3, arg3) \
+    type name(type1 arg1, type2 arg2, type3 arg3)
+
 #define HOOK_VOID1(type, name, fd, type1, arg1) \
     static type (*real_ ## name)(type1); \
     type name(type1 arg1) { \
         real_ ## name(arg1); \
         _HOOK_POST_FD_(fd) \
     }
+#define HOOK_VOID2(type, name, fd, type1, arg1, type2, arg2) \
+    static type (*real_ ## name)(type1, type2); \
+    type name(type1 arg1, type2 arg2) { \
+        _HOOK_PRE_FD_(type, name, fd) \
+        real_ ## name(arg1, arg2); \
+        _HOOK_POST_FD_(fd) \
+    }
+#define HOOK_VOID3(type, name, fd, type1, arg1, type2, arg2, type3, arg3) \
+    static type (*real_ ## name)(type1, type2, type3); \
+    type name(type1 arg1, type2 arg2, type3 arg3) { \
+        _HOOK_PRE_FD_(type, name, fd) \
+        real_ ## name(arg1, arg2, arg3); \
+        _HOOK_POST_FD_(fd) \
+    }
+
+#define HOOK_VAR_VOID1(type, name, fd, func, type1, arg1) \
+    type name(type1 arg1, ...) { \
+        va_list ap; \
+        va_start(ap, arg1); \
+        func(arg1, ap); \
+        va_end(ap); \
+    }
+#define HOOK_VAR_VOID2(type, name, fd, func, type1, arg1, type2, arg2) \
+    type name(type1 arg1, type2 arg2, ...) { \
+        va_list ap; \
+        va_start(ap, arg2); \
+        func(arg1, arg2, ap); \
+        va_end(ap); \
+    }
 
 #define HOOK_FD2(type, name, fd, type1, arg1, type2, arg2) \
     static type (*real_ ## name)(type1, type2); \
index 80d0cdd445a03b45a54f58a79a600f2112432e3f..72e822a876f5633c1d4a6825059d41e3baf5b4d5 100644 (file)
@@ -12,6 +12,11 @@ check_PROGRAMS = example example_exec
 example_SOURCES = example.c
 example_exec_SOURCES = example_exec.c
 
+if HAVE_ERR_H
+    TESTS += test_err.sh
+    check_PROGRAMS += example_err
+    example_error_SOURCES = example_err.c
+endif
 if HAVE_ERROR_H
     TESTS += test_error.sh
     check_PROGRAMS += example_error
@@ -24,9 +29,11 @@ if HAVE_VFORK
 endif
 
 dist_check_SCRIPTS = $(TESTS) lib.sh
-dist_check_DATA = example.expected \
+dist_check_DATA = example.h \
+                  example.expected \
                   example_environment.expected \
                   example_environment_empty.expected \
+                  example_err.expected \
                   example_error.expected \
                   example_exec.expected \
                   example_noforce.sh \
diff --git a/tests/example.h b/tests/example.h
new file mode 100644 (file)
index 0000000..facbc30
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Helper functions/macros for example files.
+ *
+ * Copyright (C) 2013  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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#define FORKED_TEST(pid) \
+    pid = fork(); \
+    if (pid == -1) { \
+        perror("fork"); \
+        exit(EXIT_FAILURE); \
+    } else if (pid != 0) { \
+        int status; \
+        if (waitpid(pid, &status, 0) == -1) { \
+            perror("waitpid"); \
+            exit(EXIT_FAILURE); \
+        } \
+        if (WIFEXITED(status)) { \
+            printf("exit code: %d\n", WEXITSTATUS(status)); \
+        } else { \
+            printf("child terminated!\n"); \
+        } \
+        fflush(stdout); \
+    } else
diff --git a/tests/example_err.c b/tests/example_err.c
new file mode 100644 (file)
index 0000000..90072c4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Test err(), verr(), ... Non-standard, BSD only.
+ *
+ * Copyright (C) 2013  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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "../src/compiler.h"
+#include "example.h"
+
+
+int main(int argc unused, char **argv unused) {
+    pid_t pid;
+
+    FORKED_TEST(pid) { errno = ENOMEM; err(0, "error: %s", "message"); }
+    FORKED_TEST(pid) { errno = ENOMEM; err(1, "error: %s", "message"); }
+
+    FORKED_TEST(pid) { errx(0, "error: %s", "message"); }
+    FORKED_TEST(pid) { errx(1, "error: %s", "message"); }
+
+    errno = ENOMEM;
+    warn("warning: %s", "message");
+    warnx("warning: %s", "message");
+
+    /* v*() functions are implicitly tested - the implementation uses them. */
+
+    printf("\n");
+    return EXIT_SUCCESS;
+}
diff --git a/tests/example_err.expected b/tests/example_err.expected
new file mode 100644 (file)
index 0000000..652cd81
--- /dev/null
@@ -0,0 +1,11 @@
+>STDERR>example_err: error: message: Cannot allocate memory
+<STDERR<exit code: 0
+>STDERR>example_err: error: message: Cannot allocate memory
+<STDERR<exit code: 1
+>STDERR>example_err: error: message
+<STDERR<exit code: 0
+>STDERR>example_err: error: message
+<STDERR<exit code: 1
+>STDERR>example_err: warning: message: Cannot allocate memory
+<STDERR<>STDERR>example_err: warning: message
+<STDERR<
diff --git a/tests/test_err.sh b/tests/test_err.sh
new file mode 100755 (executable)
index 0000000..fa16ebb
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# Copyright (C) 2013  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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+test "x$srcdir" = x && srcdir=.
+. "$srcdir/lib.sh"
+
+test_program          example_err
+test_program_subshell example_err