2003-03-30 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Mon, 31 Mar 2003 04:01:00 +0000 (04:01 +0000)
committerHavoc Pennington <hp@redhat.com>
Mon, 31 Mar 2003 04:01:00 +0000 (04:01 +0000)
* bus/config-parser.c: hacking

* dbus/dbus-memory.c: don't use DBusList for the list of stuff
to shut down, since it could cause weirdness with the DBusList
lock

* dbus/dbus-list.c (_dbus_list_test): add tests for the
link-oriented stack routines
(alloc_link): free the mempool if the first alloc from it fails

* dbus/dbus-mempool.c (struct DBusMemBlock): fix alignment issue

* dbus/dbus-string.c (UNICODE_VALID): sync new version of this
from GLib
(_dbus_string_skip_white): new

* doc/config-file.txt (Elements): add <includedir>

15 files changed:
ChangeLog
bus/config-loader-expat.c
bus/config-parser.c
bus/test-main.c
dbus/dbus-internals.c
dbus/dbus-internals.h
dbus/dbus-list.c
dbus/dbus-list.h
dbus/dbus-memory.c
dbus/dbus-mempool.c
dbus/dbus-string.c
dbus/dbus-string.h
dbus/dbus-threads.c
doc/config-file.txt
test/data/valid-config-files/basic.conf

index 276235c..01ce426 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2003-03-30  Havoc Pennington  <hp@pobox.com>
+
+       * bus/config-parser.c: hacking
+       
+       * dbus/dbus-memory.c: don't use DBusList for the list of stuff 
+       to shut down, since it could cause weirdness with the DBusList
+       lock
+
+       * dbus/dbus-list.c (_dbus_list_test): add tests for the
+       link-oriented stack routines
+       (alloc_link): free the mempool if the first alloc from it fails
+
+       * dbus/dbus-mempool.c (struct DBusMemBlock): fix alignment issue
+
+       * dbus/dbus-string.c (UNICODE_VALID): sync new version of this
+       from GLib
+       (_dbus_string_skip_white): new
+
+       * doc/config-file.txt (Elements): add <includedir>
+
+2003-03-28  Havoc Pennington  <hp@pobox.com>
+
+       * dbus/dbus-string.c (_dbus_string_copy_data_len)
+       (_dbus_string_copy_data): new functions
+
 2003-03-28  Anders Carlsson  <andersca@codefactory.se>
 
        * dbus/dbus-bus.c: (bus_data_free), (dbus_bus_get):
index c7981bf..a3740a4 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2003 Red Hat, Inc.
  *
  * Licensed under the Academic Free License version 1.2
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -14,7 +14,7 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
@@ -41,6 +41,27 @@ typedef struct
   dbus_bool_t failed;
 } ExpatParseContext;
 
