Skip to content

Commit

Permalink
Med: add extra run-time (client, libqb) checks that logging will work
Browse files Browse the repository at this point in the history
Now that the previous commit provides a foundation for what exactly can
go wrong with ld.bfd = 2.29+ linker, let's start reconciling that with
 some reasonable assurance that logging is not silently severed, because
realizing the logs are missing is otherwise bound to happen when the
logs are suddently pretty crucial analytical resource :-)
We'll proceed in two steps as detailed.

* * *

As a first step, the table below concludes how the test matrix overview
introduced with a message for the preceding commit (also introducing
log_test_mock.sh runner which got reused here) looks as of this
refreshed sanity check, once QB_LOG_INIT_DATA macro at hand gets applied
(meaning "for non-libqb logging participants" so as not complicate the
matrix further).  That macro is nothing triggered directly, it will just
plant a constructor-like function (to be invoked automatically early in
the execution) that will run through the checks (one original and couple
of new ones as of this changeset).

Note that for libqb users, this implies a new link dependency on libdl,
because they may opt-in for refreshed QB_LOG_INIT_DATA sanity check that
calls out to dlopen/dlsym/dladdr directly in case of "attribute section"
being available for the particular platform, and hence immediately needs
those symbols resolved in link time.  Hence, add this conditional link
dependency to libqb.pc pkg-config file under Libs variable -- we
actually restore the occurrence of "-ldl" there as it used to be present
until commit 56754d0.  While doing so, also move immediate link
dependencies of libqb (if any, currently not but that may be
a regression arising from the cleanup related to the mentioned commit)
represented with the LIBS autoconf variable under Libs.private variable
in libqb.pc, where it belongs per pkg-config documentation.

The promised table follows, but first as a recap, "X(Y)" denotes
"X linked with linker Y":
  X(a) .. ld.bfd < 2.29
  X(b) .. ld.bfd = 2.29 (and only 2.29)

goes like this (values in <angle brackets> denote non-trivial change
[not mere rewording] introduced as of this commit, in comparison to
the table stated in the preceding commit):

+=========+=========+=========+=========+=========+=========+=========+
#client(x)#        libqb(a) usage       #        libqb(b) usage       #
#   vvv   #---------+---------+---------+---------+---------+---------+
#    V    #  direct | libX(a) : libX(b) #  direct | libX(a) : libX(b) #
+=========+=========+=========+=========+=========+=========+=========+
#  x = a  #   OK    |   OK    : BAD[*2] #<BAD[*E]>|<BAD[*F]>:<BAD[*G]>#
#  x = b  # BAD[*A] | BAD[*B] : BAD[*C] #<BAD[*E]>|<BAD[*F]>:<BAD[*G]>#
+=========+=========+=========+=========+=========+=========+=========+

Woefully, nothing changes if we swap binutils 2.29 for 2.29.1, i.e.,
X(b) .. ld.bfd = 2.29.1, compared to previous state, i.e., the second
table from the previous commit is still applicable for that situation.
The added sanity checks are useful nonetheless, consider for example,
that attribute-section-less libqb is what gets run-time linked to an
attribute-section-full target.  The most precise check we could use
-- a custom logger function applied in a self-test scheme -- is not
available at the point the macro-defined function gets invoked, simply
because qb_log_init hasn't been invoked by the time that constructor
gets triggered.  However, what we can do is to add a non-trapping
libqb-residing reverse-testing of the client space that (and once it)
voluntarily initiates qb_log_init (delivering abruption all of a sudden
at some unanticipated, as opposed to a well-timed like with
constructors, execution point, seems pretty bad idea + libqb as
a library is a mere helper, not an undertaker :) -- this check then
only announces, via syslog (the only pre-enabled logging target),
the target's logging may be severed.

* * *

Hence, as a promised second step, after incorporating the syslog
change (and extending log_test_mock.sh so as to capture syslog
stream within the container), not much changes with the table above,
i.e., X(b) .. ld.bfd = 2.29:
[*A] in addition, unless QB_LOG_INIT_DATA used on client side,
     syslog carries this notice:
  "(libqb) log module hasn't observed target chain supplied callsite
   section, target's and/or libqb's build is at fault, preventing
   reliable logging (unless qb_log_init invoked in no-custom-logging
   context unexpectedly, or target chain built purposefully without
   these sections)"
     logged by libqb proper
