]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
Implement an XML writer.
authorAndreas Hofmeister <andi@collax.com>
Sun, 28 Feb 2010 14:32:01 +0000 (15:32 +0100)
committerVincent <bernat@luffy.cx>
Sat, 6 Mar 2010 09:26:46 +0000 (10:26 +0100)
XML output can be enabled with the "--with-xml" configure option. libxml2 is
used to create the actual XML output.

configure.ac
m4/xml2.m4 [new file with mode: 0644]
man/lldpctl.8
src/Makefile.am
src/display.c
src/lldpctl.c
src/writer.h
src/xml_writer.c [new file with mode: 0644]

index 700340e85386371c2519be7fd3e7d8e2ab971f50..ae684b3f37903b46a9c34fc99bcc0f25291d8b9a 100644 (file)
@@ -204,6 +204,15 @@ if test x"$with_snmp" = x"yes"; then
    lldp_CHECK_SNMP
 fi
 
+AC_ARG_WITH([xml],
+  AC_HELP_STRING(
+    [--with-xml],
+    [Enable XML output via libxml2 @<:@default=no:>@]
+  ))
+if test x"$with_xml" = x"yes"; then
+   lldp_CHECK_XML2
+fi
+
 # Privsep settings
 lldp_ARG_WITH([privsep-user], [Which user to use for privilege separation], [_lldpd])
 lldp_ARG_WITH([privsep-group], [Which group to use for privilege separation], [_lldpd])
@@ -227,6 +236,7 @@ lldp_ARG_ENABLE([listenvlan], [listen on any VLAN], [no])
 # Output results
 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"])
 AC_OUTPUT
 
 cat <<EOF
@@ -246,6 +256,7 @@ cat <<EOF
   DOT1...........: $enable_dot1
   DOT3...........: $enable_dot3
   Listen on VLAN.: $enable_listenvlan
+  XML output.....: ${with_xml-no}
 ---------------------------------------------
 
 Check the above options and compile with:
diff --git a/m4/xml2.m4 b/m4/xml2.m4
new file mode 100644 (file)
index 0000000..6da8561
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# lldp_CHECK_XML2
+#
+
+
+AC_DEFUN([lldp_CHECK_XML2], [
+   AC_PATH_TOOL([XML2_CONFIG], [xml2-config], [no])
+   if test x"$XML2_CONFIG" = x"no"; then
+      AC_MSG_ERROR([*** unable to find xml2-config])
+   fi
+   XML2_LIBS=`${XML2_CONFIG} --libs`
+   XML2_CFLAGS=`${XML2_CONFIG} --cflags`
+
+   _save_flags="$CFLAGS"
+   CFLAGS="$CFLAGS ${XML2_CFLAGS}"
+   AC_MSG_CHECKING([whether C compiler supports flag "${XML2_CFLAGS}" from libxml2])
+   AC_LINK_IFELSE([AC_LANG_PROGRAM([
+int main(void);
+],
+[
+{
+  return 0;
+}
+])],[AC_MSG_RESULT(yes)],[
+AC_MSG_RESULT(no)
+AC_MSG_ERROR([*** incorrect CFLAGS from xml2-config])])
+   AC_CHECK_LIB([xml2], [xmlNewTextWriterDoc], [],
+       [AC_MSG_ERROR([*** unable to use xml2])], ${XML2_LIBS})
+   AC_SUBST([XML2_LIBS])
+   AC_SUBST([XML2_CFLAGS])
+   AC_DEFINE_UNQUOTED([USE_XML], 1, [Define to indicate to enable XML support])
+
+   CFLAGS="$_save_flags"
+])
index 6407d1e405772ebec7386bd78fce12a183dfdcfe..416b63a6db1c1c6584fff7f745137e758d9581b0 100644 (file)
@@ -41,6 +41,13 @@ The options are as follows:
 .Bl -tag -width Ds
 .It Fl d
 Enable more debugging information.