+static dbus_bool_t
+process_content (ExpatParseContext *context)
+{
+  if (context->failed)
+    return FALSE;
+
+  if (_dbus_string_get_length (&context->content) > 0)
+    {
+      if (!bus_config_parser_content (context->parser,
+                                      &context->content,
+                                      context->error))
+        {
+          context->failed = TRUE;
+          return FALSE;
+        }
+      _dbus_string_set_length (&context->content, 0);
+    }
+
+  return TRUE;
+}
+
 static void
 expat_StartElementHandler (void            *userData,
                            const XML_Char  *name,
@@ -50,13 +71,16 @@ expat_StartElementHandler (void            *userData,
   int i;
   char **names;
   char **values;
-  
+
   /* Expat seems to suck and can't abort the parse if we
    * throw an error. Expat 2.0 is supposed to fix this.
    */
   if (context->failed)
     return;
 
+  if (!process_content (context))
+    return;
+
   /* "atts" is key, value, key, value, NULL */
   for (i = 0; atts[i] != NULL; ++i)
     ; /* nothing */
@@ -73,17 +97,17 @@ expat_StartElementHandler (void            *userData,
       dbus_free (values);
       return;
     }
-  
+
   i = 0;
   while (atts[i] != NULL)
     {
       _dbus_assert (i % 2 == 0);
-      names [i / 2]     = (char*) atts[i];
-      values[i / 2 + 1] = (char*) atts[i+1];
-      
+      names [i / 2] = (char*) atts[i];
+      values[i / 2] = (char*) atts[i+1];
+
       i += 2;
     }
-  
+
   if (!bus_config_parser_start_element (context->parser,
                                         name,
                                         (const char **) names,
@@ -105,20 +129,9 @@ expat_EndElementHandler (void           *userData,
                          const XML_Char *name)
 {
   ExpatParseContext *context = userData;
-  if (context->failed)
-    return;
 
-  if (_dbus_string_get_length (&context->content) > 0)
-    {
-      if (!bus_config_parser_content (context->parser,
-                                      &context->content,
-                                      context->error))
-        {
-          context->failed = TRUE;
-          return;
-        }
-      _dbus_string_set_length (&context->content, 0);
-    }
+  if (!process_content (context))
+    return;
 
   if (!bus_config_parser_end_element (context->parser,
                                       name,
@@ -157,22 +170,22 @@ bus_config_load (const DBusString *file,
   const char *filename;
   BusConfigParser *parser;
   ExpatParseContext context;
-  
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   parser = NULL;
   expat = NULL;
   context.error = error;
   context.failed = FALSE;
-  
+
   _dbus_string_get_const_data (file, &filename);
-  
+
   if (!_dbus_string_init (&context.content, _DBUS_INT_MAX))
     {
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       return NULL;
     }
-  
+
   expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL);
   if (expat == NULL)
     {
@@ -186,6 +199,7 @@ bus_config_load (const DBusString *file,
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       goto failed;
     }
+  context.parser = parser;
 
   XML_SetUserData (expat, &context);
   XML_SetElementHandler (expat,
@@ -197,28 +211,28 @@ bus_config_load (const DBusString *file,
   {
     DBusString data;
     const char *data_str;
-    
+
     if (!_dbus_string_init (&data, _DBUS_INT_MAX))
       {
         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
         goto failed;
       }
-    
+
     if (!_dbus_file_get_contents (&data, file, error))
       {
         _dbus_string_free (&data);
         goto failed;
       }
-    
+
     _dbus_string_get_const_data (&data, &data_str);
-    
+
     if (!XML_Parse (expat, data_str, _dbus_string_get_length (&data), TRUE))
       {
         if (context.error != NULL &&
             !dbus_error_is_set (context.error))
           {
             enum XML_Error e;
-            
+
             e = XML_GetErrorCode (expat);
             if (e == XML_ERROR_NO_MEMORY)
               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
@@ -230,7 +244,7 @@ bus_config_load (const DBusString *file,
                               XML_GetCurrentColumnNumber (expat),
                               XML_ErrorString (e));
           }
-        
+
         _dbus_string_free (&data);
         goto failed;
       }
@@ -240,7 +254,7 @@ bus_config_load (const DBusString *file,
     if (context.failed)
       goto failed;
   }
-  
+
   if (!bus_config_parser_finished (parser, error))
     goto failed;
 
@@ -249,10 +263,10 @@ bus_config_load (const DBusString *file,
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   return parser;
-  
+
  failed:
   _DBUS_ASSERT_ERROR_IS_SET (error);
-  
+
   _dbus_string_free (&context.content);
   if (expat)
     XML_ParserFree (expat);
index 2429cce..972c05a 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2003 Red Hat, Inc.
  *
  * Licensed under the Academic Free License version 1.2
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -14,7 +14,7 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 typedef enum
 {
+  ELEMENT_NONE,
   ELEMENT_BUSCONFIG,
   ELEMENT_INCLUDE,
   ELEMENT_USER,
   ELEMENT_LISTEN,
   ELEMENT_AUTH,
   ELEMENT_POLICY,
-  ELEMENT_LIMIT
+  ELEMENT_LIMIT,
+  ELEMENT_ALLOW,
+  ELEMENT_DENY
 } ElementType;
 
 typedef struct
 {
   ElementType type;
 
+  unsigned int had_content : 1;
+
   union
   {
     struct
     {
-      BusConfigParser *parser;
+      unsigned int ignore_missing : 1;
     } include;
 
     struct
     {
-      char *username;
-    } user;
-
-    struct
-    {
-      char *address;
-    } listen;
-
-    struct
-    {
       char *mechanism;
     } auth;
 
@@ -75,20 +70,53 @@ typedef struct
     {
       int foo;
     } limit;
-    
+
   } d;
-  
+
 } Element;
 
 struct BusConfigParser
 {
   int refcount;
 
-  DBusList *stack; /**< stack of Element */
+  DBusList *stack;     /**< stack of Element */
 
-  char *user;      /**< user to run as */
+  char *user;          /**< user to run as */
+
+  DBusList *listen_on; /**< List of addresses to listen to */
 };
 
+static const char*
+element_type_to_name (ElementType type)
+{
+  switch (type)
+    {
+    case ELEMENT_NONE:
+      return NULL;
+    case ELEMENT_BUSCONFIG:
+      return "busconfig";
+    case ELEMENT_INCLUDE:
+      return "include";
+    case ELEMENT_USER:
+      return "user";
+    case ELEMENT_LISTEN:
+      return "listen";
+    case ELEMENT_AUTH:
+      return "auth";
+    case ELEMENT_POLICY:
+      return "policy";
+    case ELEMENT_LIMIT:
+      return "limit";
+    case ELEMENT_ALLOW:
+      return "allow";
+    case ELEMENT_DENY:
+      return "deny";
+    }
+
+  _dbus_assert_not_reached ("bad element type");
+
+  return NULL;
+}
 
 static Element*
 push_element (BusConfigParser *parser,
@@ -96,9 +124,17 @@ push_element (BusConfigParser *parser,
 {
   Element *e;
 
+  _dbus_assert (type != ELEMENT_NONE);
+  
   e = dbus_new0 (Element, 1);
   if (e == NULL)
     return NULL;
+
+  if (!_dbus_list_append (&parser->stack, e))
+    {
+      dbus_free (e);
+      return NULL;
+    }
   
   e->type = type;
 
@@ -106,13 +142,63 @@ push_element (BusConfigParser *parser,
 }
 
 static void
+element_free (Element *e)
+{
+
+  dbus_free (e);
+}
+
+static void
 pop_element (BusConfigParser *parser)
 {
   Element *e;
 
   e = _dbus_list_pop_last (&parser->stack);
+  
+  element_free (e);
+}
 
-  dbus_free (e);
+static Element*
+peek_element (BusConfigParser *parser)
+{
+  Element *e;
+
+  e = _dbus_list_get_last (&parser->stack);
+
+  return e;
+}
+
+static ElementType
+top_element_type (BusConfigParser *parser)
+{
+  Element *e;
+
+  e = _dbus_list_get_last (&parser->stack);
+
+  if (e)
+    return e->type;
+  else
+    return ELEMENT_NONE;
+}
+
+static dbus_bool_t
+merge_included (BusConfigParser *parser,
+                BusConfigParser *included,
+                DBusError       *error)
+{
+  DBusList *link;
+
+  if (included->user != NULL)
+    {
+      dbus_free (parser->user);
+      parser->user = included->user;
+      included->user = NULL;
+    }
+
+  while ((link = _dbus_list_pop_first_link (&included->listen_on)))
+    _dbus_list_append_link (&parser->listen_on, link);
+
+  return TRUE;
 }
 
 BusConfigParser*
@@ -148,9 +234,15 @@ bus_config_parser_unref (BusConfigParser *parser)
     {
       while (parser->stack != NULL)
         pop_element (parser);
-      
+
       dbus_free (parser->user);
 
+      _dbus_list_foreach (&parser->listen_on,
+                          (DBusForeachFunction) dbus_free,
+                          NULL);
+
+      _dbus_list_clear (&parser->listen_on);
+
       dbus_free (parser);
     }
 }
@@ -161,12 +253,12 @@ bus_config_parser_check_doctype (BusConfigParser   *parser,
                                  DBusError         *error)
 {
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   if (strcmp (doctype, "busconfig") != 0)
     {
       dbus_set_error (error,
                       DBUS_ERROR_FAILED,
-                      "Document has the wrong type %s",
+                      "Configuration file has the wrong document type %s",
                       doctype);
       return FALSE;
     }
@@ -174,6 +266,271 @@ bus_config_parser_check_doctype (BusConfigParser   *parser,
     return TRUE;
 }
 
+typedef struct
+{
+  const char  *name;
+  const char **retloc;
+} LocateAttr;
+
+static dbus_bool_t
+locate_attributes (BusConfigParser  *parser,
+                   const char       *element_name,
+                   const char      **attribute_names,
+                   const char      **attribute_values,
+                   DBusError        *error,
+                   const char       *first_attribute_name,
+                   const char      **first_attribute_retloc,
+                   ...)
+{
+  va_list args;
+  const char *name;
+  const char **retloc;
+  int n_attrs;
+#define MAX_ATTRS 24
+  LocateAttr attrs[MAX_ATTRS];
+  dbus_bool_t retval;
+  int i;
+
+  _dbus_assert (first_attribute_name != NULL);
+  _dbus_assert (first_attribute_retloc != NULL);
+
+  retval = TRUE;
+
+  n_attrs = 1;
+  attrs[0].name = first_attribute_name;
+  attrs[0].retloc = first_attribute_retloc;
+  *first_attribute_retloc = NULL;
+
+  va_start (args, first_attribute_retloc);
+
+  name = va_arg (args, const char*);
+  retloc = va_arg (args, const char**);
+
+  while (name != NULL)
+    {
+      _dbus_assert (retloc != NULL);
+      _dbus_assert (n_attrs < MAX_ATTRS);
+
+      attrs[n_attrs].name = name;
+      attrs[n_attrs].retloc = retloc;
+      n_attrs += 1;
+      *retloc = NULL;
+
+      name = va_arg (args, const char*);
+      retloc = va_arg (args, const char**);
+    }
+
+  va_end (args);
+
+  if (!retval)
+    return retval;
+
+  i = 0;
+  while (attribute_names[i])
+    {
+      int j;
+      dbus_bool_t found;
+      
+      found = FALSE;
+      j = 0;
+      while (j < n_attrs)
+        {
+          if (strcmp (attrs[j].name, attribute_names[i]) == 0)
+            {
+              retloc = attrs[j].retloc;
+
+              if (*retloc != NULL)
+                {
+                  dbus_set_error (error, DBUS_ERROR_FAILED,
+                                  "Attribute \"%s\" repeated twice on the same <%s> element",
+                                  attrs[j].name, element_name);
+                  retval = FALSE;
+                  goto out;
+                }
+
+              *retloc = attribute_values[i];
+              found = TRUE;
+            }
+
+          ++j;
+        }
+
+      if (!found)
+        {
+          dbus_set_error (error, DBUS_ERROR_FAILED,
+                          "Attribute \"%s\" is invalid on <%s> element in this context",
+                          attribute_names[i], element_name);
+          retval = FALSE;
+          goto out;
+        }
+
+      ++i;
+    }
+
+ out:
+  return retval;
+}
+
+static dbus_bool_t
+check_no_attributes (BusConfigParser  *parser,
+                     const char       *element_name,
+                     const char      **attribute_names,
+                     const char      **attribute_values,
+                     DBusError        *error)
+{
+  if (attribute_names[0] != NULL)
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Attribute \"%s\" is invalid on <%s> element in this context",
+                      attribute_names[0], element_name);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static dbus_bool_t
+start_busconfig_child (BusConfigParser   *parser,
+                       const char        *element_name,
+                       const char       **attribute_names,
+                       const char       **attribute_values,
+                       DBusError         *error)
+{
+  if (strcmp (element_name, "user") == 0)
+    {
+      if (!check_no_attributes (parser, "user", attribute_names, attribute_values, error))
+        return FALSE;
+
+      if (push_element (parser, ELEMENT_USER) == NULL)
+        {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          return FALSE;
+        }
+
+      return TRUE;
+    }
+  else if (strcmp (element_name, "listen") == 0)
+    {
+      if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error))
+        return FALSE;
+
+      if (push_element (parser, ELEMENT_LISTEN) == NULL)
+        {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          return FALSE;
+        }
+
+      return TRUE;
+    }
+  else if (strcmp (element_name, "include") == 0)
+    {
+      Element *e;
+      const char *ignore_missing;
+
+      if ((e = push_element (parser, ELEMENT_INCLUDE)) == NULL)
+        {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          return FALSE;
+        }
+
+      e->d.include.ignore_missing = FALSE;
+
+      if (!locate_attributes (parser, "include",
+                              attribute_names,
+                              attribute_values,
+                              error,
+                              "ignore_missing", &ignore_missing,
+                              NULL))
+        return FALSE;
+
+      if (ignore_missing != NULL)
+        {
+          if (strcmp (ignore_missing, "yes") == 0)
+            e->d.include.ignore_missing = TRUE;
+          else if (strcmp (ignore_missing, "no") == 0)
+            e->d.include.ignore_missing = FALSE;
+          else
+            {
+              dbus_set_error (error, DBUS_ERROR_FAILED,
+                              "ignore_missing attribute must have value \"yes\" or \"no\"");
+              return FALSE;
+            }
+        }
+
+      return TRUE;
+    }
+  else if (strcmp (element_name, "policy") == 0)
+    {
+      Element *e;
+      const char *context;
+      const char *user;
+      const char *group;
+
+      if ((e = push_element (parser, ELEMENT_POLICY)) == NULL)
+        {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          return FALSE;
+        }
+
+      if (!locate_attributes (parser, "include",
+                              attribute_names,
+                              attribute_values,
+                              error,
+                              "context", &context,
+                              "user", &user,
+                              "group", &group,
+                              NULL))
+        return FALSE;
+
+      /* FIXME */
+      
+      return TRUE;
+    }
+  else
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Element <%s> not allowed inside <%s> in configuration file",
+                      element_name, "busconfig");
+      return FALSE;
+    }
+}
+
+static dbus_bool_t
+start_policy_child (BusConfigParser   *parser,
+                    const char        *element_name,
+                    const char       **attribute_names,
+                    const char       **attribute_values,
+                    DBusError         *error)
+{
+  if (strcmp (element_name, "allow") == 0)
+    {
+      if (push_element (parser, ELEMENT_ALLOW) == NULL)
+        {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          return FALSE;
+        }
+      
+      return TRUE;
+    }
+  else if (strcmp (element_name, "deny") == 0)
+    {
+      if (push_element (parser, ELEMENT_DENY) == NULL)
+        {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          return FALSE;
+        }
+      
+      return TRUE;
+    }
+  else
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Element <%s> not allowed inside <%s> in configuration file",
+                      element_name, "policy");
+      return FALSE;
+    }
+}
+
 dbus_bool_t
 bus_config_parser_start_element (BusConfigParser   *parser,
                                  const char        *element_name,
@@ -181,9 +538,56 @@ bus_config_parser_start_element (BusConfigParser   *parser,
                                  const char       **attribute_values,
                                  DBusError         *error)
 {
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);  
+  ElementType t;
 
-  return TRUE;
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  /* printf ("START: %s\n", element_name); */
+  
+  t = top_element_type (parser);
+
+  if (t == ELEMENT_NONE)
+    {
+      if (strcmp (element_name, "busconfig") == 0)
+        {
+          if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
+            return FALSE;
+          
+          if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
+            {
+              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+              return FALSE;
+            }
+
+          return TRUE;
+        }
+      else
+        {
+          dbus_set_error (error, DBUS_ERROR_FAILED,
+                          "Unknown element <%s> at root of configuration file",
+                          element_name);
+          return FALSE;
+        }
+    }
+  else if (t == ELEMENT_BUSCONFIG)
+    {
+      return start_busconfig_child (parser, element_name,
+                                    attribute_names, attribute_values,
+                                    error);
+    }
+  else if (t == ELEMENT_POLICY)
+    {
+      return start_policy_child (parser, element_name,
+                                 attribute_names, attribute_values,
+                                 error);
+    }
+  else
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Element <%s> is not allowed in this context",
+                      element_name);
+      return FALSE;
+    }  
 }
 
 dbus_bool_t
@@ -191,36 +595,247 @@ bus_config_parser_end_element (BusConfigParser   *parser,
                                const char        *element_name,
                                DBusError         *error)
 {
+  ElementType t;
+  const char *n;
+  Element *e;
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
+  /* printf ("END: %s\n", element_name); */
+  
+  t = top_element_type (parser);
+
+  if (t == ELEMENT_NONE)
+    {
+      /* should probably be an assertion failure but
+       * being paranoid about XML parsers
+       */
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "XML parser ended element with no element on the stack");
+      return FALSE;
+    }
+
+  n = element_type_to_name (t);
+  _dbus_assert (n != NULL);
+  if (strcmp (n, element_name) != 0)
+    {
+      /* should probably be an assertion failure but
+       * being paranoid about XML parsers
+       */
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "XML element ended which was not the topmost element on the stack");
+      return FALSE;
+    }
+
+  e = peek_element (parser);
+  _dbus_assert (e != NULL);
+
+  switch (e->type)
+    {
+    case ELEMENT_NONE:
+      _dbus_assert_not_reached ("element in stack has no type");
+      break;
+
+    case ELEMENT_INCLUDE:
+    case ELEMENT_USER:
+    case ELEMENT_LISTEN:
+    case ELEMENT_AUTH:
+      if (!e->had_content)
+        {
+          dbus_set_error (error, DBUS_ERROR_FAILED,
+                          "XML element <%s> was expected to have content inside it",
+                          element_type_to_name (e->type));
+          return FALSE;
+        }
+      break;
+
+    case ELEMENT_BUSCONFIG:
+    case ELEMENT_POLICY:
+    case ELEMENT_LIMIT:
+    case ELEMENT_ALLOW:
+    case ELEMENT_DENY:
+      break;
+    }
+
+  pop_element (parser);
+
   return TRUE;
 }
 
+static dbus_bool_t
+all_whitespace (const DBusString *str)
+{
+  int i;
+
+  _dbus_string_skip_white (str, 0, &i);
+
+  return i == _dbus_string_get_length (str);
+}
+
 dbus_bool_t
 bus_config_parser_content (BusConfigParser   *parser,
                            const DBusString  *content,
                            DBusError         *error)
 {
+  Element *e;
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
+#if 0
+  {
+    const char *c_str;
+    
+    _dbus_string_get_const_data (content, &c_str);
+
+    printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
+  }
+#endif
+  
+  e = peek_element (parser);
+  if (e == NULL)
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Text content outside of any XML element in configuration file");
+      return FALSE;
+    }
+  else if (e->had_content)
+    {
+      _dbus_assert_not_reached ("Element had multiple content blocks");
+      return FALSE;
+    }
+
+  switch (top_element_type (parser))
+    {
+    case ELEMENT_NONE:
+      _dbus_assert_not_reached ("element at top of stack has no type");
+      return FALSE;
+
+    case ELEMENT_BUSCONFIG:
+    case ELEMENT_POLICY:
+    case ELEMENT_LIMIT:
+    case ELEMENT_ALLOW:
+    case ELEMENT_DENY:
+      if (all_whitespace (content))
+        return TRUE;
+      else
+        {
+          dbus_set_error (error, DBUS_ERROR_FAILED,
+                          "No text content expected inside XML element %s in configuration file",
+                          element_type_to_name (top_element_type (parser)));
+          return FALSE;
+        }
+
+    case ELEMENT_INCLUDE:
+      {
+        /* FIXME good test case for this would load each config file in the
+         * test suite both alone, and as an include, and check
+         * that the result is the same
+         */
+        BusConfigParser *included;
+        DBusError tmp_error;
+
+        e->had_content = TRUE;
+        
+        dbus_error_init (&tmp_error);
+        included = bus_config_load (content, &tmp_error);
+        if (included == NULL)
+          {
+            _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
+            if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
+                e->d.include.ignore_missing)
+              {
+                dbus_error_free (&tmp_error);
+                return TRUE;
+              }
+            else
+              {
+                dbus_move_error (&tmp_error, error);
+                return FALSE;
+              }
+          }
+        else
+          {
+            _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
+
+            if (!merge_included (parser, included, error))
+              return FALSE;
+
+            bus_config_parser_unref (included);
+            return TRUE;
+          }
+      }
+      break;
+
+    case ELEMENT_USER:
+      {
+        char *s;
+
+        e->had_content = TRUE;
+        
+        if (!_dbus_string_copy_data (content, &s))
+          goto nomem;
+          
+        dbus_free (parser->user);
+        parser->user = s;
+      }
+      break;
+
+    case ELEMENT_LISTEN:
+      {
+        char *s;
+
+        e->had_content = TRUE;
+        
+        if (!_dbus_string_copy_data (content, &s))
+          goto nomem;
+
+        if (!_dbus_list_append (&parser->listen_on,
+                                s))
+          {
+            dbus_free (s);
+            goto nomem;
+          }
+      }
+      break;
+
+    case ELEMENT_AUTH:
+      {
+        e->had_content = TRUE;
+        /* FIXME */
+      }
+      break;
+    }
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   return TRUE;
+
+ nomem:
+  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+  return FALSE;
 }
 
 dbus_bool_t
 bus_config_parser_finished (BusConfigParser   *parser,
                             DBusError         *error)
 {
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);  
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  if (parser->stack != NULL)
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Element <%s> was not closed in configuration file",
+                      element_type_to_name (top_element_type (parser)));
 
+      return FALSE;
+    }
+  
   return TRUE;
 }
 
 const char*
 bus_config_parser_get_user (BusConfigParser *parser)
 {
-
-
-  return NULL;
+  return parser->user;
 }
 
 #ifdef DBUS_BUILD_TESTS