[*C] in addition, unless QB_LOG_INIT_DATA used on interlib side,
     syslog carries this notice:
  "(libqb) log module hasn't observed target chain supplied callsite
   section, target's and/or libqb's build is at fault, preventing
   reliable logging (unless qb_log_init invoked in no-custom-logging
   context unexpectedly, or target chain built purposefully without
   these sections)"
     logged by libqb proper
[*E] in addition, unless QB_LOG_INIT_DATA used on client side,
     syslog carries this warning:
  "(libqb) log module has observed target chain supplied section
   unpopulated, target's and/or libqb's build is at fault, preventing
   reliable logging (unless qb_log_init invoked in no-custom-logging
   context unexpectedly)"
     logged by libqb proper
[*F] in addition, unless QB_LOG_INIT_DATA used on interlib side,
     syslog carries this warning:
  "(libqb) log module has observed target chain supplied section
   unpopulated, target's and/or libqb's build is at fault, preventing
   reliable logging (unless qb_log_init invoked in no-custom-logging
   context unexpectedly)"
     logged by libqb proper
[*G] in addition, unless QB_LOG_INIT_DATA used on interlib side,
     syslog carries this warning:
  "(libqb) log module has observed target chain supplied section
   unpopulated, target's and/or libqb's build is at fault, preventing
   reliable logging (unless qb_log_init invoked in no-custom-logging
   context unexpectedly)"
     logged by libqb proper

but desirably changes with "X(b) .. ld.bfd = 2.29.1" one
(DEP ~ "depends"):

+=========+=========+=========+=========+=========+=========+=========+
#client(x)#        libqb(a) usage       #        libqb(b) usage       #
#   vvv   #---------+---------+---------+---------+---------+---------+
#    V    #  direct | libX(a) : libX(b) #  direct | libX(a) : libX(b) #
+=========+=========+=========+=========+=========+=========+=========+
#  x = a  #   OK    |   OK    : DEP[*J] #<BAD[*M]>|<BAD[*M]>:<BAD[*L]>#
#  x = b  #<DEP[*N]>| DEP[*I] :<DEP[*O]>#<BAD[*M]>|<BAD[*M]>:<BAD[*L]>#
+=========+=========+=========+=========+=========+=========+=========+

* * *

[*1] client logging not working
[*2] interlib logging not working
[*3] both client and interlib logging not working

[*A] boils down to [*1], unless QB_LOG_INIT_DATA used on client side,
     which then fails on
  "implicit callsite section is populated, otherwise target's build
   is at fault, preventing reliable logging"
     assertion
[*B] boils down to [*1], unless QB_LOG_INIT_DATA used on interlib side,
     which then fails on
  "implicit callsite section is populated, otherwise target's build
   is at fault, preventing reliable logging"
     assertion
[*C] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side,
     which then fails on
  "implicit callsite section is populated, otherwise target's build
   is at fault, preventing reliable logging"
     assertion
[*E] boils down to [*1], unless QB_LOG_INIT_DATA used on client side,
     which then fails on
  "implicit callsite section is self-observable, otherwise target's
   and/or libqb's build is at fault, preventing reliable logging"
     assertion
[*F] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side,
     which then fails on
  "libqb's callsite section is populated, otherwise libqb's build is
   at fault, preventing reliable logging"
     assertion
[*G] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side,
     which then fails on
  "implicit callsite section is self-observable, otherwise target's
   and/or libqb's build is at fault, preventing reliable logging"
     assertion

[*I] boils down to [*1], unless QB_LOG_INIT_DATA used on client side,
     which makes it, likely through self-reference keepalive (see
     below), work OK
[*J] boils down to [*2], unless QB_LOG_INIT_DATA used on interlib side,
     which makes it, likely through self-reference keepalive (see
     below), work OK
[*K] boils down to [*3]
     in addition, syslog carries this notice:
  "(libqb) log module hasn't observed target chain supplied callsite
   section, target's and/or libqb's build is at fault, preventing
   reliable logging (unless qb_log_init invoked in no-custom-logging
   context unexpectedly, or target chain built purposefully without
   these sections)"
     logged by libqb proper
[*L] boils down to [*3], unless QB_LOG_INIT_DATA used on interlib side
     (sufficient?), which makes it, likely through self-reference
     keepalive (see below), boil down just to [*1];
     in addition, syslog carries this notice:
  "(libqb) log module hasn't observed target chain supplied callsite
   section, target's and/or libqb's build is at fault, preventing
   reliable logging (unless qb_log_init invoked in no-custom-logging
   context unexpectedly, or target chain built purposefully without
   these sections)"
     logged by libqb proper
