From 29560adcc79a259a0be3511c056ee7453aa26c04 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Thu, 13 Mar 2003 00:56:43 +0000 Subject: 2003-03-12 Havoc Pennington 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 --- bus/activation.c | 231 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 175 insertions(+), 56 deletions(-) (limited to 'bus/activation.c') diff --git a/bus/activation.c b/bus/activation.c index b5cec44a..4e428bde 100644 --- a/bus/activation.c +++ b/bus/activation.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; -- cgit