@@ -242,12 +857,12 @@ do_load (const DBusString *full_path,
   DBusError error;
 
   dbus_error_init (&error);
-  
+
   parser = bus_config_load (full_path, &error);
   if (parser == NULL)
     {
       _DBUS_ASSERT_ERROR_IS_SET (&error);
-      
+
       if (oom_possible &&
           dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
         {
@@ -256,7 +871,7 @@ do_load (const DBusString *full_path,
           return TRUE;
         }
       else if (validity == VALID)
-        {          
+        {
           _dbus_warn ("Failed to load valid file but still had memory: %s\n",
                       error.message);
 
@@ -272,9 +887,9 @@ do_load (const DBusString *full_path,
   else
     {
       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
-      
+
       bus_config_parser_unref (parser);
-      
+
       if (validity == INVALID)
         {
           _dbus_warn ("Accepted invalid file\n");
@@ -312,17 +927,17 @@ process_test_subdir (const DBusString *test_base_dir,
 
   retval = FALSE;
   dir = NULL;
-  
+
   if (!_dbus_string_init (&test_directory, _DBUS_INT_MAX))
     _dbus_assert_not_reached ("didn't allocate test_directory\n");
 
   _dbus_string_init_const (&filename, subdir);
-  
+
   if (!_dbus_string_copy (test_base_dir, 0,
                           &test_directory, 0))
     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
-  
-  if (!_dbus_concat_dir_and_file (&test_directory, &filename))    
+
+  if (!_dbus_concat_dir_and_file (&test_directory, &filename))
     _dbus_assert_not_reached ("couldn't allocate full path");
 
   _dbus_string_free (&filename);
@@ -342,13 +957,13 @@ process_test_subdir (const DBusString *test_base_dir,
     }
 
   printf ("Testing:\n");
-  
+
  next:
   while (_dbus_directory_get_next_file (dir, &filename, &error))
     {
       DBusString full_path;
       LoaderOomData d;
-      
+
       if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
         _dbus_assert_not_reached ("couldn't init string");
 
@@ -373,7 +988,7 @@ process_test_subdir (const DBusString *test_base_dir,
         _dbus_string_get_const_data (&filename, &s);
         printf ("    %s\n", s);
       }
-      
+
       _dbus_verbose (" expecting %s\n",
                      validity == VALID ? "valid" :
                      (validity == INVALID ? "invalid" :
@@ -383,7 +998,7 @@ process_test_subdir (const DBusString *test_base_dir,
       d.validity = validity;
       if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d))
         _dbus_assert_not_reached ("test failed");
-      
+
       _dbus_string_free (&full_path);
     }
 
@@ -396,9 +1011,9 @@ process_test_subdir (const DBusString *test_base_dir,
       dbus_error_free (&error);
       goto failed;
     }
-    
+
   retval = TRUE;
-  
+
  failed:
 
   if (dir)
@@ -418,10 +1033,10 @@ bus_config_parser_test (const DBusString *test_data_dir)
       printf ("No test data\n");
       return TRUE;
     }
-  
+
   if (!process_test_subdir (test_data_dir, "valid-config-files", VALID))
     return FALSE;
-  
+
   return TRUE;
 }
 
index 3768de5..862ba60 100644 (file)
@@ -69,8 +69,8 @@ main (int argc, char **argv)
   printf ("%s: Running config file parser test\n", argv[0]);
   if (!bus_config_parser_test (&test_data_dir))
     die ("parser");
-
-  check_memleaks (argv[0]);
+  
+  check_memleaks (argv[0]);  
   
   printf ("%s: Running policy test\n", argv[0]);
   if (!bus_policy_test (&test_data_dir))
index 1c018b7..6002f7a 100644 (file)
@@ -345,7 +345,7 @@ _dbus_test_oom_handling (const char             *description,
 
   if (!(* func) (data))
     return FALSE;
-
+  
   approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
 
   _dbus_verbose ("=================\n%s: about %d mallocs total\n=================\n",
index 9bfd0b3..dcf01e4 100644 (file)
@@ -212,7 +212,8 @@ _DBUS_DECLARE_GLOBAL_LOCK (atomic);
 _DBUS_DECLARE_GLOBAL_LOCK (message_handler);
 _DBUS_DECLARE_GLOBAL_LOCK (user_info);
 _DBUS_DECLARE_GLOBAL_LOCK (bus);
-#define _DBUS_N_GLOBAL_LOCKS (7)
+_DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs);
+#define _DBUS_N_GLOBAL_LOCKS (8)
 
 DBUS_END_DECLS;
 
index b2efff6..c620597 100644 (file)
@@ -57,8 +57,8 @@ alloc_link (void *data)
 
   if (!_DBUS_LOCK (list))
     return NULL;
-  
-  if (!list_pool)
+
+  if (list_pool == NULL)
     {      
       list_pool = _dbus_mem_pool_new (sizeof (DBusList), TRUE);
 
@@ -67,9 +67,21 @@ alloc_link (void *data)
           _DBUS_UNLOCK (list);
           return NULL;
         }
+
+      link = _dbus_mem_pool_alloc (list_pool);
+      if (link == NULL)
+        {
+          _dbus_mem_pool_free (list_pool);
+          list_pool = NULL;
+          _DBUS_UNLOCK (list);
+          return NULL;
+        }
     }
-  
-  link = _dbus_mem_pool_alloc (list_pool);
+  else
+    {
+      link = _dbus_mem_pool_alloc (list_pool);
+    }
+
   if (link)
     link->data = data;
   
@@ -80,13 +92,14 @@ alloc_link (void *data)
 
 static void
 free_link (DBusList *link)
-{
+{  
   _DBUS_LOCK (list);
   if (_dbus_mem_pool_dealloc (list_pool, link))
     {
       _dbus_mem_pool_free (list_pool);
       list_pool = NULL;
     }
+  
   _DBUS_UNLOCK (list);
 }
 
@@ -608,6 +621,27 @@ _dbus_list_pop_last (DBusList **list)
 }
 
 /**
+ * Removes the last link in the list and returns it.  This is a
+ * constant-time operation.
+ *
+ * @param list address of the list head.
+ * @returns the last link in the list, or #NULL for an empty list.
+ */
+DBusList*
+_dbus_list_pop_last_link (DBusList **list)
+{
+  DBusList *link;
+  
+  link = _dbus_list_get_last_link (list);
+  if (link == NULL)
+    return NULL;
+
+  _dbus_list_unlink (list, link);
+
+  return link;
+}
+
+/**
  * Copies a list. This is a linear-time operation.  If there isn't
  * enough memory to copy the entire list, the destination list will be
  * set to #NULL.
@@ -952,6 +986,58 @@ _dbus_list_test (void)
   _dbus_assert (list1 == NULL);
   _dbus_assert (list2 == NULL);
 
+  /* Test get_first_link, get_last_link, pop_first_link, pop_last_link */
+  
+  i = 0;
+  while (i < 10)
+    {
+      _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
+      _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
+      ++i;
+    }
+
+  --i;
+  while (i >= 0)
+    {
+      DBusList *got_link1;
+      DBusList *got_link2;
+
+      DBusList *link1;
+      DBusList *link2;
+      
+      void *data1;
+      void *data2;
+      
+      got_link1 = _dbus_list_get_last_link (&list1);
+      got_link2 = _dbus_list_get_first_link (&list2);
+      
+      link1 = _dbus_list_pop_last_link (&list1);
+      link2 = _dbus_list_pop_first_link (&list2);
+
+      _dbus_assert (got_link1 == link1);
+      _dbus_assert (got_link2 == link2);
+
+      data1 = link1->data;
+      data2 = link2->data;
+
+      _dbus_list_free_link (link1);
+      _dbus_list_free_link (link2);
+      
+      _dbus_assert (_DBUS_POINTER_TO_INT (data1) == i);
+      _dbus_assert (_DBUS_POINTER_TO_INT (data2) == i);
+
+      verify_list (&list1);
+      verify_list (&list2);
+
+      _dbus_assert (is_ascending_sequence (&list1));
+      _dbus_assert (is_descending_sequence (&list2));
+      
+      --i;
+    }
+
+  _dbus_assert (list1 == NULL);
+  _dbus_assert (list2 == NULL);
+  
   /* Test iteration */
   
   i = 0;
index df06856..5f42ca3 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* dbus-list.h Generic linked list utility (internal to D-BUS implementation)
  * 
- * Copyright (C) 2002  Red Hat, Inc.
+ * Copyright (C) 2002, 2003 Red Hat, Inc.
  *
  * Licensed under the Academic Free License version 1.2
  * 
@@ -63,6 +63,7 @@ void*       _dbus_list_get_first      (DBusList **list);
 void*       _dbus_list_pop_first      (DBusList **list);
 void*       _dbus_list_pop_last       (DBusList **list);
 DBusList*   _dbus_list_pop_first_link (DBusList **list);
+DBusList*   _dbus_list_pop_last_link  (DBusList **list);
 dbus_bool_t _dbus_list_copy           (DBusList **list,
                                        DBusList **dest);
 int         _dbus_list_get_length     (DBusList **list);
index fbda713..8efbec5 100644 (file)
@@ -633,13 +633,17 @@ dbus_free_string_array (char **str_array)
  */
 int _dbus_current_generation = 1;
 
-static DBusList *registered_globals = NULL;
+typedef struct ShutdownClosure ShutdownClosure;
 
-typedef struct
+struct ShutdownClosure
 {
+  ShutdownClosure *next;
   DBusShutdownFunction func;
   void *data;
-} ShutdownClosure;
+};
+
+_DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs);
+static ShutdownClosure *registered_globals = NULL;
 
 /**
  * The D-BUS library keeps some internal global variables, for example
@@ -656,22 +660,18 @@ typedef struct
 void
 dbus_shutdown (void)
 {
-  DBusList *link;
-
-  link = _dbus_list_get_first_link (&registered_globals);
-  while (link != NULL)
+  while (registered_globals != NULL)
     {
-      ShutdownClosure *c = link->data;
+      ShutdownClosure *c;
 
+      c = registered_globals;
+      registered_globals = c->next;
+      
       (* c->func) (c->data);
-
-      dbus_free (c);
       
-      link = _dbus_list_get_next_link (&registered_globals, link);
+      dbus_free (c);
     }
 
-  _dbus_list_clear (&registered_globals);
-
   _dbus_current_generation += 1;
 }
 
@@ -693,20 +693,17 @@ _dbus_register_shutdown_func (DBusShutdownFunction  func,
 
   if (c == NULL)
     return FALSE;
-  
+
   c->func = func;
   c->data = data;
 
-  /* We prepend, then shutdown the list in order, so
-   * we shutdown last-registered stuff first which
-   * is right.
-   */
-  if (!_dbus_list_prepend (&registered_globals, c))
-    {
-      dbus_free (c);
-      return FALSE;
-    }
+  _DBUS_LOCK (shutdown_funcs);
+  
+  c->next = registered_globals;
+  registered_globals = c;
 
+  _DBUS_UNLOCK (shutdown_funcs);
+  
   return TRUE;
 }
 
index 13ba550..5074c7d 100644 (file)
@@ -84,7 +84,8 @@ struct DBusMemBlock
                         *   when we free the mem pool.
                         */
 
-  int used_so_far;     /**< bytes of this block already allocated as elements. */
+  /* this is a long so that "elements" is aligned */
+  long used_so_far;     /**< bytes of this block already allocated as elements. */
   
   unsigned char elements[ELEMENT_PADDING]; /**< the block data, actually allocated to required size */
 };
@@ -254,7 +255,7 @@ _dbus_mem_pool_alloc (DBusMemPool *pool)
             memset (element, '\0', pool->element_size);
 
           pool->allocated_elements += 1;
-      
+          
           return element;
         }
       else
@@ -311,11 +312,11 @@ _dbus_mem_pool_alloc (DBusMemPool *pool)
             }
       
           element = &pool->blocks->elements[pool->blocks->used_so_far];
-
+          
           pool->blocks->used_so_far += pool->element_size;
 
           pool->allocated_elements += 1;
-      
+          
           return element;
         }
     }
index 7549dca..0d98b37 100644 (file)
@@ -633,7 +633,74 @@ _dbus_string_steal_data_len (DBusString        *str,
       return FALSE;
     }
 
-  _dbus_warn ("Broken code in _dbus_string_steal_data_len(), FIXME\n");
+  _dbus_warn ("Broken code in _dbus_string_steal_data_len(), see @todo, FIXME\n");
+  if (!_dbus_string_steal_data (&dest, data_return))
+    {
+      _dbus_string_free (&dest);
+      return FALSE;
+    }
+
+  _dbus_string_free (&dest);
+  return TRUE;
+}
+
+
+/**
+ * Copies the data from the string into a char*
+ *
+ * @param str the string
+ * @param data_return place to return the data
+ * @returns #TRUE on success, #FALSE on no memory
+ */
+dbus_bool_t
+_dbus_string_copy_data (const DBusString  *str,
+                        char             **data_return)
+{
+  DBUS_CONST_STRING_PREAMBLE (str);
+  _dbus_assert (data_return != NULL);
+  
+  *data_return = dbus_malloc (real->len + 1);
+  if (*data_return == NULL)
+    return FALSE;
+
+  memcpy (*data_return, real->str, real->len + 1);
+
+  return TRUE;
+}
+
+/**
+ * Copies a segment of the string into a char*
+ *
+ * @param str the string
+ * @param data_return place to return the data
+ * @param start start index
+ * @param len length to copy
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_string_copy_data_len (const DBusString  *str,
+                            char             **data_return,
+                            int                start,
+                            int                len)
+{
+  DBusString dest;
+
+  DBUS_CONST_STRING_PREAMBLE (str);
+  _dbus_assert (data_return != NULL);
+  _dbus_assert (start >= 0);
+  _dbus_assert (len >= 0);
+  _dbus_assert (start <= real->len);
+  _dbus_assert (len <= real->len - start);
+
+  if (!_dbus_string_init (&dest, real->max_length))
+    return FALSE;
+
+  if (!_dbus_string_copy_len (str, start, len, &dest, 0))
+    {
+      _dbus_string_free (&dest);
+      return FALSE;
+    }
+
   if (!_dbus_string_steal_data (&dest, data_return))
     {
       _dbus_string_free (&dest);
@@ -1235,8 +1302,9 @@ _dbus_string_replace_len (const DBusString *source,
  */
 #define UNICODE_VALID(Char)                   \
     ((Char) < 0x110000 &&                     \
-     ((Char) < 0xD800 || (Char) >= 0xE000) && \
-     (Char) != 0xFFFE && (Char) != 0xFFFF)   
+     (((Char) & 0xFFFFF800) != 0xD800) &&     \
+     ((Char) < 0xFDD0 || (Char) > 0xFDEF) &&  \
+     ((Char) & 0xFFFF) != 0xFFFF)
 
 /**
  * Gets a unicode character from a UTF-8 string. Does no validation;
@@ -1426,6 +1494,7 @@ _dbus_string_find_blank (const DBusString *str,
 
 /**
  * Skips blanks from start, storing the first non-blank in *end
+ * (blank is space or tab).
  *
  * @param str the string
  * @param start where to start
@@ -1459,6 +1528,43 @@ _dbus_string_skip_blank (const DBusString *str,
 }
 
 /**
+ * Skips whitespace from start, storing the first non-whitespace in *end.
+ * (whitespace is space, tab, newline, CR).
+ *
+ * @param str the string
+ * @param start where to start
+ * @param end where to store the first non-whitespace byte index
+ */
+void
+_dbus_string_skip_white (const DBusString *str,
+                         int               start,
+                         int              *end)
+{
+  int i;
+  DBUS_CONST_STRING_PREAMBLE (str);
+  _dbus_assert (start <= real->len);
+  _dbus_assert (start >= 0);
+  
+  i = start;
+  while (i < real->len)
+    {
+      if (!(real->str[i] == ' ' ||
+            real->str[i] == '\n' ||
+            real->str[i] == '\r' ||
+            real->str[i] == '\t'))
+        break;
+      
+      ++i;
+    }
+
+  _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
+                                    real->str[i] == '\t'));
+  
+  if (end)
+    *end = i;
+}
+
+/**
  * Assigns a newline-terminated or \r\n-terminated line from the front
  * of the string to the given dest string. The dest string's previous
  * contents are deleted. If the source string contains no newline,
index 1f7d491..3a517e9 100644 (file)
@@ -81,6 +81,12 @@ dbus_bool_t _dbus_string_steal_data_len     (DBusString        *str,
                                              char             **data_return,
                                              int                start,
                                              int                len);
+dbus_bool_t _dbus_string_copy_data          (const DBusString  *str,
+                                             char             **data_return);
+dbus_bool_t _dbus_string_copy_data_len      (const DBusString  *str,
+                                             char             **data_return,
+                                             int                start,
+                                             int                len);
 
 int  _dbus_string_get_length         (const DBusString  *str);
 
@@ -175,6 +181,10 @@ void        _dbus_string_skip_blank   (const DBusString *str,
                                        int               start,
                                        int              *end);
 
+void        _dbus_string_skip_white   (const DBusString *str,
+                                       int               start,
+                                       int              *end);
+
 dbus_bool_t _dbus_string_equal        (const DBusString *a,
                                        const DBusString *b);
 
index d481479..15ce33c 100644 (file)
@@ -245,7 +245,8 @@ init_global_locks (void)
     LOCK_ADDR (atomic),
     LOCK_ADDR (message_handler),
     LOCK_ADDR (user_info),
-    LOCK_ADDR (bus)
+    LOCK_ADDR (bus),
+    LOCK_ADDR (shutdown_funcs)
 #undef LOCK_ADDR
   };
 
index c35d05c..df1e43d 100644 (file)
@@ -32,6 +32,18 @@ Elements:
    
     Include a file <include>filename.conf</include> at this point.
 
+ <includedir>
+
+    Include all files in <includedir>foo.d</includedir> at this
+    point. Files in the directory are included in undefined order.
+    Only files ending in ".conf" are included.
+
+    This is intended to allow extension of the system bus by
+    particular packages. For example, if CUPS wants to be able to send
+    out notification of printer queue changes, it could install a file
+    to /etc/dbus/system.d that allowed all apps to receive this
+    message and allowed the printer daemon user to send it.
+
  <user>
 
     The user account the daemon should run as, as either a username or
@@ -42,13 +54,12 @@ Elements:
     The last <user> entry in the file "wins", the others are ignored.
 
  <listen>
-  address="name"    mandatory attribute
 
     Add an address that the bus should listen on. The 
     address is in the standard D-BUS format that contains 
     a transport name plus possible parameters/options.
 
-    Example: <listen address="unix:path=/tmp/foo"/>
+    Example: <listen>unix:path=/tmp/foo</listen>
 
     If there are multiple <listen> elements, then the bus listens 
     on multiple addresses.
index 4b09ef7..222122c 100644 (file)
@@ -1,6 +1,10 @@
 <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 <busconfig>
+  <user>mybususer</user>
+  <listen>unix:path=/foo/bar</listen>
+  <listen>tcp:port=1234</listen>
+  <include ignore_missing="yes">nonexistent.conf</include>
   <policy context="default">
     <allow user="*"/>
   </policy>