summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog25
-rw-r--r--bus/config-loader-expat.c82
-rw-r--r--bus/config-parser.c705
-rw-r--r--bus/test-main.c4
-rw-r--r--dbus/dbus-internals.c2
-rw-r--r--dbus/dbus-internals.h3
-rw-r--r--dbus/dbus-list.c96
-rw-r--r--dbus/dbus-list.h3
-rw-r--r--dbus/dbus-memory.c43
-rw-r--r--dbus/dbus-mempool.c9
-rw-r--r--dbus/dbus-string.c112
-rw-r--r--dbus/dbus-string.h10
-rw-r--r--dbus/dbus-threads.c3
-rw-r--r--doc/config-file.txt15
-rw-r--r--test/data/valid-config-files/basic.conf4
15 files changed, 994 insertions, 122 deletions
diff --git a/ChangeLog b/ChangeLog
index 276235cd..01ce4267 100644
--- 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):
diff --git a/bus/config-loader-expat.c b/bus/config-loader-expat.c
index c7981bf4..a3740a48 100644
--- a/bus/config-loader-expat.c
+++ b/bus/config-loader-expat.c
@@ -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);
diff --git a/bus/config-parser.c b/bus/config-parser.c
index 2429cce5..972c05ac 100644
--- a/bus/config-parser.c
+++ b/bus/config-parser.c
@@ -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
@@ -28,38 +28,33 @@
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;
}
diff --git a/bus/test-main.c b/bus/test-main.c
index 3768de5f..862ba604 100644
--- a/bus/test-main.c
+++ b/bus/test-main.c
@@ -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))
diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c
index 1c018b7f..6002f7ab 100644
--- a/dbus/dbus-internals.c
+++ b/dbus/dbus-internals.c
@@ -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",
diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
index 9bfd0b3b..dcf01e48 100644
--- a/dbus/dbus-internals.h
+++ b/dbus/dbus-internals.h
@@ -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;
diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c
index b2efff6c..c6205971 100644
--- a/dbus/dbus-list.c
+++ b/dbus/dbus-list.c
@@ -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;
diff --git a/dbus/dbus-list.h b/dbus/dbus-list.h
index df068568..5f42ca3c 100644
--- a/dbus/dbus-list.h
+++ b/dbus/dbus-list.h
@@ -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);
diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c
index fbda7139..8efbec59 100644
--- a/dbus/dbus-memory.c
+++ b/dbus/dbus-memory.c
@@ -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;
}
diff --git a/dbus/dbus-mempool.c b/dbus/dbus-mempool.c
index 13ba5502..5074c7d2 100644
--- a/dbus/dbus-mempool.c
+++ b/dbus/dbus-mempool.c
@@ -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;
}
}
diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c
index 7549dcad..0d98b379 100644
--- a/dbus/dbus-string.c
+++ b/dbus/dbus-string.c
@@ -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,
diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h
index 1f7d4919..3a517e94 100644
--- a/dbus/dbus-string.h
+++ b/dbus/dbus-string.h
@@ -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);
diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
index d481479b..15ce33ca 100644
--- a/dbus/dbus-threads.c
+++ b/dbus/dbus-threads.c
@@ -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
};
diff --git a/doc/config-file.txt b/doc/config-file.txt
index c35d05c6..df1e43d8 100644
--- a/doc/config-file.txt
+++ b/doc/config-file.txt
@@ -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.
diff --git a/test/data/valid-config-files/basic.conf b/test/data/valid-config-files/basic.conf
index 4b09ef76..222122cf 100644
--- a/test/data/valid-config-files/basic.conf
+++ b/test/data/valid-config-files/basic.conf
@@ -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>