[*M] boils down to [*1];
     in addition, syslog carries this notice:
  "(libqb) log module hasn't observed target chain supplied callsite
   section, target's and/or libqb's build is at fault, preventing
   reliable logging (unless qb_log_init invoked in no-custom-logging
   context unexpectedly, or target chain built purposefully without
   these sections)"
     logged by libqb proper
[*N] boils down to [*M], unless QB_LOG_INIT_DATA used on client side,
     which makes it, likely through self-reference keepalive (see
     below), work OK
[*O] boils down to [*K], unless QB_LOG_INIT_DATA used on both client
     and interlib side, which makes it, likely through self-reference
     keepalive (see below), work OK  (it's expected that this a mere
     composite of situations [*I] and [*J] with consequences as stated)

* * *

Note: the only problematic (i.e. not captured automatically by the
QB_LOG_INIT_DATA macro presumably utilized at every non-libqb logging
system participant in the form of a discrete compilation unit)
combination with 2.29 is the one intersecting at "BAD[*2]" pertaining
"everything but interlib compiled with ld.bfd < 2.29".  It would, of
course, be solvable as well, but presumably not in an easy way, and
that use case should not be as frequent.

Takeway: whenever your target (library or client program) actively
utilizes logging (meaning it emits at least a single log message,
otherwise there's an imminent danger of possibly even run-terminating
false positive in the self-check mechanism!),

  YOU ARE strongly ENCOURAGED TO USE QB_LOG_INIT_DATA macro function
  at (exactly) one of the source code files (presumably the main one)
  per respective target's compilation unit.

It will alleviate the hassles possibly caused by downgrading libqb
to the linker-vs-libqb incompatibly compiled one or in similar
circumstances arising merely from the linker behaviour change,
which the current build system/code shake is all about.

Signed-off-by: Jan Pokorný <[email protected]>
  • Loading branch information
jnpkrn committed Dec 12, 2017
1 parent 32555d8 commit cdb0269
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 35 deletions.
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ if test "x${GCC}" = xyes; then
AC_DEFINE([QB_HAVE_ATTRIBUTE_SECTION], 1,
[Enabling code using __attribute__((section))])
PACKAGE_FEATURES="$PACKAGE_FEATURES attribute-section"
AC_SUBST([client_dlopen_LIBS],[$dlopen_LIBS])
fi
fi

Expand Down
108 changes: 80 additions & 28 deletions include/qb/qblog.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/*
* Copyright (C) 2010 Red Hat, Inc.
* Copyright 2017 Red Hat, Inc.
*
* All rights reserved.
*
* Author: Angus Salkeld <[email protected]>
* Jan Pokorny <[email protected]>
*
* 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
Expand Down Expand Up @@ -44,6 +45,7 @@ extern "C" {

#ifdef QB_HAVE_ATTRIBUTE_SECTION
#include <assert.h> /* possibly needed for QB_LOG_INIT_DATA */
#include <dlfcn.h> /* dynamic linking: dlopen, dlsym, dladdr, ... */
#endif

