From dabdb5d3bde5d81b197dc457ad0be95450cbf9b5 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sun, 11 Sep 2016 15:30:10 -0400 Subject: [PATCH] sysdb: If available, use YAJL to pretty-print JSON output. --- configure.ac | 16 ++++ src/Makefile.am | 6 +- src/tools/sysdb/command.c | 5 +- src/tools/sysdb/json.c | 159 ++++++++++++++++++++++++++++++++++++++ src/tools/sysdb/json.h | 44 +++++++++++ 5 files changed, 227 insertions(+), 3 deletions(-) create mode 100644 src/tools/sysdb/json.c create mode 100644 src/tools/sysdb/json.h diff --git a/configure.ac b/configure.ac index c39c4af..c671004 100644 --- a/configure.ac +++ b/configure.ac @@ -473,6 +473,17 @@ if test "x$with_libdbi" = "xyes"; then fi AM_CONDITIONAL([BUILD_WITH_LIBDBI], test "x$with_libdbi" = "xyes") +AC_ARG_WITH([libyajl], + [AS_HELP_STRING([--with-liyajl], [libyajl support (default: auto)])], + [with_libyajl="$withval"], + [with_libyajl="yes"]) +if test "x$with_libyajl" = "xyes" || test "x$with_libyajl" = "xauto"; then + PKG_CHECK_MODULES([YAJL], [yajl], [have_libyajl="yes"], [have_libyajl="no"]) +fi +if test "x$with_libyajl" = "xyes"; then + AC_DEFINE([HAVE_LIBYAJL], 1, [Define to 1 if you have the 'yajl' library.]) +fi + dnl Required for mocking FILE related functions. orig_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -D_GNU_SOURCE" @@ -730,6 +741,10 @@ librrd_info="$have_librrd" if test "x$have_librrd" = "xyes"; then librrd_info="yes (version `$PKG_CONFIG --modversion librrd`)" fi +libyajl_info="$have_libyajl" +if test "x$have_libyajl" = "xyes"; then + libyajl_info="yes (version `$PKG_CONFIG --modversion yajl`)" +fi AC_MSG_RESULT() AC_MSG_RESULT([$PACKAGE_NAME has been configured successfully.]) @@ -760,6 +775,7 @@ AC_MSG_RESULT([ libedit: . . . . . . . . . $libedit_info]) AC_MSG_RESULT([ libopenssl: . . . . . . . . $openssl_info]) AC_MSG_RESULT([ libreadline: . . . . . . . $have_libreadline]) AC_MSG_RESULT([ librrd: . . . . . . . . . . $librrd_info]) +AC_MSG_RESULT([ libyajl: . . . . . . . . . $libyajl_info]) AC_MSG_RESULT() AC_MSG_RESULT([ Backends:]) AC_MSG_RESULT([ collectd::unixsock: . . . . $enable_collectd_unixsock]) diff --git a/src/Makefile.am b/src/Makefile.am index 0a6c8b3..a3a65fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -135,12 +135,14 @@ libsysdb_scanner_la_CFLAGS = @COVERAGE_CFLAGS@ @PROFILING_CFLAGS@ \ sysdb_SOURCES = tools/sysdb/main.c include/client/sysdb.h \ tools/sysdb/command.c tools/sysdb/command.h \ tools/sysdb/input.c tools/sysdb/input.h \ + tools/sysdb/json.c tools/sysdb/json.h \ core/object.c include/core/object.h \ utils/llist.c include/utils/llist.h \ utils/os.c include/utils/os.h sysdb_CFLAGS = -DBUILD_DATE="\"$$( date --utc '+%F %T' ) (UTC)\"" \ - $(AM_CFLAGS) @READLINE_CFLAGS@ -sysdb_LDADD = libsysdb_scanner.la libsysdbclient.la @READLINE_LIBS@ -lm + $(AM_CFLAGS) @READLINE_CFLAGS@ @YAJL_CFLAGS@ +sysdb_LDADD = libsysdb_scanner.la libsysdbclient.la \ + @READLINE_LIBS@ @YAJL_LIBS@ -lm endif sysdbd_SOURCES = tools/sysdbd/main.c include/sysdb.h \ diff --git a/src/tools/sysdb/command.c b/src/tools/sysdb/command.c index c7ca310..4de2b44 100644 --- a/src/tools/sysdb/command.c +++ b/src/tools/sysdb/command.c @@ -33,6 +33,7 @@ #include "tools/sysdb/command.h" #include "tools/sysdb/input.h" +#include "tools/sysdb/json.h" #include "frontend/proto.h" #include "utils/error.h" @@ -89,7 +90,9 @@ data_printer(sdb_strbuf_t *buf) /* At the moment, we don't care about the result type. We simply print the * result without further parsing it. */ sdb_strbuf_skip(buf, 0, sizeof(uint32_t)); - printf("%s\n", sdb_strbuf_string(buf)); + if (sdb_json_print(buf)) + sdb_log(SDB_LOG_ERR, "Failed to print result"); + printf("\n"); } /* data_printer */ static struct { diff --git a/src/tools/sysdb/json.c b/src/tools/sysdb/json.c new file mode 100644 index 0000000..703b22e --- /dev/null +++ b/src/tools/sysdb/json.c @@ -0,0 +1,159 @@ +/* + * SysDB - src/tools/sysdb/json.c + * Copyright (C) 2016 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 HOLDERS 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "sysdb.h" + +#include "utils/error.h" +#include "utils/strbuf.h" +#include "tools/sysdb/json.h" + +#include +#include + +#include +#include + +#ifdef HAVE_LIBYAJL + +/* + * YAJL callbacks + */ + +#define GEN(obj) ((yajl_gen)(obj)) +#define OK(cb) ((cb) == yajl_gen_status_ok) + +static int +gen_null(void *ctx) { return OK(yajl_gen_null(GEN(ctx))); } + +static int +gen_boolean(void *ctx, int v) { return OK(yajl_gen_bool(GEN(ctx), v)); } + +static int +gen_number(void *ctx, const char *v, size_t l) +{ + return OK(yajl_gen_number(GEN(ctx), v, l)); +} + +static int +gen_string(void *ctx, const unsigned char *v, size_t l) +{ + return OK(yajl_gen_string(GEN(ctx), v, l)); +} + +static int +gen_start_map(void *ctx) { return OK(yajl_gen_map_open(GEN(ctx))); } + +static int +gen_end_map(void *ctx) { return OK(yajl_gen_map_close(GEN(ctx))); } + +static int +gen_start_array(void *ctx) { return OK(yajl_gen_array_open(GEN(ctx))); } + +static int +gen_end_array(void *ctx) { return OK(yajl_gen_array_close(GEN(ctx))); } + +static yajl_callbacks reformatters = { + gen_null, + gen_boolean, + NULL, /* gen_integer; */ + NULL, /* gen_doube; both default to gen_number */ + gen_number, + gen_string, + gen_start_map, + gen_string, + gen_end_map, + gen_start_array, + gen_end_array, +}; + +static void +printer(void __attribute__((unused)) *ctx, const char *str, size_t len) +{ + write(1, str, len); +} /* printer */ + +#endif /* HAVE_LIBYAJL */ + +/* + * public API + */ + +int +sdb_json_print(sdb_strbuf_t *buf) +{ +#ifdef HAVE_LIBYAJL + const unsigned char *json; + size_t json_len; + + yajl_handle h; + yajl_gen gen; + yajl_status status; + + int ret = 0; + + gen = yajl_gen_alloc(/* alloc_funcs */ NULL); + if (! gen) + return -1; + + yajl_gen_config(gen, yajl_gen_beautify, 1); + yajl_gen_config(gen, yajl_gen_validate_utf8, 1); + yajl_gen_config(gen, yajl_gen_print_callback, printer, NULL); + + h = yajl_alloc(&reformatters, /* alloc_funcs */ NULL, (void *)gen); + if (! h) { + yajl_gen_free(gen); + return -1; + } + + json = (const unsigned char *)sdb_strbuf_string(buf); + json_len = sdb_strbuf_len(buf); + status = yajl_parse(h, json, json_len); + if (status == yajl_status_ok) + status = yajl_complete_parse(h); + + if (status != yajl_status_ok) { + unsigned char *err = yajl_get_error(h, 1, json, json_len); + sdb_log(SDB_LOG_ERR, "%s", err); + yajl_free_error(h, err); + ret = -1; + } + + yajl_gen_free(gen); + yajl_free(h); + return ret; +#else /* HAVE_LIBYAJL */ + printf("%s\n", sdb_strbuf_string(buf)); + return 0; +#endif /* HAVE_LIBYAJL */ +} /* sdb_json_print */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/tools/sysdb/json.h b/src/tools/sysdb/json.h new file mode 100644 index 0000000..9fc1a70 --- /dev/null +++ b/src/tools/sysdb/json.h @@ -0,0 +1,44 @@ +/* + * SysDB - src/tools/sysdb/json.h + * Copyright (C) 2016 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 HOLDERS 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 "utils/strbuf.h" + +#ifndef SYSDB_JSON_H +#define SYSDB_JSON_H 1 + +/* + * sdb_json_print: + * Format the JSON string stored in the specified buffer. The output is + * printed to the standard output channel. + */ +int +sdb_json_print(sdb_strbuf_t *buf); + +#endif /* SYSDB_JSON_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + -- 2.30.2