- LLDPD_CONFIG_ARGS="--with-snmp --disable-lldpmed --disable-dot1 --disable-dot3 --disable-custom"
- LLDPD_CONFIG_ARGS="--enable-oldies"
- LLDPD_CONFIG_ARGS="--with-seccomp"
- - LLDPD_CONFIG_ARGS="--with-json=json-c"
matrix:
include:
- os: linux
compiler: clang
- env: LLDPD_CONFIG_ARGS="--with-snmp --with-xml --with-json"
+ env: LLDPD_CONFIG_ARGS="--with-snmp --with-xml"
- os: osx
compiler: clang
- env: LLDPD_CONFIG_ARGS="--with-snmp --with-xml --with-json"
+ env: LLDPD_CONFIG_ARGS="--with-snmp --with-xml"
lldpd (0.9.7)
* Changes:
+ + JSON support is now built-in and unconditionally enabled. Use
+ --enable-json0 to keep the pre-0.9.2 json-c format.
+ When logging to syslog and daemonizing, don't log to stderr.
lldpd (0.9.6)
mkdir build && cd build
../configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/private/etc --with-embedded-libevent \
- --without-json --without-snmp
+ --without-snmp
make -C osx pkg
If you want to compile for an older version of OS X, you need
SDK=/Developer/SDKs/MacOSX10.6.sdk
mkdir build && cd build
../configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/private/etc --with-embedded-libevent \
- --without-json --without-snmp \
+ --without-snmp \
CFLAGS="-mmacosx-version-min=10.6 -isysroot $SDK" \
LDFLAGS="-mmacosx-version-min=10.6 -isysroot $SDK"
make -C osx pkg
mkdir build && cd build
../configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/private/etc --with-embedded-libevent \
- --without-json --without-snmp \
+ --without-snmp \
CFLAGS="-mmacosx-version-min=10.9" \
LDFLAGS="-mmacosx-version-min=10.9"
make -C osx pkg
[with_xml=auto])
lldp_CHECK_XML2
-# JSON
-AC_ARG_WITH([json],
- AS_HELP_STRING(
- [--with-json],
- [Enable JSON output via janson or json-c @<:@default=auto@:>@]),
- [],
- [with_json=auto])
-if test x"$with_json" = x"yes" -o x"$with_json" = x"auto"; then
- _with_json="$with_json"
- with_json=auto
- lldp_CHECK_JANSSON
- if test x"$with_json" = x"no"; then
- with_json=auto
- lldp_CHECK_JSONC
- fi
- if test x"$with_json" = x"no" -a x"$_with_json" = x"yes"; then
- AC_MSG_FAILURE([*** no JSON support found])
- fi
-else
- lldp_CHECK_JANSSON
- lldp_CHECK_JSONC
-fi
+# JSON (built-in)
lldp_ARG_ENABLE([json0], [use of pre-0.9.2 JSON/json-c format], [no])
# Seccomp
AM_CONDITIONAL([HAVE_CHECK], [test x"$have_check" = x"yes"])
AM_CONDITIONAL([USE_SNMP], [test x"$with_snmp" = x"yes"])
AM_CONDITIONAL([USE_XML], [test x"$with_xml" = x"yes"])
-AM_CONDITIONAL([USE_JSON], [test x"$with_json" = x"json-c" || test -x"$with_json" = x"jansson"])
-AM_CONDITIONAL([USE_JANSSON], [test x"$with_json" = x"jansson"])
-AM_CONDITIONAL([USE_JSONC], [test x"$with_json" = x"json-c"])
AM_CONDITIONAL([USE_SECCOMP], [test x"$with_seccomp" = x"yes"])
dnl If old default of AR_FLAGS is otherwise being used (because of older automake),
dnl replace it with one without 'u'
DOT3...........: $enable_dot3
CUSTOM.........: $enable_custom
XML output.....: ${with_xml-no}
- JSON output....: ${with_json-no}
Oldies support.: $enable_oldies
seccomp........: ${with_seccomp-no}
dh-autoreconf,
libsnmp-dev,
libxml2-dev,
- libjansson-dev | libjson-c-dev | libjson0-dev (>= 0.10),
libevent-dev (>= 2.0.5),
libreadline-dev,
libbsd-dev,
Copyright (c) 2002 Matthieu Herrb
License: BSD-2-clause
+Files: src/client/utf8.c
+Copyright: Copyright (c) 2011 Joseph A. Adams
+License: Expat
+
Files: m4/ax_cflags_gcc_option.m4
Copyright: Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
License: GPL-2+ with Autoconf exception
Macro released by the Autoconf Archive. When you make and distribute a
modified version of the Autoconf Macro, you may extend this special
exception to the GPL to apply to your modified version as well.
+
+License: Expat
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ .
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
include /usr/share/cdbs/1/rules/autoreconf.mk
include /usr/share/cdbs/1/class/autotools.mk
-DEB_CONFIGURE_EXTRA_FLAGS = --with-snmp --with-xml --with-json --enable-pie
+DEB_CONFIGURE_EXTRA_FLAGS = --with-snmp --with-xml --enable-pie
DEB_CONFIGURE_EXTRA_FLAGS += --with-systemdsystemunitdir=/lib/systemd/system
+++ /dev/null
-#
-# lldp_CHECK_JANSSON
-#
-
-AC_DEFUN([lldp_CHECK_JANSSON], [
- if test x"$with_json" = x"auto" -o x"$with_json" = x"jansson"; then
- PKG_CHECK_MODULES([JANSSON], [jansson >= 2], [
- AC_SUBST([JANSSON_LIBS])
- AC_SUBST([JANSSON_CFLAGS])
- AC_DEFINE_UNQUOTED([USE_JSON], 1, [Define to indicate to enable JSON support])
- AC_DEFINE_UNQUOTED([USE_JANSSON], 1, [Define to indicate to enable JSON support through jansson])
- with_json=jansson
- ],[
- if test x"$with_json" = x"jansson"; then
- AC_MSG_ERROR([*** unable to find libjansson])
- fi
- with_json=no
- ])
- fi
-])
+++ /dev/null
-#
-# lldp_CHECK_JSONC
-#
-
-AC_DEFUN([lldp_CHECK_JSONC], [
- if test x"$with_json" = x"auto" -o x"$with_json" = x"json-c"; then
- PKG_CHECK_MODULES([JSONC], [json-c], [
- AC_SUBST([JSONC_LIBS])
- AC_SUBST([JSONC_CFLAGS])
- AC_DEFINE_UNQUOTED([USE_JSON], 1, [Define to indicate to enable JSON support])
- AC_DEFINE_UNQUOTED([USE_JSONC], 1, [Define to indicate to enable JSON via json-c support])
- with_json=json-c
- ],[
- PKG_CHECK_MODULES([JSONC], [json >= 0.10], [
- AC_SUBST([JSONC_LIBS])
- AC_SUBST([JSONC_CFLAGS])
- AC_DEFINE_UNQUOTED([USE_JSON], 1, [Define to indicate to enable JSON support])
- AC_DEFINE_UNQUOTED([USE_JSONC], 1, [Define to indicate to enable JSON via json-c support])
- with_json=json-c
- ],[
- if test x"$with_json" = x"json-c"; then
- AC_MSG_ERROR([*** unable to find json-c])
- fi
- with_json=no
- ])
- ])
- fi
-])
%bcond_with oldies
%endif
-# On RHEL and SLES, compile without JSON support
-%if (0%{?rhel_version} > 0) || (0%{?centos_version} > 0 && 0%{?centos_version} < 600) || (0%{?suse_version} > 0)
-%bcond_with json
-%else
-%bcond_without json
-%endif
-
# On RHEL < 7, disable systemd
# On SuSE < 12, disable systemd
%if (0%{?rhel_version} > 0 && 0%{?rhel_version} < 700) || (0%{?centos_version} > 0 && 0%{?centos_version} < 700) || (0%{?suse_version} > 0 && 0%{?suse_version} < 1210)
%if %{with xml}
BuildRequires: libxml2-devel
%endif
-%if %{with json}
-BuildRequires: json-c-devel
-%endif
%if %{with systemd}
%if 0%{?suse_version}
BuildRequires: systemd-rpm-macros
conf-lldp.c conf-system.c \
commands.c show.c \
misc.c tokenizer.c \
- writer.h text_writer.c kv_writer.c
+ utf8.c \
+ writer.h text_writer.c kv_writer.c json_writer.c
lldpcli_LDADD = \
$(top_builddir)/src/libcommon-daemon-client.la \
$(top_builddir)/src/lib/liblldpctl.la \
lldpcli_LDADD += @XML2_LIBS@
endif
-if USE_JANSSON
-lldpcli_SOURCES += jansson_writer.c
-lldpcli_CFLAGS += @JANSSON_CFLAGS@
-lldpcli_LDADD += @JANSSON_LIBS@
-endif
-
-if USE_JSONC
-lldpcli_SOURCES += jsonc_writer.c
-lldpcli_CFLAGS += @JSONC_CFLAGS@
-lldpcli_LDADD += @JSONC_LIBS@
-endif
-
# Completions
bashcompletiondir = $(datadir)/bash-completion/completions
dist_bashcompletion_DATA = completion/lldpcli
+++ /dev/null
-/* -*- mode: c; c-file-style: "openbsd" -*- */
-/*
- * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <jansson.h>
-#include <sys/queue.h>
-
-#include "writer.h"
-#include "../compat/compat.h"
-#include "../log.h"
-
-/* This list is used as a queue. The queue does not hold reference to the json_t
- * element except the first one. */
-struct json_element {
- TAILQ_ENTRY(json_element) next;
- json_t *el;
-};
-TAILQ_HEAD(json_element_list, json_element);
-struct json_writer_private {
- FILE *fh;
- struct json_element_list els;
-};
-
-static void
-jansson_start(struct writer *w, const char *tag, const char *descr)
-{
- struct json_writer_private *p = w->priv;
- struct json_element *current = TAILQ_LAST(&p->els, json_element_list);
- struct json_element *new;
- json_t *exist;
-
- /* Try to find if a similar object exists. */
- exist = json_object_get(current->el, tag);
- if (!exist) {
- exist = json_array();
- json_object_set_new(current->el, tag, exist);
- }
-
- /* Queue the new element. */
- new = malloc(sizeof(*new));
- if (new == NULL) fatal(NULL, NULL);
- new->el = json_object();
- json_array_append_new(exist, new->el);
- TAILQ_INSERT_TAIL(&p->els, new, next);
-}
-
-static void
-jansson_attr(struct writer *w, const char *tag,
- const char *descr, const char *value)
-{
- struct json_writer_private *p = w->priv;
- struct json_element *current = TAILQ_LAST(&p->els, json_element_list);
- json_t *jvalue;
- if (value && (!strcmp(value, "yes") || !strcmp(value, "on")))
- jvalue = json_true();
- else if (value && (!strcmp(value, "no") || !strcmp(value, "off")))
- jvalue = json_false();
- else
- jvalue = json_string(value?value:"");
- json_object_set_new(current->el, tag, jvalue);
-}
-
-static void
-jansson_data(struct writer *w, const char *data)
-{
- struct json_writer_private *p = w->priv;
- struct json_element *current = TAILQ_LAST(&p->els, json_element_list);
- json_object_set_new(current->el, "value",
- json_string(data?data:""));
-}
-
-/* When an array has only one member, just remove the array. When an object has
- * `value` as the only key, remove the object. Moreover, for an object, move the
- * `name` key outside (inside a new object). This is a recursive function. We
- * think the depth will be limited. */
-static json_t*
-jansson_cleanup(json_t *el)
-{
- if (el == NULL) return NULL;
-#ifndef ENABLE_JSON0
- json_t *new;
- if (json_is_array(el) && json_array_size(el) == 1) {
- new = json_array_get(el, 0);
- return jansson_cleanup(new);
- }
- if (json_is_array(el)) {
- int i = json_array_size(el);
- new = json_array();
- while (i > 0) {
- json_array_insert_new(new, 0,
- jansson_cleanup(json_array_get(el, --i)));
- }
- return new;
- }
- if (json_is_object(el) && json_object_size(el) == 1) {
- new = json_object_get(el, "value");
- if (new) {
- json_incref(new);
- return new; /* This is a string or a boolean, no need to
- * cleanup */
- }
- }
- if (json_is_object(el)) {
- json_t *value;
- json_t *name = NULL;
- void *iter = json_object_iter(el);
- new = json_object();
- while (iter) {
- const char *key;
- key = json_object_iter_key(iter);
- value = jansson_cleanup(json_object_iter_value(iter));
- if (strcmp(key, "name") || !json_is_string(value)) {
- json_object_set_new(new, key, value);
- } else {
- name = value;
- }
- iter = json_object_iter_next(el, iter);
- }
- if (name) {
- /* Embed the current object into a new one with the name
- * as key. */
- new = json_pack("{s: o}", /* o: stolen reference */
- json_string_value(name), new);
- json_decref(name);
- }
- return new;
- }
-#endif
- json_incref(el);
- return el;
-}
-
-static void
-jansson_end(struct writer *w)
-{
- struct json_writer_private *p = w->priv;
- struct json_element *current = TAILQ_LAST(&p->els, json_element_list);
- if (current == NULL) {
- log_warnx("lldpctl", "unbalanced tags");
- return;
- }
- TAILQ_REMOVE(&p->els, current, next);
- free(current);
-
- /* Display current object if last one */
- if (TAILQ_NEXT(TAILQ_FIRST(&p->els), next) == NULL) {
- struct json_element *root = TAILQ_FIRST(&p->els);
- json_t *export = jansson_cleanup(root->el);
- if (json_dumpf(export,
- p->fh,
- JSON_INDENT(2) | JSON_PRESERVE_ORDER) == -1)
- log_warnx("lldpctl", "unable to output JSON");
- fprintf(p->fh,"\n");
- fflush(p->fh);
- json_decref(export);
- json_decref(root->el);
- root->el = json_object();
- if (root->el == NULL)
- fatalx("lldpctl", "cannot create JSON root object");
- }
-}
-
-static void
-jansson_finish(struct writer *w)
-{
- struct json_writer_private *p = w->priv;
- if (TAILQ_EMPTY(&p->els)) {
- log_warnx("lldpctl", "nothing to output");
- } else if (TAILQ_NEXT(TAILQ_FIRST(&p->els), next) != NULL) {
- log_warnx("lldpctl", "unbalanced tags");
- /* memory will leak... */
- } else {
- struct json_element *root = TAILQ_FIRST(&p->els);
- json_decref(root->el);
- TAILQ_REMOVE(&p->els, root, next);
- free(root);
- }
- free(p);
- free(w);
-}
-
-struct writer*
-jansson_init(FILE *fh)
-{
- struct writer *result;
- struct json_writer_private *priv;
- struct json_element *root;
-
- priv = malloc(sizeof(*priv));
- root = malloc(sizeof(*root));
- if (priv == NULL || root == NULL) fatal(NULL, NULL);
-
- priv->fh = fh;
- TAILQ_INIT(&priv->els);
- TAILQ_INSERT_TAIL(&priv->els, root, next);
- root->el = json_object();
- if (root->el == NULL)
- fatalx("lldpctl", "cannot create JSON root object");
-
- result = malloc(sizeof(*result));
- if (result == NULL) fatal(NULL, NULL);
-
- result->priv = priv;
- result->start = jansson_start;
- result->attr = jansson_attr;
- result->data = jansson_data;
- result->end = jansson_end;
- result->finish = jansson_finish;
-
- return result;
-}
--- /dev/null
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2017 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include "writer.h"
+#include "../compat/compat.h"
+#include "../log.h"
+
+enum tag {
+ STRING,
+ BOOL,
+ ARRAY,
+ OBJECT
+};
+
+struct element {
+ struct element *parent; /* Parent (if any) */
+ TAILQ_ENTRY(element) next; /* Sibling (if any) */
+ char *key; /* Key if parent is an object */
+ enum tag tag; /* Kind of element */
+ union {
+ char *string; /* STRING */
+ int boolean; /* BOOL */
+ TAILQ_HEAD(, element) children; /* ARRAY or OBJECT */
+ };
+};
+
+struct json_writer_private {
+ FILE *fh;
+ struct element *root;
+ struct element *current; /* should always be an object */
+};
+
+/* Create a new element. If a parent is provided, it will also be attached to
+ * the parent. */
+static struct element*
+json_element_new(struct element *parent, const char *key, enum tag tag)
+{
+ struct element *child = malloc(sizeof(*child));
+ if (child == NULL) fatal(NULL, NULL);
+ child->parent = parent;
+ child->key = key?strdup(key):NULL;
+ child->tag = tag;
+ TAILQ_INIT(&child->children);
+ if (parent) TAILQ_INSERT_TAIL(&parent->children, child, next);
+ return child;
+}
+
+/* Free the element content (but not the element itself) */
+static void
+json_element_free(struct element *current)
+{
+ struct element *el, *el_next;
+ switch (current->tag) {
+ case STRING:
+ free(current->string);
+ break;
+ case BOOL:
+ break;
+ case ARRAY:
+ case OBJECT:
+ for (el = TAILQ_FIRST(¤t->children);
+ el != NULL;
+ el = el_next) {
+ el_next = TAILQ_NEXT(el, next);
+ json_element_free(el);
+ TAILQ_REMOVE(¤t->children, el, next);
+ if (current->tag == OBJECT) free(el->key);
+ free(el);
+ }
+ break;
+ }
+}
+
+static void
+json_free(struct json_writer_private *p)
+{
+ json_element_free(p->root);
+ free(p->root);
+}
+
+static void
+json_string_dump(FILE *fh, const char *s)
+{
+ fprintf(fh, "\"");
+ while (*s != '\0') {
+ unsigned int c = *s;
+ size_t len;
+ switch (c) {
+ case '"': fprintf(fh, "\\\""); s++; break;
+ case '\\': fprintf(fh, "\\\\"); s++; break;
+ case '\b': fprintf(fh, "\\\b"); s++; break;
+ case '\f': fprintf(fh, "\\\f"); s++; break;
+ case '\n': fprintf(fh, "\\\n"); s++; break;
+ case '\r': fprintf(fh, "\\\r"); s++; break;
+ case '\t': fprintf(fh, "\\\t"); s++; break;
+ default:
+ len = utf8_validate_cz(s);
+ if (len == 0) {
+ /* Not a valid UTF-8 char, use a
+ * replacement character */
+ fprintf(fh, "\\uFFFD");
+ s++;
+ } else if (c < 0x1f) {
+ /* 7-bit ASCII character */
+ fprintf(fh, "\\u%04X", c);
+ s++;
+ } else {
+ /* UTF-8, write as is */
+ while (len--) fprintf(fh, "%c", *s++);
+ }
+ break;
+ }
+ }
+ fprintf(fh, "\"");
+}
+
+/* Dump an element to the specified file handle. */
+static void
+json_element_dump(FILE *fh, struct element *current, int indent)
+{
+ static const char pairs[2][2] = { "{}", "[]" };
+ struct element *el;
+ switch (current->tag) {
+ case STRING:
+ json_string_dump(fh, current->string);
+ break;
+ case BOOL:
+ fprintf(fh, current->boolean?"true":"false");
+ break;
+ case ARRAY:
+ case OBJECT:
+ fprintf(fh, "%c\n%*s", pairs[(current->tag == ARRAY)][0],
+ indent + 2, "");
+ TAILQ_FOREACH(el, ¤t->children, next) {
+ if (current->tag == OBJECT)
+ fprintf(fh, "\"%s\": ", el->key);
+ json_element_dump(fh, el, indent + 2);
+ if (TAILQ_NEXT(el, next))
+ fprintf(fh, ",\n%*s", indent + 2, "");
+ }
+ fprintf(fh, "\n%*c", indent + 1,
+ pairs[(current->tag == ARRAY)][1]);
+ break;
+ }
+}
+
+static void
+json_dump(struct json_writer_private *p)
+{
+ json_element_dump(p->fh, p->root, 0);
+ fprintf(p->fh, "\n");
+}
+
+static void
+json_start(struct writer *w, const char *tag,
+ const char *descr)
+{
+ struct json_writer_private *p = w->priv;
+ struct element *child;
+ struct element *new;
+
+ /* Look for the tag in the current object. */
+ TAILQ_FOREACH(child, &p->current->children, next) {
+ if (!strcmp(child->key, tag)) break;
+ }
+ if (!child)
+ child = json_element_new(p->current, tag, ARRAY);
+
+ /* Queue the new element. */
+ new = json_element_new(child, NULL, OBJECT);
+ p->current = new;
+}
+
+static void
+json_attr(struct writer *w, const char *tag,
+ const char *descr, const char *value)
+{
+ struct json_writer_private *p = w->priv;
+ struct element *new = json_element_new(p->current, tag, STRING);
+ if (value && (!strcmp(value, "yes") || !strcmp(value, "on"))) {
+ new->tag = BOOL;
+ new->boolean = 1;
+ } else if (value && (!strcmp(value, "no") || !strcmp(value, "off"))) {
+ new->tag = BOOL;
+ new->boolean = 0;
+ } else {
+ new->string = strdup(value?value:"");
+ }
+}
+
+static void
+json_data(struct writer *w, const char *data)
+{
+ struct json_writer_private *p = w->priv;
+ struct element *new = json_element_new(p->current, "value", STRING);
+ new->string = strdup(data?data:"");
+}
+
+/* When an array has only one member, just remove the array. When an object has
+ * `value` as the only key, remove the object. Moreover, for an object, move the
+ * `name` key outside (inside a new object). This is a recursive function. We
+ * think the depth will be limited. Also, the provided element can be
+ * destroyed. Don't use it after this function!
+ *
+ * During the cleaning process, we will generate array of 1-size objects that
+ * could be turned into an object. We don't do that since people may rely on
+ * this format. Another problem is the format is changing depending on the
+ * number of interfaces or the number of neighbors.
+ */
+static void
+json_element_cleanup(struct element *el)
+{
+#ifndef ENABLE_JSON0
+ struct element *child, *child_next;
+
+ /* If array with one element, steal the content. Object with only one
+ * value whose key is "value", steal the content. */
+ if ((el->tag == ARRAY || el->tag == OBJECT) &&
+ (child = TAILQ_FIRST(&el->children)) &&
+ !TAILQ_NEXT(child, next) &&
+ (el->tag == ARRAY || !strcmp(child->key, "value"))) {
+ free(child->key);
+ child->key = el->key;
+ child->parent = el->parent;
+ TAILQ_INSERT_BEFORE(el, child, next);
+ TAILQ_REMOVE(&el->parent->children, el, next);
+ free(el);
+ json_element_cleanup(child);
+ return;
+ }
+
+ /* Other kind of arrays, recursively clean */
+ if (el->tag == ARRAY) {
+ for (child = TAILQ_FIRST(&el->children);
+ child;
+ child = child_next) {
+ child_next = TAILQ_NEXT(child, next);
+ json_element_cleanup(child);
+ }
+ return;
+ }
+
+ /* Other kind of objects, recursively clean, but if one key is "name",
+ * use it's value as a key for a new object stealing the existing
+ * one. */
+ if (el->tag == OBJECT) {
+ struct element *name_child = NULL;
+ for (child = TAILQ_FIRST(&el->children);
+ child;
+ child = child_next) {
+ child_next = TAILQ_NEXT(child, next);
+ json_element_cleanup(child);
+ }
+ /* Redo a check to find if we have a "name" key now */
+ for (child = TAILQ_FIRST(&el->children);
+ child;
+ child = child_next) {
+ child_next = TAILQ_NEXT(child, next);
+ if (!strcmp(child->key, "name") &&
+ child->tag == STRING) {
+ name_child = child;
+ }
+ }
+ if (name_child) {
+ struct element *new_el = json_element_new(NULL, NULL, OBJECT);
+ /* Replace el by new_el in parent object/array */
+ new_el->parent = el->parent;
+ TAILQ_INSERT_BEFORE(el, new_el, next);
+ TAILQ_REMOVE(&el->parent->children, el, next);
+ new_el->key = el->key;
+
+ /* new_el is parent of el */
+ el->parent = new_el;
+ el->key = name_child->string; /* stolen */
+ TAILQ_INSERT_TAIL(&new_el->children, el, next);
+
+ /* Remove "name" child */
+ TAILQ_REMOVE(&el->children, name_child, next);
+ free(name_child->key);
+ free(name_child);
+ }
+ return;
+ }
+#endif
+}
+
+static void
+json_cleanup(struct json_writer_private *p)
+{
+ json_element_cleanup(p->root);
+}
+
+static void
+json_end(struct writer *w)
+{
+ struct json_writer_private *p = w->priv;
+ while ((p->current = p->current->parent) != NULL && p->current->tag != OBJECT);
+ if (p->current == NULL) {
+ fatalx("lldpctl", "unbalanced tags");
+ return;
+ }
+
+ /* Display current object if last one */
+ if (p->current == p->root) {
+ json_cleanup(p);
+ json_dump(p);
+ json_free(p);
+ fprintf(p->fh,"\n");
+ fflush(p->fh);
+ p->root = p->current = json_element_new(NULL, NULL, OBJECT);
+ }
+}
+
+static void
+json_finish(struct writer *w)
+{
+ struct json_writer_private *p = w->priv;
+ if (p->current != p->root)
+ log_warnx("lldpctl", "unbalanced tags");
+ json_free(p);
+ free(p);
+ free(w);
+}
+
+struct writer*
+json_init(FILE *fh)
+{
+ struct writer *result;
+ struct json_writer_private *priv;
+
+ priv = malloc(sizeof(*priv));
+ if (priv == NULL) fatal(NULL, NULL);
+
+ priv->fh = fh;
+ priv->root = priv->current = json_element_new(NULL, NULL, OBJECT);
+
+ result = malloc(sizeof(*result));
+ if (result == NULL) fatal(NULL, NULL);
+
+ result->priv = priv;
+ result->start = json_start;
+ result->attr = json_attr;
+ result->data = json_data;
+ result->end = json_end;
+ result->finish = json_finish;
+
+ return result;
+}
+++ /dev/null
-/* -*- mode: c; c-file-style: "openbsd" -*- */
-/*
- * Copyright (c) 2014 Michel Stam <michel@reverze.net>,
- * Vincent Bernat <bernat@luffy.cx>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <json.h>
-#include <sys/queue.h>
-
-#include "writer.h"
-#include "../compat/compat.h"
-#include "../log.h"
-
-/* This list is used as a queue. The queue does not hold reference to the json_t
- * element except the first one. */
-struct json_element {
- TAILQ_ENTRY(json_element) next;
- json_object *el;
-};
-TAILQ_HEAD(json_element_list, json_element);
-struct json_writer_private {
- FILE *fh;
- struct json_element_list els;
-};
-
-static void
-jsonc_start(struct writer *w, const char *tag, const char *descr)
-{
- struct json_writer_private *p = w->priv;
- struct json_element *current = TAILQ_LAST(&p->els, json_element_list);
- struct json_element *new;
- json_object *exist = NULL;
-
- if (!json_object_object_get_ex(current->el, tag, &exist)) {
- exist = json_object_new_array();
- json_object_object_add(current->el, tag, exist);
- }
-
- /* Queue the new element. */
- new = malloc(sizeof(*new));
- if (new == NULL) fatal(NULL, NULL);
- new->el = json_object_new_object();
- json_object_array_add(exist, new->el);
- TAILQ_INSERT_TAIL(&p->els, new, next);
-}
-
-static void
-jsonc_attr(struct writer *w, const char *tag,
- const char *descr, const char *value)
-{
- struct json_writer_private *p = w->priv;
- struct json_element *current = TAILQ_LAST(&p->els, json_element_list);
- json_object *jvalue;
- if (value && (!strcmp(value, "yes") || !strcmp(value, "on")))
- jvalue = json_object_new_boolean(1);
- else if (value && (!strcmp(value, "no") || !strcmp(value, "off")))
- jvalue = json_object_new_boolean(0);
- else
- jvalue = json_object_new_string(value?value:"");
- json_object_object_add(current->el, tag, jvalue);
-}
-
-static void
-jsonc_data(struct writer *w, const char *data)
-{
- struct json_writer_private *p = w->priv;
- struct json_element *current = TAILQ_LAST(&p->els, json_element_list);
- json_object_object_add(current->el, "value",
- json_object_new_string(data?data:""));
-}
-
-/* When an array has only one member, just remove the array. When an object has
- * `value` as the only key, remove the object. Moreover, for an object, move the
- * `name` key outside (inside a new object). This is a recursive function. We
- * think the depth will be limited. */
-static json_object*
-jsonc_cleanup(json_object *el)
-{
- if (el == NULL) return NULL;
-#ifndef ENABLE_JSON0
- json_object *new;
- if (json_object_get_type(el) == json_type_array) {
- size_t len = json_object_array_length(el);
- if (len == 1) {
- new = json_object_array_get_idx(el, 0);
- return jsonc_cleanup(new);
- }
- new = json_object_new_array();
- for (size_t i = 0; i < len; i++) {
- json_object_array_add(new,
- jsonc_cleanup(json_object_array_get_idx(el, i)));
- }
- return new;
- }
- if (json_object_get_type(el) == json_type_object) {
- if (json_object_object_length(el) == 1 &&
- json_object_object_get_ex(el, "value", &new)) {
- json_object_get(new);
- return new; /* This is a string or a boolean, no need to
- * cleanup */
- }
-
- json_object *name = NULL;
- new = json_object_new_object();
- json_object_object_foreach(el, key, value) {
- value = jsonc_cleanup(value);
- if (strcmp(key, "name") ||
- json_object_get_type(value) != json_type_string) {
- json_object_object_add(new, key, value);
- } else {
- name = value;
- }
- }
- if (name) {
- /* Embed the current object into a new one with the name
- * as key. */
- json_object *replacement = json_object_new_object();
- json_object_object_add(replacement,
- json_object_get_string(name), new);
- json_object_put(name);
- return replacement;
- }
- return new;
- }
-#endif
- json_object_get(el);
- return el;
-}
-
-static void
-jsonc_end(struct writer *w)
-{
- struct json_writer_private *p = w->priv;
- struct json_element *current = TAILQ_LAST(&p->els, json_element_list);
- if (current == NULL) {
- log_warnx("lldpctl", "unbalanced tags");
- return;
- }
- TAILQ_REMOVE(&p->els, current, next);
- free(current);
-
- /* Display current object if last one */
- if (TAILQ_NEXT(TAILQ_FIRST(&p->els), next) == NULL) {
- struct json_element *root = TAILQ_FIRST(&p->els);
- json_object *export = jsonc_cleanup(root->el);
- int json_flags = (JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED);
- const char *s = json_object_to_json_string_ext(export, json_flags);
- fprintf(p->fh, "%s\n", s?s:"{}");
- fflush(p->fh);
- json_object_put(export);
- json_object_put(root->el);
- root->el = json_object_new_object();
- if (root->el == NULL)
- fatalx("lldpctl", "cannot create JSON root object");
- }
-}
-
-static void
-jsonc_finish(struct writer *w)
-{
- struct json_writer_private *p = w->priv;
- if (TAILQ_EMPTY(&p->els)) {
- log_warnx("lldpctl", "nothing to output");
- } else if (TAILQ_NEXT(TAILQ_FIRST(&p->els), next) != NULL) {
- log_warnx("lldpctl", "unbalanced tags");
- /* memory will leak... */
- } else {
- struct json_element *root = TAILQ_FIRST(&p->els);
- json_object_put(root->el);
- TAILQ_REMOVE(&p->els, root, next);
- free(root);
- }
- free(p);
- free(w);
-}
-
-struct writer*
-jsonc_init(FILE *fh)
-{
- struct writer *result;
- struct json_writer_private *priv;
- struct json_element *root;
-
- priv = malloc(sizeof(*priv));
- root = malloc(sizeof(*root));
- if (priv == NULL || root == NULL) fatal(NULL, NULL);
-
- priv->fh = fh;
- TAILQ_INIT(&priv->els);
- TAILQ_INSERT_TAIL(&priv->els, root, next);
- root->el = json_object_new_object();
- if (root->el == NULL)
- fatalx("lldpctl", "cannot create JSON root object");
-
- result = malloc(sizeof(*result));
- if (result == NULL) fatal(NULL, NULL);
-
- result->priv = priv;
- result->start = jsonc_start;
- result->attr = jsonc_attr;
- result->data = jsonc_data;
- result->end = jsonc_end;
- result->finish = jsonc_finish;
-
- return result;
-}
fprintf(stderr, "-d Enable more debugging information.\n");
fprintf(stderr, "-u socket Specify the Unix-domain socket used for communication with lldpd(8).\n");
- fprintf(stderr, "-f format Choose output format (plain, keyvalue"
+ fprintf(stderr, "-f format Choose output format (plain, keyvalue, json"
#if defined USE_XML
", xml"
-#endif
-#if defined USE_JANSSON || defined USE_JSONC
- ", json"
#endif
").\n");
if (!is_lldpctl(NULL))
if (strcmp(fmt, "plain") == 0) w = txt_init(stdout);
else if (strcmp(fmt, "keyvalue") == 0) w = kv_init(stdout);
+ else if (strcmp(fmt, "json") == 0) w = json_init(stdout);
#ifdef USE_XML
else if (strcmp(fmt, "xml") == 0) w = xml_init(stdout);
-#endif
-#ifdef USE_JANSSON
- else if (strcmp(fmt, "json") == 0) w = jansson_init(stdout);
-#endif
-#ifdef USE_JSONC
- else if (strcmp(fmt, "json") == 0) w = jsonc_init(stdout);
#endif
else {
log_warnx("lldpctl", "unknown output format \"%s\"", fmt);
--- /dev/null
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ Copyright (c) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include <stddef.h>
+
+/*
+ * Validate a single UTF-8 character starting at @s.
+ * The string must be null-terminated.
+ *
+ * If it's valid, return its length (1 thru 4).
+ * If it's invalid or clipped, return 0.
+ *
+ * This function implements the syntax given in RFC3629, which is
+ * the same as that given in The Unicode Standard, Version 6.0.
+ *
+ * It has the following properties:
+ *
+ * * All codepoints U+0000..U+10FFFF may be encoded,
+ * except for U+D800..U+DFFF, which are reserved
+ * for UTF-16 surrogate pair encoding.
+ * * UTF-8 byte sequences longer than 4 bytes are not permitted,
+ * as they exceed the range of Unicode.
+ * * The sixty-six Unicode "non-characters" are permitted
+ * (namely, U+FDD0..U+FDEF, U+xxFFFE, and U+xxFFFF).
+ */
+size_t
+utf8_validate_cz(const char *s)
+{
+ unsigned char c = *s++;
+
+ if (c <= 0x7F) { /* 00..7F */
+ return 1;
+ } else if (c <= 0xC1) { /* 80..C1 */
+ /* Disallow overlong 2-byte sequence. */
+ return 0;
+ } else if (c <= 0xDF) { /* C2..DF */
+ /* Make sure subsequent byte is in the range 0x80..0xBF. */
+ if (((unsigned char)*s++ & 0xC0) != 0x80)
+ return 0;
+
+ return 2;
+ } else if (c <= 0xEF) { /* E0..EF */
+ /* Disallow overlong 3-byte sequence. */
+ if (c == 0xE0 && (unsigned char)*s < 0xA0)
+ return 0;
+
+ /* Disallow U+D800..U+DFFF. */
+ if (c == 0xED && (unsigned char)*s > 0x9F)
+ return 0;
+
+ /* Make sure subsequent bytes are in the range 0x80..0xBF. */
+ if (((unsigned char)*s++ & 0xC0) != 0x80)
+ return 0;
+ if (((unsigned char)*s++ & 0xC0) != 0x80)
+ return 0;
+
+ return 3;
+ } else if (c <= 0xF4) { /* F0..F4 */
+ /* Disallow overlong 4-byte sequence. */
+ if (c == 0xF0 && (unsigned char)*s < 0x90)
+ return 0;
+
+ /* Disallow codepoints beyond U+10FFFF. */
+ if (c == 0xF4 && (unsigned char)*s > 0x8F)
+ return 0;
+
+ /* Make sure subsequent bytes are in the range 0x80..0xBF. */
+ if (((unsigned char)*s++ & 0xC0) != 0x80)
+ return 0;
+ if (((unsigned char)*s++ & 0xC0) != 0x80)
+ return 0;
+ if (((unsigned char)*s++ & 0xC0) != 0x80)
+ return 0;
+
+ return 4;
+ } else { /* F5..FF */
+ return 0;
+ }
+}
extern struct writer *txt_init(FILE *);
extern struct writer *kv_init(FILE *);
+extern struct writer *json_init(FILE *);
#ifdef USE_XML
extern struct writer *xml_init(FILE *);
#endif
-#ifdef USE_JANSSON
-extern struct writer *jansson_init(FILE *);
-#endif
-#ifdef USE_JSONC
-extern struct writer *jsonc_init(FILE *);
-#endif
+
+/* utf8.c */
+size_t utf8_validate_cz(const char *s);
#endif /* _WRITER_H */
#endif
NULL};
const char *const output_formats[] = {
+ "TEXT",
+ "KV",
+ "JSON",
#ifdef USE_XML
"XML",
-#endif
-#ifdef USE_JSON
- "JSON",
#endif
NULL};
sudo apt-get -qqy update
sudo apt-get -qqy install \
automake autoconf libtool pkg-config \
- libsnmp-dev libxml2-dev libjansson-dev libjson-c-dev \
+ libsnmp-dev libxml2-dev \
libevent-dev libreadline-dev libbsd-dev \
check libc6-dbg libevent-dbg libseccomp-dev \
libpcap-dev