From b8a8cf0d1a333401eae9c9e1d70b9c1b154ff9c9 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Sat, 24 Jan 2015 18:36:29 -0800 Subject: [PATCH] Add . Bug: https://code.google.com/p/android/issues/detail?id=79170 Change-Id: Id91765fac45124545e2674a5b2c814707c1a448b --- libc/Android.mk | 1 + libc/bionic/error.cpp | 95 +++++++++++++++++++++++++++++++++++++++++++ libc/include/error.h | 45 ++++++++++++++++++++ tests/Android.mk | 1 + tests/error_test.cpp | 72 ++++++++++++++++++++++++++++++++ 5 files changed, 214 insertions(+) create mode 100644 libc/bionic/error.cpp create mode 100644 libc/include/error.h create mode 100644 tests/error_test.cpp diff --git a/libc/Android.mk b/libc/Android.mk index 71ddbd3f7..522d51483 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -112,6 +112,7 @@ libc_bionic_src_files := \ bionic/epoll_pwait.cpp \ bionic/epoll_wait.cpp \ bionic/__errno.cpp \ + bionic/error.cpp \ bionic/eventfd_read.cpp \ bionic/eventfd_write.cpp \ bionic/ffs.cpp \ diff --git a/libc/bionic/error.cpp b/libc/bionic/error.cpp new file mode 100644 index 000000000..9f4d0eef8 --- /dev/null +++ b/libc/bionic/error.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +unsigned int error_message_count = 0; +void (*error_print_progname)(void) = NULL; +int error_one_per_line = 0; + +static void __error_head() { + ++error_message_count; + + if (error_print_progname != NULL) { + error_print_progname(); + } else { + fflush(stdout); + fprintf(stderr, "%s:", getprogname()); + } +} + +static void __error_tail(int status, int error) { + if (error != 0) { + fprintf(stderr, ": %s", strerror(error)); + } + + putc('\n', stderr); + fflush(stderr); + + if (status != 0) { + exit(status); + } +} + +void error(int status, int error, const char* fmt, ...) { + __error_head(); + putc(' ', stderr); + + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + __error_tail(status, error); +} + +void error_at_line(int status, int error, const char* file, unsigned int line, const char* fmt, ...) { + if (error_one_per_line) { + static const char* last_file; + static unsigned int last_line; + if (last_line == line && last_file != NULL && strcmp(last_file, file) == 0) { + return; + } + last_file = file; + last_line = line; + } + + __error_head(); + fprintf(stderr, "%s:%d: ", file, line); + + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + __error_tail(status, error); +} diff --git a/libc/include/error.h b/libc/include/error.h new file mode 100644 index 000000000..dd1288442 --- /dev/null +++ b/libc/include/error.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ERROR_H +#define _ERROR_H 1 + +#include + +__BEGIN_DECLS + +void error(int, int, const char*, ...) __printflike(3, 4); +void error_at_line(int, int, const char*, unsigned int, const char*, ...) __printflike(5, 6); + +extern void (*error_print_progname)(void); +extern unsigned int error_message_count; +extern int error_one_per_line; + +__END_DECLS + +#endif diff --git a/tests/Android.mk b/tests/Android.mk index 87c330b21..9304d46a2 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -57,6 +57,7 @@ libBionicStandardTests_src_files := \ complex_test.cpp \ ctype_test.cpp \ dirent_test.cpp \ + error_test.cpp \ eventfd_test.cpp \ fcntl_test.cpp \ fenv_test.cpp \ diff --git a/tests/error_test.cpp b/tests/error_test.cpp new file mode 100644 index 000000000..5fee16f8d --- /dev/null +++ b/tests/error_test.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include "BionicDeathTest.h" + +static size_t g_test_error_print_progname_invocation_count; + +static void test_error_print_progname() { + ++g_test_error_print_progname_invocation_count; +} + +TEST(error, smoke) { + error_message_count = 0; + error(0, 0, "oops"); + ASSERT_EQ(1U, error_message_count); + error(0, ENOENT, "couldn't open file '%s'", "blah"); + ASSERT_EQ(2U, error_message_count); + + error_print_progname = test_error_print_progname; + g_test_error_print_progname_invocation_count = 0; + error(0, 0, "oops"); + ASSERT_EQ(1U, g_test_error_print_progname_invocation_count); + + error_at_line(0, 0, "blah.c", 123, "hello %s", "world"); + + error_print_progname = NULL; +} + +TEST(error_DeathTest, error_exit) { + ASSERT_EXIT(error(22, 0, "x%c", 'y'), ::testing::ExitedWithCode(22), "xy"); +} + +TEST(error_DeathTest, error_exit_with_errno) { + ASSERT_EXIT(error(22, EBADF, "x%c", 'y'), ::testing::ExitedWithCode(22), ": xy: Bad file descriptor"); +} + +TEST(error_DeathTest, error_at_line_exit) { + ASSERT_EXIT(error_at_line(22, 0, "a.c", 123, "x%c", 'y'), ::testing::ExitedWithCode(22), ":a.c:123: xy"); +} + +TEST(error_DeathTest, error_at_line_exit_with_errno) { + ASSERT_EXIT(error_at_line(22, EBADF, "a.c", 123, "x%c", 'y'), ::testing::ExitedWithCode(22), ":a.c:123: xy: Bad file descriptor"); +}