Commit 29560adc authored by Havoc Pennington's avatar Havoc Pennington

2003-03-12 Havoc Pennington <hp@redhat.com>

        Mega-patch that gets the message bus daemon initially handling
	out-of-memory. Work still needed. Also lots of random
	moving stuff to DBusError instead of ResultCode.

	* dbus/dbus-list.c (_dbus_list_length_is_one): new function

	* dbus/dbus-connection.c
	(dbus_connection_send_with_reply_and_block): use DBusError

	* dbus/dbus-bus.c: adapt to API changes, make it use DBusError not
	DBusResultCode

	* dbus/dbus-connection.c (dbus_connection_send): drop the result
	code here, as the only failure possible is OOM.

	* bus/connection.c (bus_connection_disconnect):
	rename bus_connection_disconnected as it's a notification only

	* bus/driver.c (bus_driver_handle_acquire_service): don't free
	"name" on get_args failure, should be done by get_args;
	don't disconnect client for bad args, just return an error.
	(bus_driver_handle_service_exists): ditto

	* bus/services.c (bus_services_list): NULL-terminate returned array

	* bus/driver.c (bus_driver_send_service_lost)
	(bus_driver_send_service_acquired): send messages from driver to a
	specific client to the client's unique name, not to the broadcast
	service.

	* dbus/dbus-message.c (decode_header_data): reject messages that
	contain no name field
	(_dbus_message_get_client_serial): rename to
	dbus_message_get_serial and make public
	(_dbus_message_set_serial): rename from set_client_serial
	(_dbus_message_set_reply_serial): make public
	(_dbus_message_get_reply_serial): make public

	* bus/connection.c (bus_connection_foreach): allow stopping
	iteration by returning FALSE from foreach function.

	* dbus/dbus-connection.c (dbus_connection_send_preallocated)
	(dbus_connection_free_preallocated_send)
	(dbus_connection_preallocate_send): new API for sending a message
	without possibility of malloc failure.
	(dbus_connection_send_message): rename to just
	dbus_connection_send (and same for whole function family)

	* dbus/dbus-errors.c (dbus_error_free): make this reinit the error

	* dbus/dbus-sysdeps.c (_dbus_exit): new function

	* bus/activation.c: handle/return errors

	* dbus/dbus-errors.h: add more DBUS_ERROR #define

	* dbus/dbus-sysdeps.c (_dbus_directory_open) (_dbus_file_get_contents)
	(_dbus_directory_get_next_file): use DBusError instead of DBusResultCode
	(_dbus_result_from_errno): move to this file