/**
Expand All @@ -70,14 +72,14 @@ extern "C" {
*
* @note
* In practice, such a minimalistic approach hardly caters real use cases.
* Following section discusses the customization. Moreover, it's quite
* vital to instrument the target user of this logging subsystem with
* @c QB_LOG_INIT_DATA() macro placed in the top file scope in an exactly
* one source file (preferably the main one) to be mixed into the resulting
* compilation unit. This is a self-defensive measure for when the
* linker-assisted collection of callsite data silently fails, which
* could otherwise go unnoticed, causing troubles down the road.
*
* Following section discusses the customization. Moreover when employing
* the log module is bound to its active use (some log messages are assuredly
* emitted within the target compilation unit), it's quite vital to instrument
* the target side with @c QB_LOG_INIT_DATA() macro placed in the top file
* scope in exactly one source file (preferably the main one) to be mixed into
* the resulting compilation unit. This is a self-defensive measure for when
* the linker-assisted collection of callsite data silently fails, which could
* otherwise go unnoticed, causing troubles down the road.
*
* @par Configuring log targets.
* A log target can be syslog, stderr, the blackbox, stdout, or a text file.
Expand Down Expand Up @@ -283,35 +285,85 @@ typedef void (*qb_log_filter_fn)(struct qb_log_callsite * cs);
extern struct qb_log_callsite QB_ATTR_SECTION_START[];
extern struct qb_log_callsite QB_ATTR_SECTION_STOP[];

/* optional on-demand self-check of 1/ toolchain sanity (prerequisite for
the logging subsystem to work properly) and 2/ non-void active use of
logging (satisfied with a justifying existence of a logging callsite as
defined with a @c qb_logt invocation) at the target (but see below), which
is supposedly assured by it's author(!) as of relying on this very macro
[technically, the symbols that happen to be resolved under the respective
identifiers do not necessarily originate in the same compilation unit as
when it's not the end executable (or by induction, a library positioned
earlier in the symbol lookup order) but a shared library, the former takes
a precedence unless that site comes short of exercising the logging,
making its callsite section empty and, in turn, without such boundary
symbols, hence making the resolution continue further in the lookup order
-- despite fuzzily targeted attestation, the check remains reasonable];
only effective when link-time ("run-time amortizing") callsite collection
is; as a side effect, it can ensure the boundary-denoting symbols for the
target collection area are kept alive with some otherwise unkind linkers;
may be extended in future for more in-depth self-validation */
/* Related to the next macro that is -- unlike this one -- a public API */
#ifndef _GNU_SOURCE
#define QB_NONAPI_LOG_INIT_DATA_EXTRA_ \
_Pragma(QB_PP_STRINGIFY(GCC warning QB_PP_STRINGIFY( \
without "_GNU_SOURCE" defined (directly or not) \
QB_LOG_INIT_DATA cannot check sanity of libqb proper)))
#else
#define QB_NONAPI_LOG_INIT_DATA_EXTRA_ \
{ Dl_info work_dli; \
/* libqb sanity (locating libqb by it's relatively unique \
-- and currently only such per-linkage global one -- \
non-functional symbol, due to possible confusion otherwise) */ \
if (dladdr(dlsym(RTLD_DEFAULT, "facilitynames"), &work_dli) \
&& (work_handle = dlopen(work_dli.dli_fname, \
RTLD_LOCAL|RTLD_LAZY)) != NULL) { \
work_s1 = (struct qb_log_callsite *) \
dlsym(work_handle, QB_ATTR_SECTION_START_STR); \
work_s2 = (struct qb_log_callsite *) \
dlsym(work_handle, QB_ATTR_SECTION_STOP_STR); \
assert("libqb's callsite section is observable, otherwise \
libqb's build is at fault, preventing reliable logging" \
&& work_s1 != NULL && work_s2 != NULL); \
assert("libqb's callsite section is populated, otherwise \
libqb's build is at fault, preventing reliable logging" \
&& work_s1 != work_s2); \
dlclose(work_handle); } }
#endif /* _GNU_SOURCE */

