From 642f74de61987ddf7672ddfcff1303f4b70ce47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= Date: Thu, 11 Feb 2016 20:42:35 +0100 Subject: [PATCH] Feature: allow changing the identifier for syslog (+tests) Original "qb_log_ctl" interface had to be extended for passing read-only strings (new parameter), resulting in new "qb_log_ctl2" function, which is what qb_log_ctl calls into with the new parameter set to NULL. This ensures backward compatibility. A new QB_LOG_CONF_IDENT configuration directive for the mentioned interface is added with a goal to set new internal identifier that is, notably, used for syslog sink. This allows for switching the identification without a need to reinitialize logging subsystem, akin to changing target logging facility. Also a brand new concept of testing syslog sink in particular is introduced (finally). During initial trial&error stage, it used LD_PRELOAD hack but it seems that libtool is sophisticated enough that no such extra intervention is needed and the desired symbol resolution Just Works (tm). However, the technique is highly non-portable (there is even a warning about that from libtool, which is partially on purpose as the _syslog_override.so should rather be explicit it is by no mean a regular library) and hence the syslog tests have to be enabled with explicit ./configure --enable-syslog-tests rather than possibly break on untested platforms (far too many). The concept can be extended upon, but initially, just the new feature is being tested. Post-review: thanks Chrissie for a suggestion how to deal with extract-arg-and-forget in a less intrusive way (no defines). --- configure.ac | 12 ++++++++ include/qb/qblog.h | 25 ++++++++++++++++ lib/log.c | 34 ++++++++++++++++------ tests/Makefile.am | 7 +++++ tests/_syslog_override.c | 62 ++++++++++++++++++++++++++++++++++++++++ tests/_syslog_override.h | 34 ++++++++++++++++++++++ tests/check_log.c | 29 +++++++++++++++++++ 7 files changed, 194 insertions(+), 9 deletions(-) create mode 100644 tests/_syslog_override.c create mode 100644 tests/_syslog_override.h diff --git a/configure.ac b/configure.ac index 50e1549..3cd47ee 100644 --- a/configure.ac +++ b/configure.ac @@ -434,6 +434,12 @@ AC_ARG_ENABLE([slow-tests], [ --enable-slow-tests : build and run slow tests. ], [ default="no" ]) +if test x"$with_check" = xyes; then +AC_ARG_ENABLE([syslog-tests], + [ --enable-syslog-tests : build and run syslog tests. ], + [ default="no" ]) +fi + AC_ARG_WITH([socket-dir], [ --with-socket-dir=DIR : socket dir. ], [ SOCKETDIR="$withval" ], @@ -514,6 +520,12 @@ if test "x${enable_slow_tests}" = xyes ; then fi AM_CONDITIONAL(HAVE_SLOW_TESTS, [test "x${enable_slow_tests}" = xyes]) AC_SUBST(HAVE_SLOW_TESTS) +if test "x${enable_syslog_tests}" = xyes ; then + AC_DEFINE([HAVE_SYSLOG_TESTS], 1,[have syslog tests]) + AC_MSG_NOTICE([Enabling syslog tests]) +fi +AM_CONDITIONAL(HAVE_SYSLOG_TESTS, [test "x${enable_syslog_tests}" = xyes]) +AC_SUBST(HAVE_SYSLOG_TESTS) # --- callsite sections --- if test "x${GCC}" = xyes; then diff --git a/include/qb/qblog.h b/include/qb/qblog.h index 870cbae..0abb90e 100644 --- a/include/qb/qblog.h +++ b/include/qb/qblog.h @@ -420,6 +420,7 @@ enum qb_log_conf { QB_LOG_CONF_STATE_GET, QB_LOG_CONF_FILE_SYNC, QB_LOG_CONF_EXTENDED, + QB_LOG_CONF_IDENT, }; enum qb_log_filter_type { @@ -504,6 +505,30 @@ void qb_log_callsites_dump(void); */ int32_t qb_log_ctl(int32_t target, enum qb_log_conf conf_type, int32_t arg); +typedef union { + int32_t i32; + const char *s; +} qb_log_ctl2_arg_t; + +/** + * Extension of main logging control function accepting also strings. + * + * @param arg for QB_LOG_CONF_IDENT, 's' member as new identifier to openlog(), + * for all original qb_log_ctl-compatible configuration directives, + * 'i32' member is assumed (although a preferred way is to use + * that original function directly as it allows for more type safety) + * @see qb_log_ctl + * + * @note You can use QB_LOG_CTL2_I32 and QB_LOG_CTL2_S + * macros for a convenient on-the-fly construction of the object + * to be passed as an arg argument. + */ +int32_t qb_log_ctl2(int32_t target, enum qb_log_conf conf_type, + qb_log_ctl2_arg_t arg); + +#define QB_LOG_CTL2_I32(a) ((qb_log_ctl2_arg_t) { .i32 = (a) }) +#define QB_LOG_CTL2_S(a) ((qb_log_ctl2_arg_t) { .s = (a) }) + /** * This allows you modify the 'tags' and 'targets' callsite fields at runtime. */ diff --git a/lib/log.c b/lib/log.c index b6eb3ce..e851d89 100644 --- a/lib/log.c +++ b/lib/log.c @@ -1060,11 +1060,15 @@ _log_target_disable(struct qb_log_target *t) } int32_t -qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg) +qb_log_ctl2(int32_t t, enum qb_log_conf c, qb_log_ctl2_arg_t arg_not4directuse) { int32_t rc = 0; int32_t need_reload = QB_FALSE; + /* extract the constants and do not touch the origin anymore */ + const int32_t arg_i32 = arg_not4directuse.i32; + const char * const arg_s = arg_not4directuse.s; + if (!logger_inited) { return -EINVAL; } @@ -1074,7 +1078,7 @@ qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg) } switch (c) { case QB_LOG_CONF_ENABLED: - if (arg) { + if (arg_i32) { rc = _log_target_enable(&conf[t]); } else { _log_target_disable(&conf[t]); @@ -1084,33 +1088,39 @@ qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg) rc = conf[t].state; break; case QB_LOG_CONF_FACILITY: - conf[t].facility = arg; + conf[t].facility = arg_i32; + if (t == QB_LOG_SYSLOG) { + need_reload = QB_TRUE; + } + break; + case QB_LOG_CONF_IDENT: + (void)strlcpy(conf[t].name, arg_s, PATH_MAX); if (t == QB_LOG_SYSLOG) { need_reload = QB_TRUE; } break; case QB_LOG_CONF_FILE_SYNC: - conf[t].file_sync = arg; + conf[t].file_sync = arg_i32; break; case QB_LOG_CONF_PRIORITY_BUMP: - conf[t].priority_bump = arg; + conf[t].priority_bump = arg_i32; break; case QB_LOG_CONF_SIZE: if (t == QB_LOG_BLACKBOX) { - if (arg <= 0) { + if (arg_i32 <= 0) { return -EINVAL; } - conf[t].size = arg; + conf[t].size = arg_i32; need_reload = QB_TRUE; } else { return -ENOSYS; } break; case QB_LOG_CONF_THREADED: - conf[t].threaded = arg; + conf[t].threaded = arg_i32; break; case QB_LOG_CONF_EXTENDED: - conf[t].extended = arg; + conf[t].extended = arg_i32; break; default: @@ -1123,3 +1133,9 @@ qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg) } return rc; } + +int32_t +qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg) +{ + return qb_log_ctl2(t, c, QB_LOG_CTL2_I32(arg)); +} diff --git a/tests/Makefile.am b/tests/Makefile.am index aaeb415..807ae2e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -147,6 +147,13 @@ ipc_test_LDADD = $(top_builddir)/lib/libqb.la @CHECK_LIBS@ log_test_SOURCES = check_log.c $(top_builddir)/include/qb/qblog.h log_test_CFLAGS = @CHECK_CFLAGS@ -I$(top_srcdir)/include log_test_LDADD = $(top_builddir)/lib/libqb.la @CHECK_LIBS@ +if HAVE_SYSLOG_TESTS +log_test_LDADD += _syslog_override.la + +lib_LTLIBRARIES = _syslog_override.la +_syslog_override_la_SOURCES = _syslog_override.c +_syslog_override_la_LDFLAGS = -module +endif util_test_SOURCES = check_util.c $(top_builddir)/include/qb/qbutil.h util_test_CFLAGS = @CHECK_CFLAGS@ -I$(top_srcdir)/include diff --git a/tests/_syslog_override.c b/tests/_syslog_override.c new file mode 100644 index 0000000..0c3a809 --- /dev/null +++ b/tests/_syslog_override.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Jan Pokorny + * + * This file is part of libqb. + * + * libqb is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * libqb 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libqb. If not, see . + */ + +#include "_syslog_override.h" + +#include +#include + +int _syslog_opened = 0; +int _syslog_option = 0; +int _syslog_facility = 0; +char _syslog_ident[PATH_MAX] = ""; + +void openlog(const char *ident, int option, int facility); + +void +openlog(const char *ident, int option, int facility) +{ + _syslog_opened = 1; + _syslog_option = option; + _syslog_facility = facility; + strncpy(_syslog_ident, ident, sizeof(_syslog_ident)); +} + +void syslog(int priority, const char *format, ...); + +void +syslog(int priority, const char *format, ...) +{ + _syslog_opened = 1; +} + +void closelog(void); + +void +closelog(void) +{ + _syslog_opened = 0; + _syslog_option = -1; + _syslog_facility = -1; + _syslog_ident[0] = '\0'; +} diff --git a/tests/_syslog_override.h b/tests/_syslog_override.h new file mode 100644 index 0000000..7b254ae --- /dev/null +++ b/tests/_syslog_override.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016 Red Hat, Inc. + * + * All rights reserved. + * + * Author: Jan Pokorny + * + * This file is part of libqb. + * + * libqb is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 of the License, or + * (at your option) any later version. + * + * libqb 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libqb. If not, see . + */ + +#ifndef QB_SYSLOG_OVERRIDE_H_DEFINED +#define QB_SYSLOG_OVERRIDE_H_DEFINED + +#include + +extern int _syslog_opened; +extern int _syslog_option; +extern int _syslog_facility; +extern char _syslog_ident[PATH_MAX]; + +#endif diff --git a/tests/check_log.c b/tests/check_log.c index 56c9305..d7ac70b 100644 --- a/tests/check_log.c +++ b/tests/check_log.c @@ -29,6 +29,10 @@ #include #include +#ifdef HAVE_SYSLOG_TESTS +#include "_syslog_override.h" +#endif + extern size_t qb_vsnprintf_serialize(char *serialize, size_t max_len, const char *fmt, va_list ap); extern size_t qb_vsnprintf_deserialize(char *string, size_t strlen, const char *buf); @@ -765,6 +769,25 @@ START_TEST(test_extended_information) } END_TEST +#ifdef HAVE_SYSLOG_TESTS +START_TEST(test_syslog) +{ + qb_log_init("flip", LOG_USER, LOG_INFO); + qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE); + + qb_log(LOG_ERR, "first as flip"); + ck_assert_int_eq(_syslog_opened, 1); + ck_assert_str_eq(_syslog_ident, "flip"); + + qb_log_ctl2(QB_LOG_SYSLOG, QB_LOG_CONF_IDENT, QB_LOG_CTL2_S("flop")); + qb_log(LOG_ERR, "second as flop"); + ck_assert_str_eq(_syslog_ident, "flop"); + + qb_log_fini(); +} +END_TEST +#endif + static Suite * log_suite(void) { @@ -812,6 +835,12 @@ log_suite(void) tcase_add_test(tc, test_extended_information); suite_add_tcase(s, tc); +#ifdef HAVE_SYSLOG_TESTS + tc = tcase_create("syslog"); + tcase_add_test(tc, test_syslog); + suite_add_tcase(s, tc); +#endif + return s; }