parent 799a3ff4
2003-03-12 Havoc Pennington <hp@redhat.com>
Mega-patch that gets the message bus daemon initially handling
out-of-memory. Work still needed. Also lots of random
moving stuff to DBusError instead of ResultCode.
* dbus/dbus-list.c (_dbus_list_length_is_one): new function
* dbus/dbus-connection.c
(dbus_connection_send_with_reply_and_block): use DBusError
* dbus/dbus-bus.c: adapt to API changes, make it use DBusError not
DBusResultCode
* dbus/dbus-connection.c (dbus_connection_send): drop the result
code here, as the only failure possible is OOM.
* bus/connection.c (bus_connection_disconnect):
rename bus_connection_disconnected as it's a notification only
* bus/driver.c (bus_driver_handle_acquire_service): don't free
"name" on get_args failure, should be done by get_args;
don't disconnect client for bad args, just return an error.
(bus_driver_handle_service_exists): ditto
* bus/services.c (bus_services_list): NULL-terminate returned array
* bus/driver.c (bus_driver_send_service_lost)
(bus_driver_send_service_acquired): send messages from driver to a
specific client to the client's unique name, not to the broadcast
service.
* dbus/dbus-message.c (decode_header_data): reject messages that
contain no name field
(_dbus_message_get_client_serial): rename to
dbus_message_get_serial and make public
(_dbus_message_set_serial): rename from set_client_serial
(_dbus_message_set_reply_serial): make public
(_dbus_message_get_reply_serial): make public
* bus/connection.c (bus_connection_foreach): allow stopping
iteration by returning FALSE from foreach function.
* dbus/dbus-connection.c (dbus_connection_send_preallocated)
(dbus_connection_free_preallocated_send)
(dbus_connection_preallocate_send): new API for sending a message
without possibility of malloc failure.
(dbus_connection_send_message): rename to just
dbus_connection_send (and same for whole function family)
* dbus/dbus-errors.c (dbus_error_free): make this reinit the error
* dbus/dbus-sysdeps.c (_dbus_exit): new function
* bus/activation.c: handle/return errors
* dbus/dbus-errors.h: add more DBUS_ERROR #define
* dbus/dbus-sysdeps.c (_dbus_directory_open) (_dbus_file_get_contents)
(_dbus_directory_get_next_file): use DBusError instead of DBusResultCode
(_dbus_result_from_errno): move to this file
2003-03-10 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-marshal.c:
......
......@@ -59,18 +59,24 @@ bus_activation_entry_free (BusActivationEntry *entry)
}
static dbus_bool_t
add_desktop_file_entry (BusDesktopFile *desktop_file)
add_desktop_file_entry (BusDesktopFile *desktop_file,
DBusError *error)
{
char *name, *exec;
BusActivationEntry *entry;
name = NULL;
exec = NULL;
entry = NULL;
if (!bus_desktop_file_get_string (desktop_file,
DBUS_SERVICE_SECTION,
DBUS_SERVICE_NAME,
&name))
{
_dbus_verbose ("No \""DBUS_SERVICE_NAME"\" key in .service file\n");
return FALSE;
dbus_set_error (error, DBUS_ERROR_FAILED,
"No \""DBUS_SERVICE_NAME"\" key in .service file\n");
goto failed;
}
if (!bus_desktop_file_get_string (desktop_file,
......@@ -78,57 +84,104 @@ add_desktop_file_entry (BusDesktopFile *desktop_file)
DBUS_SERVICE_EXEC,
&exec))
{
_dbus_verbose ("No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
dbus_free (name);
return FALSE;
dbus_set_error (error, DBUS_ERROR_FAILED,
"No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
goto failed;
}
/* FIXME we need a better-defined algorithm for which service file to
* pick than "whichever one is first in the directory listing"
*/
if (_dbus_hash_table_lookup_string (activation_entries, name))
{
_dbus_verbose ("Service %s already exists in activation entry list\n", name);
dbus_free (name);
dbus_free (exec);
return FALSE;
dbus_set_error (error, DBUS_ERROR_FAILED,
"Service %s already exists in activation entry list\n", name);
goto failed;
}
entry = dbus_new0 (BusActivationEntry, 1);
if (entry == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
BUS_HANDLE_OOM (entry = dbus_malloc0 (sizeof (BusActivationEntry)));
entry->name = name;
entry->exec = exec;
BUS_HANDLE_OOM (_dbus_hash_table_insert_string (activation_entries, entry->name, entry));
if (!_dbus_hash_table_insert_string (activation_entries, entry->name, entry))
{
BUS_SET_OOM (error);
goto failed;
}
_dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
return TRUE;
failed:
dbus_free (name);
dbus_free (exec);
dbus_free (entry);
return FALSE;
}
static void
load_directory (const char *directory)
/* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
* hash entries it already added.
*/
static dbus_bool_t
load_directory (const char *directory,
DBusError *error)
{
DBusDirIter *iter;
DBusString dir, filename;
DBusResultCode result;
DBusString full_path;
BusDesktopFile *desktop_file;
DBusError tmp_error;
_dbus_string_init_const (&dir, directory);
iter = NULL;
desktop_file = NULL;
iter = _dbus_directory_open (&dir, &result);
if (iter == NULL)
if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
{
_dbus_verbose ("Failed to open directory %s: &s\n", directory,
result);
return;
BUS_SET_OOM (error);
return FALSE;
}
BUS_HANDLE_OOM (_dbus_string_init (&filename, _DBUS_INT_MAX));
if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
{
BUS_SET_OOM (error);
_dbus_string_free (&filename);
return FALSE;
}
/* from this point it's safe to "goto failed" */
iter = _dbus_directory_open (&dir, error);
if (iter == NULL)
{
_dbus_verbose ("Failed to open directory %s: %s\n",
directory, error ? error->message : "unknown");
goto failed;
}
/* Now read the files */
while (_dbus_directory_get_next_file (iter, &filename, &result))
dbus_error_init (&tmp_error);
while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
{
DBusString full_path;
BusDesktopFile *desktop_file;
DBusError error;
_dbus_assert (!dbus_error_is_set (&tmp_error));
_dbus_string_set_length (&full_path, 0);
if (!_dbus_string_append (&full_path, directory) ||
!_dbus_concat_dir_and_file (&full_path, &filename))
{
BUS_SET_OOM (error);
goto failed;
}
if (!_dbus_string_ends_with_c_str (&filename, ".service"))
{
......@@ -136,71 +189,133 @@ load_directory (const char *directory)
_dbus_string_get_const_data (&filename, &filename_c);
_dbus_verbose ("Skipping non-.service file %s\n",
filename_c);
continue;
continue;
}
BUS_HANDLE_OOM (_dbus_string_init (&full_path, _DBUS_INT_MAX));
BUS_HANDLE_OOM (_dbus_string_append (&full_path, directory));
BUS_HANDLE_OOM (_dbus_concat_dir_and_file (&full_path, &filename));
desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
desktop_file = bus_desktop_file_load (&full_path, &error);
if (!desktop_file)
if (desktop_file == NULL)
{
const char *full_path_c;
_dbus_string_get_const_data (&full_path, &full_path_c);
_dbus_verbose ("Could not load %s: %s\n", full_path_c,
error.message);
dbus_error_free (&error);
_dbus_string_free (&full_path);
tmp_error.message);
if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
{
dbus_move_error (&tmp_error, error);
goto failed;
}
dbus_error_free (&tmp_error);
continue;
}
if (!add_desktop_file_entry (desktop_file))
if (!add_desktop_file_entry (desktop_file, &tmp_error))
{
const char *full_path_c;
bus_desktop_file_free (desktop_file);
desktop_file = NULL;
_dbus_string_get_const_data (&full_path, &full_path_c);
_dbus_verbose ("Could not add %s to activation entry list.\n", full_path_c);
_dbus_verbose ("Could not add %s to activation entry list: %s\n",
full_path_c, tmp_error.message);
if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
{
dbus_move_error (&tmp_error, error);
goto failed;
}
dbus_error_free (&tmp_error);
continue;
}
else
{
bus_desktop_file_free (desktop_file);
desktop_file = NULL;
continue;
}
}
bus_desktop_file_free (desktop_file);
_dbus_string_free (&full_path);
if (dbus_error_is_set (&tmp_error))
{
dbus_move_error (&tmp_error, error);
goto failed;
}
return TRUE;
failed:
_DBUS_ASSERT_ERROR_IS_SET (error);
if (iter != NULL)
_dbus_directory_close (iter);
if (desktop_file)
bus_desktop_file_free (desktop_file);
_dbus_string_free (&filename);
_dbus_string_free (&full_path);
return FALSE;
}
void
bus_activation_init (const char *address,
const char **directories)
dbus_bool_t
bus_activation_init (const char *address,
const char **directories,
DBusError *error)
{
int i;
_dbus_assert (server_address == NULL);
_dbus_assert (activation_entries == NULL);
/* FIXME: We should split up the server addresses. */
BUS_HANDLE_OOM (server_address = _dbus_strdup (address));
server_address = _dbus_strdup (address);
if (server_address == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
BUS_HANDLE_OOM (activation_entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
(DBusFreeFunction)bus_activation_entry_free));
i = 0;
activation_entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
(DBusFreeFunction)bus_activation_entry_free);
if (activation_entries == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
/* Load service files */
i = 0;
while (directories[i] != NULL)
{
load_directory (directories[i]);
i++;
if (!load_directory (directories[i], error))
goto failed;
++i;
}
return TRUE;
failed:
dbus_free (server_address);
if (activation_entries)
_dbus_hash_table_unref (activation_entries);
return FALSE;
}
static void
child_setup (void *data)
{
/* FIXME: Check return value in case of OOM */
_dbus_setenv ("DBUS_ADDRESS", server_address);
/* If no memory, we simply have the child exit, so it won't try
* to connect to the wrong thing.
*/
if (!_dbus_setenv ("DBUS_ADDRESS", server_address))
_dbus_exit (1);
}
dbus_bool_t
......@@ -220,6 +335,10 @@ bus_activation_activate_service (const char *service_name,
return FALSE;
}
/* FIXME we need to support a full command line, not just a single
* argv[0]
*/
/* Now try to spawn the process */
argv[0] = entry->exec;
argv[1] = NULL;
......
......@@ -26,8 +26,9 @@
#include <dbus/dbus.h>
void bus_activation_init (const char *address,
const char **paths);
dbus_bool_t bus_activation_init (const char *address,
const char **paths,
DBusError *error);
dbus_bool_t bus_activation_activate_service (const char *service_name,
DBusError *error);
......
This diff is collapsed.
......@@ -27,13 +27,19 @@
#include <dbus/dbus.h>
#include "services.h"
typedef void (* BusConnectionForeachFunction) (DBusConnection *connection,
void *data);
typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection,
void *data);
dbus_bool_t bus_connection_init (void);
dbus_bool_t bus_connection_setup (DBusConnection *connection);
dbus_bool_t bus_connection_is_active (DBusConnection *connection);
dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection);
void bus_connection_send_oom_error (DBusConnection *connection,
DBusMessage *in_reply_to);
/* called by services.c */
dbus_bool_t bus_connection_add_owned_service (DBusConnection *connection,
BusService *service);
......@@ -47,8 +53,20 @@ const char *bus_connection_get_name (DBusConnection *connection);
void bus_connection_foreach (BusConnectionForeachFunction function,
void *data);
/* called by dispatch.c */
void bus_connection_disconnect (DBusConnection *connection);
/* called by dispatch.c when the connection is dropped */
void bus_connection_disconnected (DBusConnection *connection);
/* transaction API so we can send or not send a block of messages as a whole */
BusTransaction* bus_transaction_new (void);
dbus_bool_t bus_transaction_send_message (BusTransaction *transaction,
DBusConnection *connection,
DBusMessage *message);
dbus_bool_t bus_transaction_send_error_reply (BusTransaction *transaction,
DBusConnection *connection,
const DBusError *error,
DBusMessage *in_reply_to);
void bus_transaction_cancel_and_free (BusTransaction *transaction);
void bus_transaction_execute_and_free (BusTransaction *transaction);
#endif /* BUS_CONNECTION_H */
......@@ -125,7 +125,7 @@ bus_desktop_file_free (BusDesktopFile *desktop_file)
dbus_free (desktop_file);
}
static void
static dbus_bool_t
grow_lines_in_section (BusDesktopFileSection *section)
{
BusDesktopFileLine *lines;
......@@ -137,14 +137,19 @@ grow_lines_in_section (BusDesktopFileSection *section)
else
new_n_lines = section->n_allocated_lines*2;
BUS_HANDLE_OOM (lines = dbus_realloc (section->lines,
sizeof (BusDesktopFileLine) * new_n_lines));
section->lines = lines;
lines = dbus_realloc (section->lines,
sizeof (BusDesktopFileLine) * new_n_lines);
if (lines == NULL)
return FALSE;
section->lines = lines;
section->n_allocated_lines = new_n_lines;
return TRUE;
}
static void
static dbus_bool_t
grow_sections (BusDesktopFile *desktop_file)
{
int new_n_sections;
......@@ -155,21 +160,36 @@ grow_sections (BusDesktopFile *desktop_file)
else
new_n_sections = desktop_file->n_allocated_sections*2;
BUS_HANDLE_OOM (sections = dbus_realloc (desktop_file->sections,
sizeof (BusDesktopFileSection) * new_n_sections));
sections = dbus_realloc (desktop_file->sections,
sizeof (BusDesktopFileSection) * new_n_sections);
if (sections == NULL)
return FALSE;
desktop_file->sections = sections;
desktop_file->n_allocated_sections = new_n_sections;
return TRUE;
}
static char *
unescape_string (const DBusString *str, int pos, int end_pos)
unescape_string (BusDesktopFileParser *parser,
const DBusString *str,
int pos,
int end_pos,
DBusError *error)
{
char *retval, *q;
/* len + 1 is enough, because unescaping never makes the
* string longer */
BUS_HANDLE_OOM (retval = dbus_malloc (end_pos - pos + 1));
* string longer
*/
retval = dbus_malloc (end_pos - pos + 1);
if (retval == NULL)
{
BUS_SET_OOM (error);
return NULL;
}
q = retval;
......@@ -179,6 +199,8 @@ unescape_string (const DBusString *str, int pos, int end_pos)
{
/* Found an embedded null */
dbus_free (retval);
report_error (parser, "Text to be unescaped contains embedded nul",
BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
return NULL;
}
......@@ -190,6 +212,8 @@ unescape_string (const DBusString *str, int pos, int end_pos)
{
/* Escape at end of string */
dbus_free (retval);
report_error (parser, "Text to be unescaped ended in \\",
BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
return NULL;
}
......@@ -213,7 +237,9 @@ unescape_string (const DBusString *str, int pos, int end_pos)
default:
/* Invalid escape code */
dbus_free (retval);
return NULL;
report_error (parser, "Text to be unescaped had invalid escape sequence",
BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
return NULL;
}
pos++;
}
......@@ -235,20 +261,34 @@ new_section (BusDesktopFile *desktop_file,
const char *name)
{
int n;
char *name_copy;
if (desktop_file->n_allocated_sections == desktop_file->n_sections)
grow_sections (desktop_file);
n = desktop_file->n_sections++;
{
if (!grow_sections (desktop_file))
return NULL;
}
BUS_HANDLE_OOM (desktop_file->sections[n].section_name = _dbus_strdup (name));
name_copy = _dbus_strdup (name);
if (name_copy == NULL)
return NULL;
n = desktop_file->n_sections + 1;
desktop_file->sections[n].section_name = name_copy;
desktop_file->sections[n].n_lines = 0;
desktop_file->sections[n].lines = NULL;
desktop_file->sections[n].n_allocated_lines = 0;
grow_lines_in_section (&desktop_file->sections[n]);
if (!grow_lines_in_section (&desktop_file->sections[n]))
{
dbus_free (desktop_file->sections[n].section_name);
desktop_file->sections[n].section_name = NULL;
return NULL;
}
desktop_file->n_sections = n;
return &desktop_file->sections[n];
}
......@@ -277,7 +317,10 @@ new_line (BusDesktopFileParser *parser)
section = &parser->desktop_file->sections[parser->current_section];
if (section->n_allocated_lines == section->n_lines)
grow_lines_in_section (section);
{
if (!grow_lines_in_section (section))
return NULL;
}
line = &section->lines[section->n_lines++];
......@@ -358,11 +401,12 @@ parse_section_start (BusDesktopFileParser *parser, DBusError *error)
return FALSE;
}
section_name = unescape_string (&parser->data, parser->pos + 1, line_end - 1);
section_name = unescape_string (parser,
&parser->data, parser->pos + 1, line_end - 1,
error);
if (section_name == NULL)
{
report_error (parser, "Invalid escaping in section name", BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
parser_free (parser);
return FALSE;
}
......@@ -450,20 +494,39 @@ parse_key_value (BusDesktopFileParser *parser, DBusError *error)
value_start = p;
value = unescape_string (&parser->data, value_start, line_end);
value = unescape_string (parser, &parser->data, value_start, line_end, error);
if (value == NULL)
{
report_error (parser, "Invalid escaping in value", BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error);
parser_free (parser);
return FALSE;
}
line = new_line (parser);
BUS_HANDLE_OOM (_dbus_string_init (&key, key_end - key_start));
BUS_HANDLE_OOM (_dbus_string_copy_len (&parser->data, key_start, key_end - key_start,
&key, 0));
BUS_HANDLE_OOM (_dbus_string_steal_data (&key, &tmp));
if (line == NULL)
{
parser_free (parser);
return FALSE;
}