/**
* Optional on-demand self-check of 1/ toolchain sanity (prerequisite for
* the logging subsystem to work properly) and 2/ non-void active use of
* logging (satisfied with a justifying existence of a logging callsite as
* defined with a @c qb_logt invocation) at the target (but see below), which
* is supposedly assured by it's author(!) as of relying on this very macro
* [technically, the symbols that happen to be resolved under the respective
* identifiers do not necessarily originate in the same compilation unit as
* when it's not the end executable (or by induction, a library positioned
* earlier in the symbol lookup order) but a shared library, the former takes
* a precedence unless that site comes short of exercising the logging,
* making its callsite section empty and, in turn, without such boundary
* symbols, hence making the resolution continue further in the lookup order
* -- despite fuzzily targeted attestation, the check remains reasonable];
* only effective when link-time ("run-time amortizing") callsite collection
* is; as a side effect, it can ensure the boundary-denoting symbols for the
* target collection area are kept alive with some otherwise unkind linkers.
*
* Applying this macro in the target program/library is strongly recommended
* whenever the logging as framed by this header file is in use.
* Moreover, it's important to state that using this check while not ensuring
* @c _GNU_SOURCE macro definition is present at compile-time means only half
* of the available sanity checking will be performed, possibly resulting
* in libqb's own internally logged messages being lost without warning.
*/
#define QB_LOG_INIT_DATA(name) \
void name(void); \
void name(void) { \
void *work_handle; struct qb_log_callsite *work_s1, *work_s2; \
/* our own (target's) sanity, or possibly that of higher priority \
symbol resolution site (unless target equals end executable) \
or even the lower one if no such predecessor defines these */ \
assert("implicit callsite section is populated" \
if ((work_handle = dlopen(NULL, RTLD_LOCAL|RTLD_LAZY)) != NULL) { \
work_s1 = (struct qb_log_callsite *) \
dlsym(work_handle, QB_ATTR_SECTION_START_STR); \
work_s2 = (struct qb_log_callsite *) \
dlsym(work_handle, QB_ATTR_SECTION_STOP_STR); \
assert("implicit callsite section is observable, otherwise \
target's and/or libqb's build is at fault, preventing reliable logging" \
&& work_s1 != NULL && work_s2 != NULL); \
dlclose(work_handle); /* perhaps overly eager thing to do */ } \
/* better targeted attestations when available */ \
QB_NONAPI_LOG_INIT_DATA_EXTRA_; \
/* finally, original, straightforward check */ \
assert("implicit callsite section is populated, otherwise \
target's build is at fault, preventing reliable logging" \
&& QB_ATTR_SECTION_START != QB_ATTR_SECTION_STOP); } \
void __attribute__ ((constructor)) name(void);
#else
#define QB_LOG_INIT_DATA(name)
#endif
#endif /* QB_HAVE_ATTRIBUTE_SECTION */

/**
* Internal function: use qb_log() or qb_logt()
Expand Down
3 changes: 2 additions & 1 deletion lib/libqb.pc.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ Name: libqb
Version: @PACKAGE_VERSION@
Description: libqb
Requires:
Libs: -L${libdir} -lqb @LIBS@
Libs: -L${libdir} -lqb @client_dlopen_LIBS@
Libs.private: @LIBS@
Cflags: -I${includedir}
51 changes: 51 additions & 0 deletions lib/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,18 @@ qb_log_init(const char *name, int32_t facility, uint8_t priority)
{
int32_t l;
enum qb_log_target_slot i;
#ifdef QB_HAVE_ATTRIBUTE_SECTION
void *work_handle; struct qb_log_callsite *work_s1, *work_s2;
Dl_info work_dli;
#endif /* QB_HAVE_ATTRIBUTE_SECTION */
/* cannot reuse single qb_log invocation in various contexts
through the variables (when section attribute in use),
hence this indirection */
enum {
preinit_err_none,
preinit_err_target_sec,
preinit_err_target_empty,
} preinit_err = preinit_err_none;

l = pthread_rwlock_init(&_listlock, NULL);
assert(l == 0);
Expand All @@ -871,6 +883,26 @@ qb_log_init(const char *name, int32_t facility, uint8_t priority)

qb_log_dcs_init();
#ifdef QB_HAVE_ATTRIBUTE_SECTION
/* sanity check that target chain supplied QB_ATTR_SECTION_ST{ART,OP}
symbols and hence the local references to them are not referencing
the proper libqb's ones (locating libqb-self by it's relatively
unique -- and currently only such per-linkage global one --
non-functional symbol, due to possible confusion otherwise) */
if (dladdr(dlsym(RTLD_DEFAULT, "facilitynames"), &work_dli)
&& (work_handle = dlopen(work_dli.dli_fname,
RTLD_LOCAL|RTLD_LAZY)) != NULL) {
work_s1 = (struct qb_log_callsite *)
dlsym(work_handle, QB_ATTR_SECTION_START_STR);
work_s2 = (struct qb_log_callsite *)
dlsym(work_handle, QB_ATTR_SECTION_STOP_STR);
if (work_s1 == QB_ATTR_SECTION_START
|| work_s2 == QB_ATTR_SECTION_STOP) {
preinit_err = preinit_err_target_sec;
} else if (work_s1 == work_s2) {
preinit_err = preinit_err_target_empty;
}
dlclose(work_handle); /* perhaps overly eager thing to do */
}
qb_log_callsites_register(QB_ATTR_SECTION_START, QB_ATTR_SECTION_STOP);
dl_iterate_phdr(_log_so_walk_callback, NULL);
_log_so_walk_dlnames();
Expand All @@ -884,6 +916,25 @@ qb_log_init(const char *name, int32_t facility, uint8_t priority)
_log_target_state_set(&conf[QB_LOG_SYSLOG], QB_LOG_STATE_ENABLED);
(void)qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, "*", priority);

