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>
This commit is contained in:
Havoc Pennington 2003-03-31 04:01:00 +00:00
parent d361874ef6
commit bc86794f23
15 changed files with 995 additions and 123 deletions

View file

@ -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):

View 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);

View 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
@ -28,36 +28,31 @@
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;
@ -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,23 +124,81 @@ 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;
return e;
}
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;
}

View 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))

View 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",

View 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;

View 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);
}
@ -607,6 +620,27 @@ _dbus_list_pop_last (DBusList **list)
return data;
}
/**
* 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
@ -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;

View 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);

View 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->func) (c->data);
dbus_free (c);
c = registered_globals;
registered_globals = c->next;
link = _dbus_list_get_next_link (&registered_globals, link);
(* c->func) (c->data);
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;
}

View 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;
}
}

View 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
@ -1458,6 +1527,43 @@ _dbus_string_skip_blank (const DBusString *str,
*end = i;
}
/**
* 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

View 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);

View 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
};

View 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.

View 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>