Home | History | Annotate | Download | only in bus
      1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
      2 /* config-loader-libxml.c  libxml2 XML loader
      3  *
      4  * Copyright (C) 2003 Red Hat, Inc.
      5  *
      6  * Licensed under the Academic Free License version 2.1
      7  *
      8  * This program is free software; you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License as published by
     10  * the Free Software Foundation; either version 2 of the License, or
     11  * (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  * GNU General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write to the Free Software
     20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     21  *
     22  */
     23 
     24 #include <config.h>
     25 #include "config-parser.h"
     26 #include <dbus/dbus-internals.h>
     27 #include <libxml/xmlreader.h>
     28 #include <libxml/parser.h>
     29 #include <libxml/globals.h>
     30 #include <libxml/xmlmemory.h>
     31 #ifdef HAVE_ERRNO_H
     32 #include <errno.h>
     33 #endif
     34 #include <string.h>
     35 
     36 /* About the error handling:
     37  *  - setup a "structured" error handler that catches structural
     38  *    errors and some oom errors
     39  *  - assume that a libxml function returning an error code means
     40  *    out-of-memory
     41  */
     42 #define _DBUS_MAYBE_SET_OOM(e) (dbus_error_is_set(e) ? (void)0 : _DBUS_SET_OOM(e))
     43 
     44 
     45 static dbus_bool_t
     46 xml_text_start_element (BusConfigParser   *parser,
     47 			xmlTextReader     *reader,
     48 			DBusError         *error)
     49 {
     50   const char *name;
     51   int n_attributes;
     52   const char **attribute_names, **attribute_values;
     53   dbus_bool_t ret;
     54   int i, status, is_empty;
     55 
     56   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
     57 
     58   ret = FALSE;
     59   attribute_names = NULL;
     60   attribute_values = NULL;
     61 
     62   name = xmlTextReaderConstName (reader);
     63   n_attributes = xmlTextReaderAttributeCount (reader);
     64   is_empty = xmlTextReaderIsEmptyElement (reader);
     65 
     66   if (name == NULL || n_attributes < 0 || is_empty == -1)
     67     {
     68       _DBUS_MAYBE_SET_OOM (error);
     69       goto out;
     70     }
     71 
     72   attribute_names = dbus_new0 (const char *, n_attributes + 1);
     73   attribute_values = dbus_new0 (const char *, n_attributes + 1);
     74   if (attribute_names == NULL || attribute_values == NULL)
     75     {
     76       _DBUS_SET_OOM (error);
     77       goto out;
     78     }
     79   i = 0;
     80   while ((status = xmlTextReaderMoveToNextAttribute (reader)) == 1)
     81     {
     82       _dbus_assert (i < n_attributes);
     83       attribute_names[i] = xmlTextReaderConstName (reader);
     84       attribute_values[i] = xmlTextReaderConstValue (reader);
     85       if (attribute_names[i] == NULL || attribute_values[i] == NULL)
     86 	{
     87           _DBUS_MAYBE_SET_OOM (error);
     88 	  goto out;
     89 	}
     90       i++;
     91     }
     92   if (status == -1)
     93     {
     94       _DBUS_MAYBE_SET_OOM (error);
     95       goto out;
     96     }
     97   _dbus_assert (i == n_attributes);
     98 
     99   ret = bus_config_parser_start_element (parser, name,
    100 					 attribute_names, attribute_values,
    101 					 error);
    102   if (ret && is_empty == 1)
    103     ret = bus_config_parser_end_element (parser, name, error);
    104 
    105  out:
    106   dbus_free (attribute_names);
    107   dbus_free (attribute_values);
    108 
    109   return ret;
    110 }
    111 
    112 static void xml_shut_up (void *ctx, const char *msg, ...)
    113 {
    114     return;
    115 }
    116 
    117 static void
    118 xml_text_reader_error (void *arg, xmlErrorPtr xml_error)
    119 {
    120   DBusError *error = arg;
    121 
    122 #if 0
    123   _dbus_verbose ("XML_ERROR level=%d, domain=%d, code=%d, msg=%s\n",
    124                  xml_error->level, xml_error->domain,
    125                  xml_error->code, xml_error->message);
    126 #endif
    127 
    128   if (!dbus_error_is_set (error))
    129     {
    130       if (xml_error->code == XML_ERR_NO_MEMORY)
    131         _DBUS_SET_OOM (error);
    132       else if (xml_error->level == XML_ERR_ERROR ||
    133                xml_error->level == XML_ERR_FATAL)
    134         dbus_set_error (error, DBUS_ERROR_FAILED,
    135                         "Error loading config file: '%s'",
    136                         xml_error->message);
    137     }
    138 }
    139 
    140 
    141 BusConfigParser*
    142 bus_config_load (const DBusString      *file,
    143                  dbus_bool_t            is_toplevel,
    144                  const BusConfigParser *parent,
    145                  DBusError             *error)
    146 
    147 {
    148   xmlTextReader *reader;
    149   BusConfigParser *parser;
    150   DBusString dirname, data;
    151   DBusError tmp_error;
    152   int ret;
    153 
    154   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    155 
    156   parser = NULL;
    157   reader = NULL;
    158 
    159   if (!_dbus_string_init (&dirname))
    160     {
    161       _DBUS_SET_OOM (error);
    162       return NULL;
    163     }
    164 
    165   if (!_dbus_string_init (&data))
    166     {
    167       _DBUS_SET_OOM (error);
    168       _dbus_string_free (&dirname);
    169       return NULL;
    170     }
    171 
    172   if (is_toplevel)
    173     {
    174       /* xmlMemSetup only fails if one of the functions is NULL */
    175       xmlMemSetup (dbus_free,
    176                    dbus_malloc,
    177                    dbus_realloc,
    178                    _dbus_strdup);
    179       xmlInitParser ();
    180       xmlSetGenericErrorFunc (NULL, xml_shut_up);
    181     }
    182 
    183   if (!_dbus_string_get_dirname (file, &dirname))
    184     {
    185       _DBUS_SET_OOM (error);
    186       goto failed;
    187     }
    188 
    189   parser = bus_config_parser_new (&dirname, is_toplevel, parent);
    190   if (parser == NULL)
    191     {
    192       _DBUS_SET_OOM (error);
    193       goto failed;
    194     }
    195 
    196   if (!_dbus_file_get_contents (&data, file, error))
    197     goto failed;
    198 
    199   reader = xmlReaderForMemory (_dbus_string_get_const_data (&data),
    200                                _dbus_string_get_length (&data),
    201 			       NULL, NULL, 0);
    202   if (reader == NULL)
    203     {
    204       _DBUS_SET_OOM (error);
    205       goto failed;
    206     }
    207 
    208   xmlTextReaderSetParserProp (reader, XML_PARSER_SUBST_ENTITIES, 1);
    209 
    210   dbus_error_init (&tmp_error);
    211   xmlTextReaderSetStructuredErrorHandler (reader, xml_text_reader_error, &tmp_error);
    212 
    213   while ((ret = xmlTextReaderRead (reader)) == 1)
    214     {
    215       int type;
    216 
    217       if (dbus_error_is_set (&tmp_error))
    218         goto reader_out;
    219 
    220       type = xmlTextReaderNodeType (reader);
    221       if (type == -1)
    222         {
    223           _DBUS_MAYBE_SET_OOM (&tmp_error);
    224           goto reader_out;
    225         }
    226 
    227       switch ((xmlReaderTypes) type) {
    228       case XML_READER_TYPE_ELEMENT:
    229 	xml_text_start_element (parser, reader, &tmp_error);
    230 	break;
    231 
    232       case XML_READER_TYPE_TEXT:
    233       case XML_READER_TYPE_CDATA:
    234 	{
    235 	  DBusString content;
    236 	  const char *value;
    237 	  value = xmlTextReaderConstValue (reader);
    238 	  if (value != NULL)
    239 	    {
    240 	      _dbus_string_init_const (&content, value);
    241 	      bus_config_parser_content (parser, &content, &tmp_error);
    242 	    }
    243           else
    244             _DBUS_MAYBE_SET_OOM (&tmp_error);
    245 	  break;
    246 	}
    247 
    248       case XML_READER_TYPE_DOCUMENT_TYPE:
    249 	{
    250 	  const char *name;
    251 	  name = xmlTextReaderConstName (reader);
    252 	  if (name != NULL)
    253 	    bus_config_parser_check_doctype (parser, name, &tmp_error);
    254           else
    255             _DBUS_MAYBE_SET_OOM (&tmp_error);
    256 	  break;
    257 	}
    258 
    259       case XML_READER_TYPE_END_ELEMENT:
    260 	{
    261 	  const char *name;
    262 	  name = xmlTextReaderConstName (reader);
    263 	  if (name != NULL)
    264 	    bus_config_parser_end_element (parser, name, &tmp_error);
    265           else
    266             _DBUS_MAYBE_SET_OOM (&tmp_error);
    267 	  break;
    268 	}
    269 
    270       case XML_READER_TYPE_DOCUMENT:
    271       case XML_READER_TYPE_DOCUMENT_FRAGMENT:
    272       case XML_READER_TYPE_PROCESSING_INSTRUCTION:
    273       case XML_READER_TYPE_COMMENT:
    274       case XML_READER_TYPE_ENTITY:
    275       case XML_READER_TYPE_NOTATION:
    276       case XML_READER_TYPE_WHITESPACE:
    277       case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
    278       case XML_READER_TYPE_END_ENTITY:
    279       case XML_READER_TYPE_XML_DECLARATION:
    280 	/* nothing to do, just read on */
    281 	break;
    282 
    283       case XML_READER_TYPE_NONE:
    284       case XML_READER_TYPE_ATTRIBUTE:
    285       case XML_READER_TYPE_ENTITY_REFERENCE:
    286 	_dbus_assert_not_reached ("unexpected nodes in XML");
    287       }
    288 
    289       if (dbus_error_is_set (&tmp_error))
    290         goto reader_out;
    291     }
    292 
    293   if (ret == -1)
    294     _DBUS_MAYBE_SET_OOM (&tmp_error);
    295 
    296  reader_out:
    297   xmlFreeTextReader (reader);
    298   reader = NULL;
    299   if (dbus_error_is_set (&tmp_error))
    300     {
    301       dbus_move_error (&tmp_error, error);
    302       goto failed;
    303     }
    304 
    305   if (!bus_config_parser_finished (parser, error))
    306     goto failed;
    307   _dbus_string_free (&dirname);
    308   _dbus_string_free (&data);
    309   if (is_toplevel)
    310     xmlCleanupParser();
    311   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    312   return parser;
    313 
    314  failed:
    315   _DBUS_ASSERT_ERROR_IS_SET (error);
    316   _dbus_string_free (&dirname);
    317   _dbus_string_free (&data);
    318   if (is_toplevel)
    319     xmlCleanupParser();
    320   if (parser)
    321     bus_config_parser_unref (parser);
    322   _dbus_assert (reader == NULL); /* must go to reader_out first */
    323   return NULL;
    324 }
    325