From 213d943a3372230b0a90563e9906dc66d6200320 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 1 Mar 2023 22:56:13 +0000 Subject: [PATCH] syslog.h: implement LOG_PERROR. This is the one openlog() flag that toybox uses. We should probably try to unify toybox's POSIX logger and Android-specific log at some point, and this will help. Also fix our behavior with an empty format string, noticed while adding tests. Test: treehugger Test: adb shell logger -s foo Change-Id: Ic027e78a460be3db83cc4c6f9946c9efa22be6e1 --- libc/bionic/syslog.cpp | 18 +++++++--- libc/include/syslog.h | 16 +++++---- tests/Android.bp | 1 + tests/syslog_test.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 tests/syslog_test.cpp diff --git a/libc/bionic/syslog.cpp b/libc/bionic/syslog.cpp index 6b17d268a..a459c6b1e 100644 --- a/libc/bionic/syslog.cpp +++ b/libc/bionic/syslog.cpp @@ -18,18 +18,22 @@ #include #include #include +#include #include static const char* syslog_log_tag = nullptr; static int syslog_priority_mask = 0xff; +static int syslog_options = 0; void closelog() { syslog_log_tag = nullptr; + syslog_options = 0; } -void openlog(const char* log_tag, int /*options*/, int /*facility*/) { +void openlog(const char* log_tag, int options, int /*facility*/) { syslog_log_tag = log_tag; + syslog_options = options; } int setlogmask(int new_mask) { @@ -73,10 +77,16 @@ void vsyslog(int priority, const char* fmt, va_list args) { android_log_priority = ANDROID_LOG_DEBUG; } - // We can't let async_safe_format_log do the formatting because it doesn't support - // all the printf functionality. + // We can't let async_safe_format_log do the formatting because it doesn't + // support all the printf functionality. char log_line[1024]; - vsnprintf(log_line, sizeof(log_line), fmt, args); + int n = vsnprintf(log_line, sizeof(log_line), fmt, args); + if (n < 0) return; async_safe_format_log(android_log_priority, log_tag, "%s", log_line); + if ((syslog_options & LOG_PERROR) != 0) { + bool have_newline = + (n > 0 && n < static_cast(sizeof(log_line)) && log_line[n - 1] == '\n'); + dprintf(STDERR_FILENO, "%s: %s%s", log_tag, log_line, have_newline ? "" : "\n"); + } } diff --git a/libc/include/syslog.h b/libc/include/syslog.h index d89d7695c..90ea76ef0 100644 --- a/libc/include/syslog.h +++ b/libc/include/syslog.h @@ -112,17 +112,21 @@ __BEGIN_DECLS */ #define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) -/** openlog() options are currently ignored on Android. */ +/** openlog() option ignored on Android. */ #define LOG_PID 0x01 -/** openlog() options are currently ignored on Android. */ +/** openlog() option ignored on Android. */ #define LOG_CONS 0x02 -/** openlog() options are currently ignored on Android. */ +/** openlog() option ignored on Android. */ #define LOG_ODELAY 0x04 -/** openlog() options are currently ignored on Android. */ +/** openlog() option ignored on Android. */ #define LOG_NDELAY 0x08 -/** openlog() options are currently ignored on Android. */ +/** openlog() option ignored on Android. */ #define LOG_NOWAIT 0x10 -/** openlog() options are currently ignored on Android. */ +/** + * openlog() option to log to stderr as well as the system log. + * + * Available since API level 34 (ignored before then). + */ #define LOG_PERROR 0x20 /** diff --git a/tests/Android.bp b/tests/Android.bp index 1be1ec3e4..281e29d6a 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -503,6 +503,7 @@ cc_test_library { "sys_vfs_test.cpp", "sys_wait_test.cpp", "sys_xattr_test.cpp", + "syslog_test.cpp", "system_properties_test.cpp", "system_properties_test2.cpp", "termios_test.cpp", diff --git a/tests/syslog_test.cpp b/tests/syslog_test.cpp new file mode 100644 index 000000000..3ec3337ce --- /dev/null +++ b/tests/syslog_test.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023 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 "utils.h" + +TEST(syslog, syslog_percent_m) { + ExecTestHelper eth; + eth.Run( + [&]() { + openlog("foo", LOG_PERROR, LOG_AUTH); + errno = EINVAL; + syslog(LOG_ERR, "a b c: %m"); + closelog(); + exit(0); + }, + 0, "foo: a b c: Invalid argument\n"); +} + +TEST(syslog, syslog_empty) { + ExecTestHelper eth; + eth.Run( + [&]() { + openlog("foo", LOG_PERROR, LOG_AUTH); + errno = EINVAL; + syslog(LOG_ERR, ""); + closelog(); + exit(0); + }, + 0, "foo: \n"); +} + +TEST(syslog, syslog_truncation) { + ExecTestHelper eth; + eth.Run( + [&]() { + openlog("bar", LOG_PERROR, LOG_AUTH); + char too_long[2048] = {}; + memset(too_long, 'x', sizeof(too_long) - 1); + syslog(LOG_ERR, "%s", too_long); + closelog(); + exit(0); + }, + 0, "bar: x{1023}\n"); +}