From 3833ceed1695bbd723801c04235054d60c212a05 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Fri, 23 Mar 2012 18:50:54 +0100 Subject: Fix a formatting mistake in the API docs. Signed-off-by: Gergely Nagy --- lib/umberlog.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/umberlog.rst b/lib/umberlog.rst index 036341b..515a6cc 100644 --- a/lib/umberlog.rst +++ b/lib/umberlog.rst @@ -44,8 +44,8 @@ change these functions bring, are that the message they generate will be a CEE-enhanced message, with a JSON payload. See below for an explanation on what this means. -_syslog()** and **ul_vsyslog()** are two new functions provided by the -library, that have similar interface to the legacy **syslog()** +**ul_syslog()** and **ul_vsyslog()** are two new functions provided by +the library, that have similar interface to the legacy **syslog()** functions, but they can be used to add arbitrary key-value pairs to the emitted message. After the *msg_format* format string, and any other parameters it refers to, there must be a NULL-terminated list of -- cgit From d5dd310da5fdad1690827293ae7f4260ec9ed971 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sat, 24 Mar 2012 10:04:34 +0100 Subject: Mark a few internal functions inline. Signed-off-by: Gergely Nagy --- lib/umberlog.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/umberlog.c b/lib/umberlog.c index 151b333..842ab43 100644 --- a/lib/umberlog.c +++ b/lib/umberlog.c @@ -94,7 +94,7 @@ ul_openlog (const char *ident, int option, int facility) } /** HELPERS **/ -static const char * +static inline const char * _find_facility (void) { int i = 0; @@ -108,7 +108,7 @@ _find_facility (void) return ""; } -static const char * +static inline const char * _find_prio (int prio) { int i = 0; @@ -159,7 +159,7 @@ _get_hostname (void) return ul_sys_settings.hostname; } -static struct json_object * +static inline struct json_object * _ul_json_vappend (struct json_object *json, va_list ap) { char *key; @@ -177,7 +177,7 @@ _ul_json_vappend (struct json_object *json, va_list ap) return json; } -static struct json_object * +static inline struct json_object * _ul_json_append (struct json_object *json, ...) { va_list ap; @@ -230,7 +230,7 @@ _ul_discover (struct json_object *jo, int priority) _ul_json_append_timestamp (jo); } -static struct json_object * +static inline struct json_object * _ul_vformat (struct json_object *jo, int format_version, int priority, const char *msg_format, va_list ap) -- cgit From 21e8d846ed040a1bf55987036578807d5826d958 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sat, 24 Mar 2012 11:17:03 +0100 Subject: Implement proper error handling. Instead of calling abort() if vasprintf() fails, and ignoring possible errors from the JSON library, do handle errors reasonably sanely: check return values, and return an error state from all functions, and propagate it up to the application level, too. This means that the legacy overrides will silently fail, but set errno appropriately in case serializing to JSON fails, and do what the system libc does with syslog otherwise. The new functions can return NULL or non-zero on error, which the application can then handle as it sees fit. Signed-off-by: Gergely Nagy --- lib/umberlog.c | 170 ++++++++++++++++++++++++++++++++++++++----------------- lib/umberlog.h | 9 ++- lib/umberlog.rst | 23 +++++--- 3 files changed, 139 insertions(+), 63 deletions(-) (limited to 'lib') diff --git a/lib/umberlog.c b/lib/umberlog.c index 842ab43..5a0b532 100644 --- a/lib/umberlog.c +++ b/lib/umberlog.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "umberlog.h" @@ -167,11 +168,22 @@ _ul_json_vappend (struct json_object *json, va_list ap) while ((key = (char *)va_arg (ap, char *)) != NULL) { char *fmt = (char *)va_arg (ap, char *); - char *value; + char *value = NULL; + struct json_object *jstr; if (vasprintf (&value, fmt, ap) == -1) - abort (); - json_object_object_add (json, key, json_object_new_string (value)); + return NULL; + if (!value) + return NULL; + + jstr = json_object_new_string (value); + if (!jstr) + { + free (value); + return NULL; + } + + json_object_object_add (json, key, jstr); free (value); } return json; @@ -183,13 +195,13 @@ _ul_json_append (struct json_object *json, ...) va_list ap; va_start (ap, json); - _ul_json_vappend (json, ap); + json = _ul_json_vappend (json, ap); va_end (ap); return json; } -static inline void +static inline struct json_object * _ul_json_append_timestamp (struct json_object *jo) { struct timespec ts; @@ -203,31 +215,31 @@ _ul_json_append_timestamp (struct json_object *jo) strftime (stamp, sizeof (stamp), "%FT%T", tm); strftime (zone, sizeof (zone), "%z", tm); - _ul_json_append (jo, "timestamp", "%s.%lu%s", - stamp, ts.tv_nsec, zone, - NULL); + return _ul_json_append (jo, "timestamp", "%s.%lu%s", + stamp, ts.tv_nsec, zone, + NULL); } -static inline void +static inline struct json_object * _ul_discover (struct json_object *jo, int priority) { if (ul_sys_settings.flags & LOG_UL_NODISCOVER) - return; - - _ul_json_append (jo, - "pid", "%d", _find_pid (), - "facility", "%s", _find_facility (), - "priority", "%s", _find_prio (priority), - "program", "%s", ul_sys_settings.ident, - "uid", "%d", _get_uid (), - "gid", "%d", _get_gid (), - "host", "%s", _get_hostname (), - NULL); - - if (ul_sys_settings.flags & LOG_UL_NOTIME) - return; - - _ul_json_append_timestamp (jo); + return jo; + + jo = _ul_json_append (jo, + "pid", "%d", _find_pid (), + "facility", "%s", _find_facility (), + "priority", "%s", _find_prio (priority), + "program", "%s", ul_sys_settings.ident, + "uid", "%d", _get_uid (), + "gid", "%d", _get_gid (), + "host", "%s", _get_hostname (), + NULL); + + if (ul_sys_settings.flags & LOG_UL_NOTIME || !jo) + return jo; + + return _ul_json_append_timestamp (jo); } static inline struct json_object * @@ -236,18 +248,30 @@ _ul_vformat (struct json_object *jo, int format_version, va_list ap) { char *value; + struct json_object *jstr; if (vasprintf (&value, msg_format, ap) == -1) - abort (); - json_object_object_add (jo, "msg", json_object_new_string (value)); + return NULL; + if (!value) + return NULL; + + jstr = json_object_new_string (value); + if (!jstr) + { + free (value); + return NULL; + } + + json_object_object_add (jo, "msg", jstr); free (value); if (format_version > 0) - _ul_json_vappend (jo, ap); + jo = _ul_json_vappend (jo, ap); - _ul_discover (jo, priority); + if (!jo) + return NULL; - return jo; + return _ul_discover (jo, priority); } static inline const char * @@ -255,9 +279,12 @@ _ul_vformat_str (struct json_object *jo, int format_version, int priority, const char *msg_format, va_list ap) { - return json_object_to_json_string (_ul_vformat (jo, format_version, - priority, msg_format, - ap)); + jo = _ul_vformat (jo, format_version, + priority, msg_format, ap); + if (!jo) + return NULL; + + return json_object_to_json_string (jo); } /** Public API **/ @@ -279,46 +306,83 @@ ul_vformat (int priority, const char *msg_format, va_list ap) { struct json_object *jo = json_object_new_object (); char *result; + const char *msg; - result = strdup (_ul_vformat_str (jo, 1, priority, msg_format, ap)); - json_object_put (jo); - return result; -} + if (!jo) + { + errno = ENOMEM; + return NULL; + } -void -ul_syslog (int priority, const char *msg_format, ...) -{ - va_list ap; + msg = _ul_vformat_str (jo, 1, priority, msg_format, ap); + if (!msg) + { + json_object_put (jo); + errno = ENOMEM; + return NULL; + } - va_start (ap, msg_format); - ul_vsyslog (priority, msg_format, ap); - va_end (ap); + result = strdup (msg); + json_object_put (jo); + return result; } -static inline void +static inline int _ul_vsyslog (int format_version, int priority, const char *msg_format, va_list ap) { struct json_object *jo; + const char *msg; if (!(ul_sys_settings.mask & priority)) - return; + return 0; + + jo = json_object_new_object (); + if (!jo) + return -1; + + if (_ul_vformat (jo, format_version, + priority, msg_format, ap) == NULL) + { + json_object_put (jo); + return -1; + } + + msg = json_object_to_json_string (jo); + if (!msg) + { + json_object_put (jo); + return -1; + } - jo = _ul_vformat (json_object_new_object (), format_version, - priority, msg_format, ap); #if __USE_FORTIFY_LEVEL > 0 - old_syslog_chk (priority, __USE_FORTIFY_LEVEL - 1, "@cee:%s", - json_object_to_json_string (jo)); + old_syslog_chk (priority, __USE_FORTIFY_LEVEL - 1, "@cee:%s", msg); #else - old_syslog (priority, "@cee:%s", json_object_to_json_string (jo)); + old_syslog (priority, "@cee:%s", msg); #endif + json_object_put (jo); + + return 0; } -void +int +ul_syslog (int priority, const char *msg_format, ...) +{ + va_list ap; + int status; + + va_start (ap, msg_format); + status = ul_vsyslog (priority, msg_format, ap); + va_end (ap); + + return status; +} + +int ul_vsyslog (int priority, const char *msg_format, va_list ap) { - _ul_vsyslog (1, priority, msg_format, ap); + return _ul_vsyslog (1, priority, msg_format, ap); } void diff --git a/lib/umberlog.h b/lib/umberlog.h index f91fe67..4245dae 100644 --- a/lib/umberlog.h +++ b/lib/umberlog.h @@ -36,14 +36,17 @@ #define LOG_UL_NOCACHE_UID 0x0100 #define LOG_UL_NOTIME 0x0200 -char *ul_format (int priority, const char *msg_format, ...); +char *ul_format (int priority, const char *msg_format, ...) + __attribute__((sentinel)); char *ul_vformat (int priority, const char *msg_format, va_list ap); void ul_openlog (const char *ident, int option, int facility); int ul_setlogmask (int mask); -void ul_syslog (int priority, const char *msg_format, ...); -void ul_vsyslog (int priority, const char *msg_format, va_list ap); +int ul_syslog (int priority, const char *msg_format, ...) + __attribute__((warn_unused_result, sentinel)); +int ul_vsyslog (int priority, const char *msg_format, va_list ap) + __attribute__((warn_unused_result)); void ul_legacy_syslog (int priority, const char *msg_format, ...); void ul_legacy_vsyslog (int priority, const char *msg_format, va_list ap); diff --git a/lib/umberlog.rst b/lib/umberlog.rst index 515a6cc..26204e2 100644 --- a/lib/umberlog.rst +++ b/lib/umberlog.rst @@ -20,8 +20,8 @@ SYNOPSIS void ul_openlog (const char *ident, int option, int facility); - void ul_syslog (int priority, const char *format, ....); - void ul_vsyslog (int priority, const char *format, va_list ap); + int ul_syslog (int priority, const char *format, ....); + int ul_vsyslog (int priority, const char *format, va_list ap); void ul_legacy_syslog (int priority, const char *format, ...); void ul_legacy_vsyslog (int priority, const char *format, va_list ap); @@ -57,6 +57,15 @@ will be added to the generated message. variants above, except the formatted payload is not sent to syslog, but returned as a newly allocated string. +RETURN VALUE +============ + +When successful, **ul_syslog()** and **ul_vsyslog()** return zero, +while **ul_format()** and **ul_vformat()** return a character string. + +On failure the former two will return non-zero, the latter two +**NULL**, and set *errno* appropriately. + CEE PAYLOAD =========== @@ -122,11 +131,11 @@ EXAMPLES :: - ul_syslog(LOG_NOTICE, "Logged in user: %s", username, - "service", "%s", service, - "auth-method", "%s", auth_method, - "sessionid", "%d", session_id, - NULL); + status = ul_syslog(LOG_NOTICE, "Logged in user: %s", username, + "service", "%s", service, + "auth-method", "%s", auth_method, + "sessionid", "%d", session_id, + NULL); SEE ALSO ======== -- cgit From deb0d36d4e3343f2424b73caccfb494157f94a75 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sat, 24 Mar 2012 11:24:33 +0100 Subject: Allow compilation with clang, too. Clang tries to expand the syslog and vsyslog macros when we define our overrides. To work around that, #undef them first. Signed-off-by: Gergely Nagy --- lib/umberlog.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/umberlog.c b/lib/umberlog.c index 5a0b532..516f41c 100644 --- a/lib/umberlog.c +++ b/lib/umberlog.c @@ -430,9 +430,11 @@ __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"))); +#undef syslog void syslog (int priority, const char *msg_format, ...) __attribute__((alias ("ul_legacy_syslog"))); +#undef vsyslog void vsyslog (int priority, const char *msg_format, va_list ap) __attribute__((alias ("ul_legacy_vsyslog"))); -- cgit From c515ced437047b459cfce6b6a34eb572558566f9 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sat, 24 Mar 2012 15:52:25 +0100 Subject: Portability fixes Use _POSIX_HOST_NAME_MAX instead of HOST_NAME_MAX: both Linux and FreeBSD have the former, but FreeBSD does not have HOST_NAME_MAX in limits.h Signed-off-by: Gergely Nagy --- lib/umberlog.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/umberlog.c b/lib/umberlog.c index 516f41c..e2d72de 100644 --- a/lib/umberlog.c +++ b/lib/umberlog.c @@ -64,7 +64,7 @@ static __thread struct uid_t uid; gid_t gid; const char *ident; - char hostname[HOST_NAME_MAX + 1]; + char hostname[_POSIX_HOST_NAME_MAX + 1]; } ul_sys_settings; static void @@ -91,7 +91,7 @@ ul_openlog (const char *ident, int option, int facility) ul_sys_settings.uid = getuid (); ul_sys_settings.ident = ident; - gethostname (ul_sys_settings.hostname, HOST_NAME_MAX); + gethostname (ul_sys_settings.hostname, _POSIX_HOST_NAME_MAX); } /** HELPERS **/ @@ -156,7 +156,7 @@ static inline const char * _get_hostname (void) { if (ul_sys_settings.flags & LOG_UL_NOCACHE) - gethostname (ul_sys_settings.hostname, HOST_NAME_MAX); + gethostname (ul_sys_settings.hostname, _POSIX_HOST_NAME_MAX); return ul_sys_settings.hostname; } -- cgit From edd3b75417caafeb1c6476c2958a970d8f799437 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sat, 24 Mar 2012 16:06:05 +0100 Subject: More portability fixes While on glibc-based systems, we need -ldl (for dlopen) and -lrt (for clock_gettime), FreeBSD has both in libc, and does not have these extra libraries. Teach configure about this. Signed-off-by: Gergely Nagy --- lib/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/Makefile.am b/lib/Makefile.am index 030ae4e..768484e 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -4,7 +4,7 @@ LUL_AGE = 0 lib_LTLIBRARIES = libumberlog.la libumberlog_la_LDFLAGS = -Wl,--version-script,${srcdir}/libumberlog.ld -libumberlog_la_LIBADD = @JSON_LIBS@ -ldl -lrt +libumberlog_la_LIBADD = @JSON_LIBS@ libumberlog_la_CFLAGS = @JSON_CFLAGS@ libumberlog_la_SOURCES = umberlog.c umberlog.h -- cgit From d6fbe492d6dd7a1648134ef26ee22a83c5ad6365 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sat, 24 Mar 2012 17:18:12 +0100 Subject: Fix infinite recursion on FreeBSD. On FreeBSD, syslog() calls vsyslog(), our own replacement version. So when from syslog(), we call our vsyslog(), which calls the old syslog(), that ends up calling our own vsyslog() again. To work around this issue, use a thread-local static variable that signals whether we're recursing, and if we are, then call the old vsyslog from the new one, thus breaking the loop. This makes the library function correctly on FreeBSD too. Signed-off-by: Gergely Nagy --- lib/umberlog.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/umberlog.c b/lib/umberlog.c index e2d72de..ae9ebaf 100644 --- a/lib/umberlog.c +++ b/lib/umberlog.c @@ -45,8 +45,10 @@ #if __USE_FORTIFY_LEVEL > 0 static void (*old_syslog_chk) (); +static void (*old_vsyslog_chk) (); #else static void (*old_syslog) (); +static void (*old_vsyslog) (); #endif static void (*old_openlog) (); @@ -67,13 +69,17 @@ static __thread struct char hostname[_POSIX_HOST_NAME_MAX + 1]; } ul_sys_settings; +static __thread int ul_recurse; + static void ul_init (void) { #if __USE_FORTIFY_LEVEL > 0 old_syslog_chk = dlsym (RTLD_NEXT, "__syslog_chk"); + old_vsyslog_chk = dlsym (RTLD_NEXT, "__vsyslog_chk"); #else old_syslog = dlsym (RTLD_NEXT, "syslog"); + old_vsyslog = dlsym (RTLD_NEXT, "vsyslog"); #endif old_openlog = dlsym (RTLD_NEXT, "openlog"); old_setlogmask = dlsym (RTLD_NEXT, "setlogmask"); @@ -388,7 +394,20 @@ ul_vsyslog (int priority, const char *msg_format, va_list ap) void ul_legacy_vsyslog (int priority, const char *msg_format, va_list ap) { - _ul_vsyslog (0, priority, msg_format, ap); + if (ul_recurse) + { +#if __USE_FORTIFY_LEVEL > 0 + old_vsyslog_chk (priority, __USE_FORTIFY_LEVEL - 1, msg_format, ap); +#else + old_vsyslog (priority, msg_format, ap); +#endif + } + else + { + ul_recurse = 1; + _ul_vsyslog (0, priority, msg_format, ap); + } + ul_recurse = 0; } void -- cgit From 9f6935065f4c844835774e8874fd38ad62363de0 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sat, 24 Mar 2012 17:49:47 +0100 Subject: Include the linker script and the API docs in the dist tarball. Signed-off-by: Gergely Nagy --- lib/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/Makefile.am b/lib/Makefile.am index 768484e..5c64fb6 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -14,3 +14,5 @@ libumberlog_include_HEADERS = umberlog.h pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libumberlog.pc + +EXTRA_DIST = umberlog.rst libumberlog.ld -- cgit