summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore16
-rw-r--r--.travis.yml8
-rw-r--r--NEWS33
-rw-r--r--README.rst14
-rw-r--r--configure.ac9
-rw-r--r--lib/Makefile.am13
-rw-r--r--lib/buffer.c51
-rw-r--r--lib/libumberlog.ld5
-rw-r--r--lib/umberlog.c40
-rw-r--r--lib/umberlog.h1
-rw-r--r--lib/umberlog.rst8
-rw-r--r--t/Makefile.am4
-rw-r--r--t/test_umberlog.c104
13 files changed, 245 insertions, 61 deletions
diff --git a/.gitignore b/.gitignore
index c8e9623..2f00815 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,17 +1,33 @@
/config.guess
/config.sub
/config.h.in
+/config.h
+/config.status
+/config.log
/configure
/configure.scan
/depcomp
/install-sh
+/libtool
+/stamp-*
/ltmain.sh
/missing
/aclocal.m4
/autom4te.cache
/m4
Makefile.in
+Makefile
*~
+.deps/
+.libs/
+*.o
+*.lo
+*.la
+core
+/lib/libumberlog.pc
+/lib/umberlog.3
+/t/test_perf
+/t/test_umberlog
/debian/autoreconf.*
/debian/build-tree/
/debian/files
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..db9129c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: c
+install: sudo apt-get install libjson0-dev check python-docutils
+before_script:
+ - ./autogen.sh
+script:
+ - ./configure
+ - make
+ - make check
diff --git a/NEWS b/NEWS
index 607bb6f..14311e0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,37 @@
#+STARTUP: indent showall -*- org -*-
-* 0.2.0
+* 0.2.1 - <2012-05-02 Wed>
+
+** Fixed JSON formatting for syslog() messages
+
+In version 0.2.0, when converting to formatting the JSON output
+ourselves, a bug creeped in that made the library emit invalid JSON
+when used as an LD_PRELOAD-ed library.
+
+This has been corrected.
+
+** Facility and priority values are handled properly
+
+In all versions of the library the facility and priority handling was
+broken for all but the most trivial cases. This version fixes this
+issue aswell.
+
+** Previous openlog() settings are cleared at closelog() time
+
+In all former versions of the library, openlog() collected a set of
+information that was then used by all other functions, even after
+closelog() was called.
+
+Closing the log should return us to the default state, so we now wrap
+closelog() too, and the library resets its settings to their default.
+
+** Noticable performance increase
+
+The library was changed to try and do less memory allocations, and
+reuse memory instead of a malloc/free cycle. This results in a
+noticable performance increase under heavy load.
+
+* 0.2.0 - <2012-04-16 Mon>
** Remove the json-c dependency
diff --git a/README.rst b/README.rst
index 3147295..5e2b792 100644
--- a/README.rst
+++ b/README.rst
@@ -54,11 +54,15 @@ SSH Login::
Requirements
------------
-Apart from the autotools, a C compiler, and `json\-c`_ (for the test
-suite), there are no other hard dependencies when building, except for
-a sufficiently modern system.
+Apart from the autotools, a C compiler, there are no other
+dependencies when building, except for a sufficiently modern system.
+
+The test suite requires `json\-c`_ and `check`_ too, and `docutils`_
+is required to build the documentation.
.. _json\-c: http://oss.metaparadigm.com/json-c/
+.. _check: http://check.sourceforge.net/
+.. _docutils: http://docutils.sourceforge.net/
Installation
------------
@@ -72,6 +76,8 @@ The library follows the usual autotools way of installation:
$ ./autogen.sh
$ ./configure && make && make install
+.. image:: https://secure.travis-ci.org/algernon/libumberlog.png?branch=master
+
Usage
-----
@@ -96,7 +102,7 @@ Non-goals
matter how reliable this information may be.
* It is not a goal to support complex values, or anything other than
plain C strings.
-
+
License
-------
diff --git a/configure.ac b/configure.ac
index 4717dd4..a3cf642 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
dnl Process this file with autoconf to produce a configure script.
dnl
-AC_INIT(libumberlog, 0.1.2, algernon@balabit.hu, libumberlog, https://github.com/algernon/libumberlog)
+AC_INIT(libumberlog, 0.2.1, algernon@balabit.hu, libumberlog, https://github.com/algernon/libumberlog)
AM_INIT_AUTOMAKE([1.9 tar-ustar])
dnl ***************************************************************************
@@ -24,6 +24,7 @@ AC_PROG_RANLIB
AM_PROG_CC_STDC
AC_PROG_MAKE_SET
PKG_PROG_PKG_CONFIG
+AC_PATH_PROG([RST2MAN], [rst2man])
LT_INIT([shared])
dnl ***************************************************************************
@@ -54,9 +55,12 @@ AC_SEARCH_LIBS([clock_gettime], [rt], [], [
])
dnl ***************************************************************************
-dnl JSON-C headers/libraries
+dnl Libraries for the test suite
dnl ***************************************************************************
PKG_CHECK_MODULES(JSON, json >= $JSON_C_MIN_VERSION,[enable_tests="1"],[enable_tests="0"])
+if test "x$enable_tests" = "x1"; then
+ PKG_CHECK_MODULES(CHECK, check, [enable_tests="1"],[enable_tests="0"])
+fi
dnl ***************************************************************************
dnl misc features to be enabled
@@ -72,6 +76,7 @@ AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [package name])
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [version number])
AM_CONDITIONAL(ENABLE_TESTS, [test "$enable_tests" = "1"])
+AM_CONDITIONAL(ENABLE_MANS, [test "x$RST2MAN" != "x"])
AC_OUTPUT(
Makefile
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 169b0b2..b6b60b3 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,6 +1,6 @@
-LUL_CURRENT = 1
+LUL_CURRENT = 2
LUL_REVISION = 0
-LUL_AGE = 0
+LUL_AGE = 1
lib_LTLIBRARIES = libumberlog.la
libumberlog_la_LDFLAGS = -Wl,--version-script,${srcdir}/libumberlog.ld \
@@ -15,3 +15,12 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libumberlog.pc
EXTRA_DIST = umberlog.rst libumberlog.ld
+
+if ENABLE_MANS
+man3_MANS = umberlog.3
+CLEANFILES = umberlog.3
+EXTRA_DIST += umberlog.3
+
+umberlog.3: umberlog.rst
+ $(AM_V_GEN) $(RST2MAN) $< $@
+endif
diff --git a/lib/buffer.c b/lib/buffer.c
index 8bdb3ef..ef448bf 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -54,11 +54,20 @@ static const unsigned char json_exceptions[] =
0xff, '\0'
};
+static __thread ul_buffer_t escape_buffer;
+
+static void ul_buffer_finish (void) __attribute__((destructor));
+
+static void
+ul_buffer_finish (void)
+{
+ free (escape_buffer.msg);
+}
+
static inline char *
-_ul_str_escape (const char *str)
+_ul_str_escape (const char *str, char *dest, size_t *length)
{
const unsigned char *p;
- char *dest;
char *q;
static unsigned char exmap[256];
static int exmap_inited;
@@ -67,7 +76,7 @@ _ul_str_escape (const char *str)
return NULL;
p = (unsigned char *)str;
- q = dest = malloc (strlen (str) * 6 + 1);
+ q = dest;
if (!exmap_inited)
{
@@ -139,6 +148,8 @@ _ul_str_escape (const char *str)
}
*q = 0;
+ if (length)
+ *length = q - dest;
return dest;
}
@@ -169,38 +180,44 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value)
{
char *k, *v;
size_t lk, lv;
+ size_t orig_len = buffer->len;
- k = _ul_str_escape (key);
+ /* Append the key to the buffer */
+ escape_buffer.len = 0;
+ _ul_buffer_ensure_size (&escape_buffer, strlen (key) * 6 + 1);
+ k = _ul_str_escape (key, escape_buffer.msg, &lk);
if (!k)
return NULL;
- v = _ul_str_escape (value);
+
+ buffer = _ul_buffer_ensure_size (buffer, buffer->len + lk + 4);
+ if (!buffer)
+ return NULL;
+
+ memcpy (buffer->msg + buffer->len, "\"", 1);
+ memcpy (buffer->msg + buffer->len + 1, k, lk);
+ memcpy (buffer->msg + buffer->len + 1 + lk, "\":\"", 3);
+
+ /* Append the value to the buffer */
+ escape_buffer.len = 0;
+ _ul_buffer_ensure_size (&escape_buffer, strlen (value) * 6 + 1);
+ v = _ul_str_escape (value, escape_buffer.msg, &lv);
if (!v)
{
- free (k);
+ buffer->len = orig_len;
return NULL;
}
- lk = strlen (k);
- lv = strlen (v);
-
buffer = _ul_buffer_ensure_size (buffer, buffer->len + lk + lv + 6);
if (!buffer)
{
- free (k);
- free (v);
+ buffer->len = orig_len;
return NULL;
}
- memcpy (buffer->msg + buffer->len, "\"", 1);
- memcpy (buffer->msg + buffer->len + 1, k, lk);
- memcpy (buffer->msg + buffer->len + 1 + lk, "\":\"", 3);
memcpy (buffer->msg + buffer->len + 1 + lk + 3, v, lv);
memcpy (buffer->msg + buffer->len + 1 + lk + 3 + lv, "\",", 2);
buffer->len += lk + lv + 6;
- free (k);
- free (v);
-
return buffer;
}
diff --git a/lib/libumberlog.ld b/lib/libumberlog.ld
index 8cd48e7..225d51c 100644
--- a/lib/libumberlog.ld
+++ b/lib/libumberlog.ld
@@ -15,3 +15,8 @@ LIBUMBERLOG_0.1.0 {
facilitynames;
prioritynames;
};
+
+LIBUMBERLOG_0.2.1 {
+ global:
+ ul_closelog;
+} LIBUMBERLOG_0.1.0;
diff --git a/lib/umberlog.c b/lib/umberlog.c
index fe0a6b7..e4eb5d3 100644
--- a/lib/umberlog.c
+++ b/lib/umberlog.c
@@ -48,9 +48,11 @@
static void (*old_syslog) ();
static void (*old_vsyslog) ();
static void (*old_openlog) ();
+static void (*old_closelog) ();
static int (*old_setlogmask) ();
static void ul_init (void) __attribute__((constructor));
+static void ul_finish (void) __attribute__((destructor));
static __thread struct
{
@@ -74,9 +76,16 @@ ul_init (void)
old_syslog = dlsym (RTLD_NEXT, "syslog");
old_vsyslog = dlsym (RTLD_NEXT, "vsyslog");
old_openlog = dlsym (RTLD_NEXT, "openlog");
+ old_closelog = dlsym (RTLD_NEXT, "closelog");
old_setlogmask = dlsym (RTLD_NEXT, "setlogmask");
}
+static void
+ul_finish (void)
+{
+ free (ul_buffer.msg);
+}
+
void
ul_openlog (const char *ident, int option, int facility)
{
@@ -92,17 +101,28 @@ ul_openlog (const char *ident, int option, int facility)
gethostname (ul_sys_settings.hostname, _POSIX_HOST_NAME_MAX);
}
+void
+ul_closelog (void)
+{
+ old_closelog ();
+ memset (&ul_sys_settings, 0, sizeof (ul_sys_settings));
+}
+
/** HELPERS **/
static inline const char *
-_find_facility (void)
+_find_facility (int prio)
{
int i = 0;
+ int fac = prio & LOG_FACMASK;
+
+ if (fac == 0)
+ fac = ul_sys_settings.facility;
while (facilitynames[i].c_name != NULL &&
- facilitynames[i].c_val != ul_sys_settings.facility)
+ facilitynames[i].c_val != fac)
i++;
- if (facilitynames[i].c_val == ul_sys_settings.facility)
+ if (facilitynames[i].c_val == fac)
return facilitynames[i].c_name;
return "<unknown>";
}
@@ -111,12 +131,13 @@ static inline const char *
_find_prio (int prio)
{
int i = 0;
+ int pri = LOG_PRI (prio);
while (prioritynames[i].c_name != NULL &&
- prioritynames[i].c_val != prio)
+ prioritynames[i].c_val != pri)
i++;
- if (prioritynames[i].c_val == prio)
+ if (prioritynames[i].c_val == pri)
return prioritynames[i].c_name;
return "<unknown>";
}
@@ -309,7 +330,7 @@ _ul_discover (ul_buffer_t *buffer, int priority)
buffer = _ul_json_append (buffer,
"pid", "%d", _find_pid (),
- "facility", "%s", _find_facility (),
+ "facility", "%s", _find_facility (priority),
"priority", "%s", _find_prio (priority),
"program", "%s", ul_sys_settings.ident,
"uid", "%d", _get_uid (),
@@ -341,6 +362,8 @@ _ul_vformat (ul_buffer_t *buffer, int format_version,
if (!value)
return NULL;
+ ul_buffer_reset (buffer);
+
buffer = ul_buffer_append (buffer, "msg", value);
if (buffer == NULL)
{
@@ -395,8 +418,6 @@ ul_vformat (int priority, const char *msg_format, va_list ap)
const char *msg;
ul_buffer_t *buffer = &ul_buffer;
- ul_buffer_reset (buffer);
-
msg = _ul_vformat_str (buffer, 1, priority, msg_format, ap);
if (!msg)
{
@@ -500,6 +521,9 @@ __vsyslog_chk (int __pri, int __flag, __const char *__fmt, va_list ap)
void openlog (const char *ident, int option, int facility)
__attribute__((alias ("ul_openlog")));
+void closelog (void)
+ __attribute__((alias ("ul_closelog")));
+
#undef syslog
void syslog (int priority, const char *msg_format, ...)
__attribute__((alias ("ul_legacy_syslog")));
diff --git a/lib/umberlog.h b/lib/umberlog.h
index 4245dae..51ed7be 100644
--- a/lib/umberlog.h
+++ b/lib/umberlog.h
@@ -41,6 +41,7 @@ char *ul_format (int priority, const char *msg_format, ...)
char *ul_vformat (int priority, const char *msg_format, va_list ap);
void ul_openlog (const char *ident, int option, int facility);
+void ul_closelog (void);
int ul_setlogmask (int mask);
int ul_syslog (int priority, const char *msg_format, ...)
diff --git a/lib/umberlog.rst b/lib/umberlog.rst
index c655263..d2cd354 100644
--- a/lib/umberlog.rst
+++ b/lib/umberlog.rst
@@ -7,7 +7,7 @@ CEE-enhanced syslog message generation
--------------------------------------
:Author: Gergely Nagy <algernon@balabit.hu>
-:Date: 2012-03-23
+:Date: 2012-04-28
:Manual section: 3
:Manual group: CEE-enhanced syslog Manual
@@ -19,6 +19,7 @@ SYNOPSIS
#include <umberlog.h>
void ul_openlog (const char *ident, int option, int facility);
+ void ul_closelog (void);
int ul_syslog (int priority, const char *format, ....);
int ul_vsyslog (int priority, const char *format, va_list ap);
@@ -37,6 +38,11 @@ the original **openlog()** function, which opens a connection to the
system logger for a program. The updated version adds support for a
number of new option flags, described below.
+**ul_closelog()** (also aliased to **closelog()**) is similar to
+**ul_openlog()** in that it is a wrapper around the original
+**closelog()**. It clears any settings set so far, to get back to a
+clean state.
+
**ul_legacy_syslog()** and **ul_legacy_vsyslog()** are both thin
layers over the original **syslog()** and **vsyslog()** functions, and
the library overrides the original functions with this two. The only
diff --git a/t/Makefile.am b/t/Makefile.am
index b07c6f2..91e4b53 100644
--- a/t/Makefile.am
+++ b/t/Makefile.am
@@ -2,6 +2,6 @@ if ENABLE_TESTS
TESTS = test_umberlog test_perf
check_PROGRAMS = ${TESTS}
-AM_CFLAGS = -I$(top_srcdir)/lib @JSON_CFLAGS@
-LDADD = $(top_builddir)/lib/libumberlog.la @JSON_LIBS@
+AM_CFLAGS = -I$(top_srcdir)/lib @JSON_CFLAGS@ @CHECK_CFLAGS@
+LDADD = $(top_builddir)/lib/libumberlog.la @JSON_LIBS@ @CHECK_LIBS@
endif
diff --git a/t/test_umberlog.c b/t/test_umberlog.c
index 26fbadb..9818a35 100644
--- a/t/test_umberlog.c
+++ b/t/test_umberlog.c
@@ -10,6 +10,8 @@
#include <stdio.h>
#include <limits.h>
+#include <check.h>
+
static void
verify_value (struct json_object *jo, const char *key,
const char *expected_value)
@@ -19,12 +21,11 @@ verify_value (struct json_object *jo, const char *key,
o = json_object_object_get (jo, key);
- assert (o != NULL);
+ ck_assert (o != NULL);
value = json_object_get_string (o);
- assert (value != NULL);
- assert (strcmp (value, expected_value) == 0);
+ ck_assert_str_eq (value, expected_value);
}
static void
@@ -33,7 +34,7 @@ verify_value_exists (struct json_object *jo, const char *key)
struct json_object *o;
o = json_object_object_get (jo, key);
- assert (o != NULL);
+ ck_assert_msg (o != NULL, "key '%s' does not exist", key);
}
static void
@@ -56,8 +57,7 @@ parse_msg (const char *msg)
return jo;
}
-static void
-test_simple (void)
+START_TEST (test_simple)
{
char *msg;
struct json_object *jo;
@@ -85,9 +85,9 @@ test_simple (void)
closelog ();
}
+END_TEST
-static void
-test_no_discover (void)
+START_TEST (test_no_discover)
{
char *msg;
struct json_object *jo;
@@ -112,9 +112,9 @@ test_no_discover (void)
closelog ();
}
+END_TEST
-static void
-test_additional_fields (void)
+START_TEST (test_additional_fields)
{
char *msg;
struct json_object *jo;
@@ -136,9 +136,9 @@ test_additional_fields (void)
closelog ();
}
+END_TEST
-static void
-test_discover_priority (void)
+START_TEST (test_discover_priority)
{
char *msg, *pid;
struct json_object *jo;
@@ -162,9 +162,9 @@ test_discover_priority (void)
closelog ();
}
+END_TEST
-static void
-test_no_timestamp (void)
+START_TEST (test_no_timestamp)
{
char *msg;
struct json_object *jo;
@@ -189,9 +189,9 @@ test_no_timestamp (void)
closelog ();
}
+END_TEST
-static void
-test_json_escape (void)
+START_TEST (test_json_escape)
{
char *msg;
struct json_object *jo;
@@ -218,16 +218,72 @@ test_json_escape (void)
closelog ();
}
+END_TEST
+
+START_TEST (test_facprio)
+{
+ char *msg;
+ struct json_object *jo;
+
+ msg = ul_format (LOG_LOCAL1 | LOG_DEBUG, "%s", __FUNCTION__,
+ NULL);
+ jo = parse_msg (msg);
+ free (msg);
+
+ verify_value (jo, "facility", "local1");
+ verify_value (jo, "priority", "debug");
+
+ json_object_put (jo);
+}
+END_TEST
+
+START_TEST (test_closelog)
+{
+ char *msg;
+ struct json_object *jo;
+
+ openlog ("umberlog/test_closelog", LOG_UL_NODISCOVER, LOG_LOCAL0);
+ closelog ();
+
+ msg = ul_format (LOG_LOCAL1 | LOG_DEBUG, "%s", __FUNCTION__, NULL);
+ jo = parse_msg (msg);
+ free (msg);
+
+ verify_value (jo, "facility", "local1");
+
+ json_object_put (jo);
+}
+END_TEST
int
main (void)
{
- test_simple ();
- test_no_discover ();
- test_additional_fields ();
- test_discover_priority ();
- test_no_timestamp ();
- test_json_escape ();
-
- return 0;
+ Suite *s;
+ SRunner *sr;
+ TCase *ft, *bt;
+ int nfailed;
+
+ s = suite_create ("Umberlog functional testsuite");
+
+ ft = tcase_create ("Basic tests");
+ tcase_add_test (ft, test_simple);
+ tcase_add_test (ft, test_no_discover);
+ tcase_add_test (ft, test_additional_fields);
+ tcase_add_test (ft, test_discover_priority);
+ tcase_add_test (ft, test_no_timestamp);
+ suite_add_tcase (s, ft);
+
+ bt = tcase_create ("Bug tests");
+ tcase_add_test (bt, test_json_escape);
+ tcase_add_test (bt, test_facprio);
+ tcase_add_test (bt, test_closelog);
+ suite_add_tcase (s, bt);
+
+ sr = srunner_create (s);
+
+ srunner_run_all (sr, CK_ENV);
+ nfailed = srunner_ntests_failed (sr);
+ srunner_free (sr);
+
+ return (nfailed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}