X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bus%2Factivation.c;h=3dc87016a994a03dbb19b72fcbd045eabb8cf553;hb=61d97215c317a4154df47fbfb882aab60b92fbab;hp=af0282557f757b950ad17ec018f54a4c77894e2c;hpb=d95cc488a83ad56f17e08e282a8ebcc33aa34c92;p=platform%2Fupstream%2Fdbus.git diff --git a/bus/activation.c b/bus/activation.c index af02825..3dc8701 100644 --- a/bus/activation.c +++ b/bus/activation.c @@ -4,6 +4,7 @@ * Copyright (C) 2003 CodeFactory AB * Copyright (C) 2003 Red Hat, Inc. * Copyright (C) 2004 Imendio HB + * Copyright (C) 2013 Samsung Electronics * * Licensed under the Academic Free License version 2.1 * @@ -80,7 +81,14 @@ typedef struct BusPendingActivationEntry BusPendingActivationEntry; struct BusPendingActivationEntry { + /* Normally a method call, but if connection is NULL, this is a signal + * instead. + */ DBusMessage *activation_message; + /* NULL if this activation entry is for the dbus-daemon itself, + * waiting for systemd to start. In this case, auto_activation is always + * TRUE. + */ DBusConnection *connection; dbus_bool_t auto_activation; @@ -143,16 +151,6 @@ bus_pending_activation_entry_free (BusPendingActivationEntry *entry) dbus_free (entry); } -static void -handle_timeout_callback (DBusTimeout *timeout, - void *data) -{ - BusPendingActivation *pending_activation = data; - - while (!dbus_timeout_handle (pending_activation->timeout)) - _dbus_wait_for_memory (); -} - static BusPendingActivation * bus_pending_activation_ref (BusPendingActivation *pending_activation) { @@ -179,8 +177,7 @@ bus_pending_activation_unref (BusPendingActivation *pending_activation) if (pending_activation->timeout_added) { _dbus_loop_remove_timeout (bus_context_get_loop (pending_activation->activation->context), - pending_activation->timeout, - handle_timeout_callback, pending_activation); + pending_activation->timeout); pending_activation->timeout_added = FALSE; } @@ -264,9 +261,11 @@ update_desktop_file_entry (BusActivation *activation, DBusStat stat_buf; DBusString file_path; DBusError tmp_error; + dbus_bool_t retval; _DBUS_ASSERT_ERROR_IS_CLEAR (error); + retval = FALSE; name = NULL; exec = NULL; user = NULL; @@ -286,14 +285,14 @@ update_desktop_file_entry (BusActivation *activation, !_dbus_concat_dir_and_file (&file_path, filename)) { BUS_SET_OOM (error); - goto failed; + goto out; } if (!_dbus_stat (&file_path, &stat_buf, NULL)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Can't stat the service file\n"); - goto failed; + goto out; } if (!bus_desktop_file_get_string (desktop_file, @@ -301,14 +300,14 @@ update_desktop_file_entry (BusActivation *activation, DBUS_SERVICE_NAME, &name, error)) - goto failed; + goto out; if (!bus_desktop_file_get_string (desktop_file, DBUS_SERVICE_SECTION, DBUS_SERVICE_EXEC, &exec_tmp, error)) - goto failed; + goto out; exec = _dbus_strdup (_dbus_replace_install_prefix (exec_tmp)); dbus_free (exec_tmp); @@ -325,7 +324,7 @@ update_desktop_file_entry (BusActivation *activation, if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) { dbus_move_error (&tmp_error, error); - goto failed; + goto out; } else { @@ -348,7 +347,7 @@ update_desktop_file_entry (BusActivation *activation, if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) { dbus_move_error (&tmp_error, error); - goto failed; + goto out; } else { @@ -373,14 +372,14 @@ update_desktop_file_entry (BusActivation *activation, { dbus_set_error (error, DBUS_ERROR_FAILED, "Service %s already exists in activation entry list\n", name); - goto failed; + goto out; } entry = dbus_new0 (BusActivationEntry, 1); if (entry == NULL) { BUS_SET_OOM (error); - goto failed; + goto out; } entry->name = name; @@ -389,18 +388,24 @@ update_desktop_file_entry (BusActivation *activation, entry->systemd_service = systemd_service; entry->refcount = 1; + /* ownership has been transferred to entry, do not free separately */ + name = NULL; + exec = NULL; + user = NULL; + systemd_service = NULL; + entry->s_dir = s_dir; entry->filename = _dbus_strdup (_dbus_string_get_const_data (filename)); if (!entry->filename) { BUS_SET_OOM (error); - goto failed; + goto out; } if (!_dbus_hash_table_insert_string (activation->entries, entry->name, bus_activation_entry_ref (entry))) { BUS_SET_OOM (error); - goto failed; + goto out; } if (!_dbus_hash_table_insert_string (s_dir->entries, entry->filename, bus_activation_entry_ref (entry))) @@ -408,7 +413,7 @@ update_desktop_file_entry (BusActivation *activation, /* Revert the insertion in the entries table */ _dbus_hash_table_remove_string (activation->entries, entry->name); BUS_SET_OOM (error); - goto failed; + goto out; } _dbus_verbose ("Added \"%s\" to list of services\n", entry->name); @@ -420,19 +425,31 @@ update_desktop_file_entry (BusActivation *activation, if (_dbus_hash_table_lookup_string (activation->entries, name)) { - _dbus_verbose ("The new service name \"%s\" of service file \"%s\" already in cache, ignoring\n", + _dbus_verbose ("The new service name \"%s\" of service file \"%s\" is already in cache, ignoring\n", name, _dbus_string_get_const_data (&file_path)); - goto failed; + dbus_set_error (error, DBUS_ERROR_FAILED, + "The new service name \"%s\" of service file \"%s\" is already in cache, ignoring\n", + name, _dbus_string_get_const_data (&file_path)); + goto out; } + /* ownership has been transferred to entry, do not free separately */ dbus_free (entry->name); + entry->name = name; + name = NULL; + dbus_free (entry->exec); + entry->exec = exec; + exec = NULL; + dbus_free (entry->user); + entry->user = user; + user = NULL; + dbus_free (entry->systemd_service); entry->systemd_service = systemd_service; - entry->name = name; - entry->exec = exec; - entry->user = user; + systemd_service = NULL; + if (!_dbus_hash_table_insert_string (activation->entries, entry->name, bus_activation_entry_ref(entry))) { @@ -441,20 +458,17 @@ update_desktop_file_entry (BusActivation *activation, * the entries hash table */ _dbus_hash_table_remove_string (entry->s_dir->entries, entry->filename); - bus_activation_entry_unref (entry); - return FALSE; + goto out; } } entry->mtime = stat_buf.mtime; + retval = TRUE; - _dbus_string_free (&file_path); - bus_activation_entry_unref (entry); - - return TRUE; - -failed: +out: + /* if these have been transferred into entry, the variables will be NULL */ dbus_free (name); + dbus_free (exec); dbus_free (user); dbus_free (systemd_service); _dbus_string_free (&file_path); @@ -462,7 +476,7 @@ failed: if (entry) bus_activation_entry_unref (entry); - return FALSE; + return retval; } static dbus_bool_t @@ -878,8 +892,6 @@ bus_activation_new (BusContext *context, DBusError *error) { BusActivation *activation; - DBusList *link; - char *dir; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -1092,13 +1104,18 @@ bus_activation_service_created (BusActivation *activation, if (!pending_activation) return TRUE; + bus_context_log (activation->context, + DBUS_SYSTEM_LOG_INFO, "Successfully activated service '%s'", + service_name); + link = _dbus_list_get_first_link (&pending_activation->entries); while (link != NULL) { BusPendingActivationEntry *entry = link->data; DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); - if (dbus_connection_get_is_connected (entry->connection)) + /* entry->connection is NULL for activating systemd */ + if (entry->connection && dbus_connection_get_is_connected (entry->connection)) { /* Only send activation replies to regular activation requests. */ if (!entry->auto_activation) @@ -1167,11 +1184,20 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation BusPendingActivationEntry *entry = link->data; DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); - if (entry->auto_activation && dbus_connection_get_is_connected (entry->connection)) + if (entry->auto_activation && (entry->connection == NULL || dbus_connection_get_is_connected (entry->connection))) { DBusConnection *addressed_recipient; - addressed_recipient = bus_service_get_primary_owners_connection (service); +#ifdef ENABLE_KDBUS_TRANSPORT + /* kdbus change - we can not send anything using phantom connections + * (DBusConnection structures for services other than daemon) + * so we have to use daemon connection + */ + if(bus_context_is_kdbus(bus_transaction_get_context (transaction))) + addressed_recipient = entry->connection; + else +#endif + addressed_recipient = bus_service_get_primary_owners_connection (service); /* Resume dispatching where we left off in bus_dispatch() */ if (!bus_dispatch_matches (transaction, @@ -1225,7 +1251,7 @@ try_send_activation_failure (BusPendingActivation *pending_activation, BusPendingActivationEntry *entry = link->data; DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); - if (dbus_connection_get_is_connected (entry->connection)) + if (entry->connection && dbus_connection_get_is_connected (entry->connection)) { if (!bus_transaction_send_error_reply (transaction, entry->connection, @@ -1316,22 +1342,16 @@ handle_servicehelper_exit_error (int exit_code, } } -static dbus_bool_t -babysitter_watch_callback (DBusWatch *watch, - unsigned int condition, - void *data) +static void +pending_activation_finished_cb (DBusBabysitter *babysitter, + void *data) { BusPendingActivation *pending_activation = data; - dbus_bool_t retval; - DBusBabysitter *babysitter; dbus_bool_t uses_servicehelper; - babysitter = pending_activation->babysitter; - + _dbus_assert (babysitter == pending_activation->babysitter); _dbus_babysitter_ref (babysitter); - retval = dbus_watch_handle (watch, condition); - /* There are two major cases here; are we the system bus or the session? Here this * is distinguished by whether or not we use a setuid helper launcher. With the launch helper, * some process exit codes are meaningful, processed by handle_servicehelper_exit_error. @@ -1342,15 +1362,7 @@ babysitter_watch_callback (DBusWatch *watch, */ uses_servicehelper = bus_context_get_servicehelper (pending_activation->activation->context) != NULL; - /* FIXME this is broken in the same way that - * connection watches used to be; there should be - * a separate callback for status change, instead - * of doing "if we handled a watch status might - * have changed" - * - * Fixing this lets us move dbus_watch_handle - * calls into dbus-mainloop.c - */ + /* strictly speaking this is redundant with the check in dbus-spawn now */ if (_dbus_babysitter_get_child_exited (babysitter)) { DBusError error; @@ -1386,6 +1398,11 @@ babysitter_watch_callback (DBusWatch *watch, if (activation_failed) { + bus_context_log (pending_activation->activation->context, + DBUS_SYSTEM_LOG_INFO, "Activated service '%s' failed: %s", + pending_activation->service_name, + error.message); + /* Destroy all pending activations with the same exec */ _dbus_hash_iter_init (pending_activation->activation->pending_activations, &iter); @@ -1405,8 +1422,6 @@ babysitter_watch_callback (DBusWatch *watch, } _dbus_babysitter_unref (babysitter); - - return retval; } static dbus_bool_t @@ -1415,9 +1430,9 @@ add_babysitter_watch (DBusWatch *watch, { BusPendingActivation *pending_activation = data; - return _dbus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context), - watch, babysitter_watch_callback, pending_activation, - NULL); + return _dbus_loop_add_watch ( + bus_context_get_loop (pending_activation->activation->context), + watch); } static void @@ -1427,7 +1442,17 @@ remove_babysitter_watch (DBusWatch *watch, BusPendingActivation *pending_activation = data; _dbus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context), - watch, babysitter_watch_callback, pending_activation); + watch); +} + +static void +toggle_babysitter_watch (DBusWatch *watch, + void *data) +{ + BusPendingActivation *pending_activation = data; + + _dbus_loop_toggle_watch (bus_context_get_loop (pending_activation->activation->context), + watch); } static dbus_bool_t @@ -1448,6 +1473,10 @@ pending_activation_timed_out (void *data) dbus_set_error (&error, DBUS_ERROR_TIMED_OUT, "Activation of %s timed out", pending_activation->service_name); + bus_context_log (pending_activation->activation->context, + DBUS_SYSTEM_LOG_INFO, + "Failed to activate service '%s': timed out", + pending_activation->service_name); pending_activation_failed (pending_activation, &error); @@ -1660,6 +1689,7 @@ bus_activation_activate_service (BusActivation *activation, const char *service_name, DBusError *error) { + DBusError tmp_error; BusActivationEntry *entry; BusPendingActivation *pending_activation; BusPendingActivationEntry *pending_activation_entry; @@ -1670,12 +1700,9 @@ bus_activation_activate_service (BusActivation *activation, char **envp = NULL; int argc; dbus_bool_t retval; - DBusHashIter iter; - dbus_bool_t activated; + dbus_bool_t was_pending_activation; DBusString command; - activated = TRUE; - _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (activation->n_pending_activations >= @@ -1750,11 +1777,13 @@ bus_activation_activate_service (BusActivation *activation, pending_activation_entry->activation_message = activation_message; dbus_message_ref (activation_message); pending_activation_entry->connection = connection; - dbus_connection_ref (connection); + if (connection) + dbus_connection_ref (connection); /* Check if the service is being activated */ pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name); - if (pending_activation) + was_pending_activation = (pending_activation != NULL); + if (was_pending_activation) { if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry)) { @@ -1833,10 +1862,7 @@ bus_activation_activate_service (BusActivation *activation, } if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context), - pending_activation->timeout, - handle_timeout_callback, - pending_activation, - NULL)) + pending_activation->timeout)) { _dbus_verbose ("Failed to add timeout for pending activation\n"); @@ -1861,19 +1887,6 @@ bus_activation_activate_service (BusActivation *activation, pending_activation->n_entries += 1; pending_activation->activation->n_pending_activations += 1; - activated = FALSE; - _dbus_hash_iter_init (activation->pending_activations, &iter); - while (_dbus_hash_iter_next (&iter)) - { - BusPendingActivation *p = _dbus_hash_iter_get_value (&iter); - - if (strcmp (p->exec, entry->exec) == 0) - { - activated = TRUE; - break; - } - } - if (!_dbus_hash_table_insert_string (activation->pending_activations, pending_activation->service_name, pending_activation)) @@ -1896,7 +1909,7 @@ bus_activation_activate_service (BusActivation *activation, return FALSE; } - if (activated) + if (was_pending_activation) return TRUE; if (bus_context_get_systemd_activation (activation->context)) @@ -1962,18 +1975,34 @@ bus_activation_activate_service (BusActivation *activation, service = bus_registry_lookup (registry, &service_string); if (service != NULL) - /* Wonderful, systemd is connected, let's just send the msg */ - retval = bus_dispatch_matches (activation_transaction, NULL, bus_service_get_primary_owners_connection (service), - message, error); + { + bus_context_log (activation->context, + DBUS_SYSTEM_LOG_INFO, "Activating via systemd: service name='%s' unit='%s'", + service_name, + entry->systemd_service); + /* Wonderful, systemd is connected, let's just send the msg */ + retval = bus_dispatch_matches (activation_transaction, NULL, bus_service_get_primary_owners_connection (service), + message, error); + } else - /* systemd is not around, let's "activate" it. */ - retval = bus_activation_activate_service (activation, connection, activation_transaction, TRUE, - message, "org.freedesktop.systemd1", error); + { + bus_context_log (activation->context, + DBUS_SYSTEM_LOG_INFO, "Activating systemd to hand-off: service name='%s' unit='%s'", + service_name, + entry->systemd_service); + /* systemd is not around, let's "activate" it. */ + retval = bus_activation_activate_service (activation, NULL, activation_transaction, TRUE, + message, "org.freedesktop.systemd1", error); + } dbus_message_unref (message); if (!retval) { + bus_context_log (activation->context, + DBUS_SYSTEM_LOG_INFO, "Failed to activate via systemd: service name='%s' unit='%s'", + service_name, + entry->systemd_service); _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_verbose ("failed to send activation message: %s\n", error->name); bus_transaction_cancel_and_free (activation_transaction); @@ -2069,13 +2098,29 @@ bus_activation_activate_service (BusActivation *activation, } _dbus_verbose ("Spawning %s ...\n", argv[0]); + if (servicehelper != NULL) + bus_context_log (activation->context, + DBUS_SYSTEM_LOG_INFO, "Activating service name='%s' (using servicehelper)", + service_name); + else + bus_context_log (activation->context, + DBUS_SYSTEM_LOG_INFO, "Activating service name='%s'", + service_name); + + dbus_error_init (&tmp_error); + if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv, envp, NULL, activation, - error)) + &tmp_error)) { _dbus_verbose ("Failed to spawn child\n"); - _DBUS_ASSERT_ERROR_IS_SET (error); + bus_context_log (activation->context, + DBUS_SYSTEM_LOG_INFO, "Failed to activate service %s: %s", + service_name, + tmp_error.message); + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + dbus_move_error (&tmp_error, error); dbus_free_string_array (argv); dbus_free_string_array (envp); @@ -2087,10 +2132,14 @@ bus_activation_activate_service (BusActivation *activation, _dbus_assert (pending_activation->babysitter != NULL); + _dbus_babysitter_set_result_function (pending_activation->babysitter, + pending_activation_finished_cb, + pending_activation); + if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter, add_babysitter_watch, remove_babysitter_watch, - NULL, + toggle_babysitter_watch, pending_activation, NULL)) { @@ -2140,7 +2189,7 @@ bus_activation_list_services (BusActivation *activation, error: for (j = 0; j < i; j++) - dbus_free (retval[i]); + dbus_free (retval[j]); dbus_free (retval); return FALSE; @@ -2166,10 +2215,16 @@ dbus_activation_systemd_failure (BusActivation *activation, DBUS_TYPE_INVALID)) dbus_set_error(&error, code, str); + if (unit) { DBusHashIter iter; + bus_context_log (activation->context, + DBUS_SYSTEM_LOG_INFO, "Activation via systemd failed for unit '%s': %s", + unit, + str); + _dbus_hash_iter_init (activation->pending_activations, &iter); @@ -2187,7 +2242,7 @@ dbus_activation_systemd_failure (BusActivation *activation, return TRUE; } -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS #include @@ -2494,11 +2549,17 @@ dbus_bool_t bus_activation_service_reload_test (const DBusString *test_data_dir) { DBusString directory; + const char *tmp; if (!_dbus_string_init (&directory)) return FALSE; - if (!_dbus_string_append (&directory, _dbus_get_tmpdir())) + tmp = _dbus_get_tmpdir (); + + if (tmp == NULL) + return FALSE; + + if (!_dbus_string_append (&directory, tmp)) return FALSE; if (!_dbus_string_append (&directory, "/dbus-reload-test-") || @@ -2512,14 +2573,18 @@ bus_activation_service_reload_test (const DBusString *test_data_dir) _dbus_assert_not_reached ("could not initiate service reload test"); if (!do_service_reload_test (&directory, FALSE)) - ; /* Do nothing? */ + { + /* Do nothing? */ + } /* Do OOM tests */ if (!init_service_reload_test (&directory)) _dbus_assert_not_reached ("could not initiate service reload test"); if (!do_service_reload_test (&directory, TRUE)) - ; /* Do nothing? */ + { + /* Do nothing? */ + } /* Cleanup test directory */ if (!cleanup_service_reload_test (&directory)) @@ -2530,4 +2595,4 @@ bus_activation_service_reload_test (const DBusString *test_data_dir) return TRUE; } -#endif /* DBUS_BUILD_TESTS */ +#endif /* DBUS_ENABLE_EMBEDDED_TESTS */