+.It Fl f Ar format
+Choose the output format. Currently
+.Em plain
+and
+.Em xml
+formats are available. The default is
+.Em plain.
 .It Fl L Ar location
 Enable the transmission of LLDP-MED location TLV for the given
 interfaces. This option can be repeated several times to enable the
index 8770313479f73707f4fcc90cd31c5eac95f70b60..ec471b506e7736bd76c716e49916030f62a0a8fa 100644 (file)
@@ -24,3 +24,11 @@ liblldpd_la_SOURCES += agent.c agent_priv.c
 liblldpd_la_CFLAGS = @NETSNMP_CFLAGS@
 lldpd_LDADD += @NETSNMP_LIBS@
 endif
+
+if USE_XML
+lldpctl_SOURCES += xml_writer.c
+lldpctl_CFLAGS = @XML2_CFLAGS@
+lldpctl_LDADD  += @XML2_LIBS@
+endif
+
+
index 3c066bdbe948bc210347f907c08501bf26c14561..8e1be2774ef1a9c84aa48801114d516b282846d3 100644 (file)
@@ -663,9 +663,9 @@ display_med(struct writer *w, struct lldpd_chassis *chassis, struct lldpd_port *
                                free(value);
                                break;
                        default:
-                               LLOG_WARN("unknown location data format: \n   %s",
-                                   dump(port->p_med_location[i].data,
-                                       port->p_med_location[i].data_len, 20, ' '));
+                               tag_attr(w, "type", "", "unknown");
+                               tag_data(w, dump(port->p_med_location[i].data,
+                                            port->p_med_location[i].data_len, 20, ' '));
                        }
                        tag_end(w);
                }
@@ -922,7 +922,7 @@ display_age(struct lldpd_port *port)
 }
 
 void