if (preinit_err == preinit_err_target_sec)
qb_util_log(LOG_NOTICE, "(libqb) log module hasn't observed"
" target chain supplied callsite"
" section, target's and/or libqb's"
" build is at fault, preventing"
" reliable logging (unless qb_log_init"
" invoked in no-custom-logging context"
" unexpectedly, or target chain built"
" purposefully without these sections)");
else if (preinit_err == preinit_err_target_empty) {
qb_util_log(LOG_WARNING, "(libqb) log module has observed"
" target chain supplied section"
" unpopulated, target's and/or libqb's"
" build is at fault, preventing"
" reliable logging (unless qb_log_init"
" invoked in no-custom-logging context"
" unexpectedly)");
}
}

void
Expand Down
3 changes: 2 additions & 1 deletion tests/functional/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = GNUmakefile log_test_client.err log_test_interlib_client.err \
log_test_client.sh log_test_interlib_client.sh log_test_mock.sh \
log_test_client.sh log_test_interlib_client.sh \
log_test_mock.sh syslog-stdout.py \
log_callsite_bench_gen.py
SUBDIRS = log_external log_internal
2 changes: 1 addition & 1 deletion tests/functional/log.am
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ MAINTAINERCLEANFILES = Makefile.in
CLEANFILES = log_test_client.err.real log_test_interlib_client.err.real \
../log_callsite_bench.c

AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_builddir)/include -I$(top_srcdir)/include

noinst_PROGRAMS = log_client log_interlib_client
# cannot use {check,noinst}_LTLIBRARIES because it leads to solely static lib
Expand Down
8 changes: 6 additions & 2 deletions tests/functional/log_external/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@

include ../log.am

log_client_LDFLAGS = -lqb
liblog_inter_la_LIBADD = -lqb
# while linking with system-wide version of libqb, we are still pursuing
# local in-tree header file, hence we need to link with dynamic linking
# library (which is a prerequisite for using QB_LOG_INIT_DATA defined
# in qblog.h) explicitly
log_client_LDFLAGS = -lqb @client_dlopen_LIBS@
liblog_inter_la_LIBADD = -lqb @client_dlopen_LIBS@

# extras for log_external: comparable, generated callsite-heavy logging clients

Expand Down
13 changes: 11 additions & 2 deletions tests/functional/log_test_mock.sh
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,19 @@ do_compile_and_test_client () {
-exec rm -- {} \;"
;;
esac
mock ${mock_args} --copyin "syslog-stdout.py" "builddir"
mock ${mock_args} --shell "( cd \"builddir/build/BUILD/$1\"; ./configure )"
mock ${mock_args} --shell \
"make -C \"builddir/build/BUILD/$1/tests/functional/log_external\" \
check-TESTS \"TESTS=../${_logfile}.sh\" $5" \
"python3 builddir/syslog-stdout.py \
>\"builddir/build/BUILD/$1/tests/functional/log_external/.syslog\" & \
{ sleep 2; make -C \"builddir/build/BUILD/$1/tests/functional/log_external\" \
check-TESTS \"TESTS=../${_logfile}.sh\" $5; } \
&& ! test -s \"builddir/build/BUILD/$1/tests/functional/log_external/.syslog\"; \
ret_ec=\$?; \
( cd \"builddir/build/BUILD/$1/tests/functional/log_external\"; \
cat .syslog >> test-suite.log; \
echo SYSLOG-begin; cat .syslog; echo SYSLOG-end ); \
ret () { return \$1; }; ret \${ret_ec}" \
&& _result="${_result}_good" \
|| _result="${_result}_bad"
mock ${mock_args} --copyout \
Expand Down
51 changes: 51 additions & 0 deletions tests/functional/syslog-stdout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/python3
# Copyright 2017 Red Hat, Inc.
#
# Author: Jan Pokorny <[email protected]>
#
# 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 <http://www.gnu.org/licenses/>.

"""Simple /dev/log to stdout forwarding"""

import socket
from atexit import register
from os import remove
from sys import argv

# no locking, but anyway
try:
remove("/dev/log")
except FileNotFoundError:
pass
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind("/dev/log")

def shutdown():
sock.close()
remove("/dev/log")

def main(*argv):
register(shutdown)
while True:
try:
b = sock.recv(4096)
# flushing is crucial here
print(">>> " + str(b, 'ascii').split(' ', 3)[-1], flush=True)
except IOError:
pass

if __name__ == '__main__':
main(*argv)

0 comments on commit cdb0269

Please sign in to comment.