-display_interfaces(int s, int argc, char *argv[])
+display_interfaces(int s, const char * fmt, int argc, char *argv[])
 {
        struct writer * w;
        int i, nb;
@@ -935,7 +935,17 @@ display_interfaces(int s, int argc, char *argv[])
        struct lldpd_port port;
        char sep[80];
 
-       w = txt_init( stdout );
+       if ( strcmp(fmt,"plain") == 0 ) {
+               w = txt_init( stdout );
+       }
+#ifdef USE_XML
+       else if ( strcmp(fmt,"xml") == 0 ) {
+               w = xml_init( stdout );
+       }
+#endif
+       else {
+               w = txt_init( stdout );
+       }
 
        memset(sep, '-', 79);
        sep[79] = 0;
index 38b32ce39b8572b9c5dbc74b7ada20c5c66df0e2..7480e81f29c6e02a2d6b7f0187dfd08ca0cd0754 100644 (file)
@@ -39,7 +39,7 @@ extern void
 get_interfaces(int s, struct interfaces *ifs);
 
 extern void
-display_interfaces(int s, int argc, char *argv[]);
+display_interfaces(int s, const char * fmt, int argc, char *argv[]);
 
 static void
 usage(void)
@@ -294,17 +294,21 @@ int
 main(int argc, char *argv[])
 {
        int ch, s, debug = 1;
+       char * fmt = "plain";
 #define ACTION_SET_LOCATION 1
        int action = 0;
        
        /*
         * Get and parse command line options
         */
-       while ((ch = getopt(argc, argv, "dL:")) != -1) {
+       while ((ch = getopt(argc, argv, "df:L:")) != -1) {
                switch (ch) {
                case 'd':
                        debug++;
                        break;
+               case 'f':
+                       fmt = optarg;
+                       break;
                case 'L':
 #ifdef ENABLE_LLDPMED
                        action = ACTION_SET_LOCATION;
@@ -334,7 +338,7 @@ main(int argc, char *argv[])
                break;
 #endif
        default:
-               display_interfaces(s, argc, argv);
+               display_interfaces(s, fmt, argc, argv);
        }
        
        close(s);
index 4af13797370d17408545452e14c68eb6a8d3dc0c..4b4b89125adff2d284d3a1cdd17cf5da3f2f57a0 100644 (file)
@@ -36,4 +36,8 @@ struct writer {
 
 extern struct writer * txt_init( FILE * );
 
+#ifdef USE_XML
+extern struct writer * xml_init( FILE * );
+#endif
+
 #endif /* _WRITER_H */
diff --git a/src/xml_writer.c b/src/xml_writer.c
new file mode 100644 (file)
index 0000000..e7d2eed
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2010 Andreas Hofmeister <andi@collax.com>
+ *
+ * Permission to use, copy, modify, and 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/encoding.h>
+#include <libxml/xmlwriter.h>
+
+#include "writer.h"
+#include "lldpd.h"
+
+struct xml_writer_private {
+       xmlTextWriterPtr xw;
+       xmlDocPtr doc;
+};
+
+void xml_start(struct writer * w , const char * tag, const char * descr ) {
+       struct xml_writer_private * p = w->priv;
+
+       if (xmlTextWriterStartElement(p->xw, BAD_CAST tag) < 0)
+               LLOG_WARN("cannot start '%s' element\n", tag);
+}
+
+void xml_attr(struct writer * w, const char * tag, const char * descr, const char * value ) {
+       struct xml_writer_private * p = w->priv;
+
+       if (xmlTextWriterWriteFormatAttribute(p->xw, BAD_CAST tag, "%s", value) < 0)
+               LLOG_WARN("cannot add attribute %s with value %s\n", tag, value);
+}
+
+void xml_data(struct writer * w, const char * data) {
+       struct xml_writer_private * p = w->priv;
+
+       if (xmlTextWriterWriteString(p->xw, BAD_CAST data) < 0 )
+               LLOG_WARN("cannot add '%s' as data to element\n", data);
+}
+
+void xml_end(struct writer * w) {
+       struct xml_writer_private * p = w->priv;
+
+       if (xmlTextWriterEndElement(p->xw) < 0 )
+               LLOG_WARN("cannot end element\n");
+}
+
+#define MY_ENCODING "UTF-8"
+
+void xml_finish(struct writer * w) {
+       struct xml_writer_private * p = w->priv;
+       int failed = 0;
+
+       if (xmlTextWriterEndDocument(p->xw) < 0 ) {
+               LLOG_WARN("cannot finish document\n");
+               failed = 1;
+       }
+
+       xmlFreeTextWriter(p->xw);
+       
+       if ( ! failed )
+               xmlSaveFileEnc("-", p->doc, MY_ENCODING);
+
+       xmlFreeDoc(p->doc);
+
+       free( w->priv );
+       free( w );
+}
+
+struct writer * xml_init(FILE * fh) {
+
+       struct writer * result;
+       struct xml_writer_private * priv;
+
+       priv = malloc( sizeof( *priv ) );
+       if ( ! priv ) {
+               fatalx("out of memory\n");
+               return NULL;
+       }
+
+       priv->xw = xmlNewTextWriterDoc(&(priv->doc), 0);
+       if ( ! priv->xw ) {
+               fatalx("cannot create xml writer\n");
+               return NULL;
+       }
+
+       xmlTextWriterSetIndent(priv->xw, 4);
+
+       if (xmlTextWriterStartDocument(priv->xw, NULL, MY_ENCODING, NULL) < 0 ) {
+               fatalx("cannot start xml document\n");
+               return NULL;
+       }
+
+       result = malloc( sizeof( struct writer ) );
+       if ( ! result ) {
+               fatalx("out of memory\n");
+               return NULL;
+       }
+
+       result->priv  = priv;
+       result->start = xml_start;
+       result->attr  = xml_attr;
+       result->data  = xml_data;
+       result->end   = xml_end;
+       result->finish= xml_finish;
+
+       return result;
+}
+