diff options
author | Jan Alexander Steffens (heftig) <jan.steffens@gmail.com> | 2015-11-15 16:00:33 +0100 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2015-11-17 18:21:22 +0000 |
commit | a5c46b4ae4bf1264adb65e4509b4e7af516aa59c (patch) | |
tree | 3c57763f2d51981927d3c5b6335f47773388b9ef | |
parent | 4f116d786539b2f1613d88532f989970f3349c69 (diff) | |
download | dbus-a5c46b4ae4bf1264adb65e4509b4e7af516aa59c.tar.gz |
bus_driver_handle_update_activation_environment: Forward to systemd
If we use systemd activation, forward all UpdateActivationEnvironment
requests to org.freedesktop.systemd1.Manager.SetEnvironment, in order
to ensure variables needed by D-Bus services are available when these
services are launched by systemd.
Since UpdateActivationEnvironment is not available on the system bus,
this only applies to user buses.
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=92857
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
-rw-r--r-- | bus/driver.c | 155 |
1 files changed, 152 insertions, 3 deletions
diff --git a/bus/driver.c b/bus/driver.c index a59d5329..3234250f 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -978,6 +978,72 @@ send_ack_reply (DBusConnection *connection, return TRUE; } +/* + * Send a message from the driver, activating the destination if necessary. + * The message must already have a destination set. + */ +static dbus_bool_t +bus_driver_send_or_activate (BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + BusContext *context; + BusService *service; + const char *service_name; + DBusString service_string; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + service_name = dbus_message_get_destination (message); + + _dbus_assert (service_name != NULL); + + _dbus_string_init_const (&service_string, service_name); + + context = bus_transaction_get_context (transaction); + + service = bus_registry_lookup (bus_context_get_registry (context), + &service_string); + + if (service == NULL) + { + /* destination isn't connected yet; pass the message to activation */ + BusActivation *activation; + + activation = bus_context_get_activation (context); + + if (!bus_transaction_capture (transaction, NULL, message)) + { + BUS_SET_OOM (error); + _dbus_verbose ("No memory for bus_transaction_capture()"); + return FALSE; + } + + if (!bus_activation_activate_service (activation, NULL, transaction, TRUE, + message, service_name, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_verbose ("bus_activation_activate_service() failed"); + return FALSE; + } + } + else + { + DBusConnection *service_conn; + + service_conn = bus_service_get_primary_owners_connection (service); + + if (!bus_transaction_send_from_driver (transaction, service_conn, message)) + { + BUS_SET_OOM (error); + _dbus_verbose ("No memory for bus_transaction_send_from_driver()"); + return FALSE; + } + } + + return TRUE; +} + static dbus_bool_t bus_driver_handle_update_activation_environment (DBusConnection *connection, BusTransaction *transaction, @@ -994,6 +1060,8 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection, int key_type; DBusList *keys, *key_link; DBusList *values, *value_link; + DBusMessage *systemd_message; + DBusMessageIter systemd_iter; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -1034,6 +1102,7 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection, dbus_message_iter_recurse (&iter, &dict_iter); retval = FALSE; + systemd_message = NULL; /* Then loop through the sent dictionary, add the location of * the environment keys and values to lists. The result will @@ -1088,6 +1157,33 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection, _dbus_assert (_dbus_list_get_length (&keys) == _dbus_list_get_length (&values)); + if (bus_context_get_systemd_activation (bus_connection_get_context (connection))) + { + /* Prepare a call to forward environment updates to systemd */ + systemd_message = dbus_message_new_method_call ("org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SetEnvironment"); + if (systemd_message == NULL || + !dbus_message_set_sender (systemd_message, DBUS_SERVICE_DBUS)) + { + BUS_SET_OOM (error); + _dbus_verbose ("No memory to create systemd message\n"); + goto out; + } + + dbus_message_set_no_reply (systemd_message, TRUE); + dbus_message_iter_init_append (systemd_message, &iter); + + if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", + &systemd_iter)) + { + BUS_SET_OOM (error); + _dbus_verbose ("No memory to open systemd message container\n"); + goto out; + } + } + key_link = keys; value_link = values; while (key_link != NULL) @@ -1100,11 +1196,41 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection, if (!bus_activation_set_environment_variable (activation, key, value, error)) - { + { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_verbose ("bus_activation_set_environment_variable() failed\n"); break; - } + } + + if (systemd_message != NULL) + { + DBusString envline; + const char *s; + + /* SetEnvironment wants an array of KEY=VALUE strings */ + if (!_dbus_string_init (&envline) || + !_dbus_string_append_printf (&envline, "%s=%s", key, value)) + { + BUS_SET_OOM (error); + _dbus_verbose ("No memory to format systemd environment line\n"); + _dbus_string_free (&envline); + break; + } + + s = _dbus_string_get_data (&envline); + + if (!dbus_message_iter_append_basic (&systemd_iter, + DBUS_TYPE_STRING, &s)) + { + BUS_SET_OOM (error); + _dbus_verbose ("No memory to append systemd environment line\n"); + _dbus_string_free (&envline); + break; + } + + _dbus_string_free (&envline); + } + key_link = _dbus_list_get_next_link (&keys, key_link); value_link = _dbus_list_get_next_link (&values, value_link); } @@ -1114,7 +1240,28 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection, * matter, so we're punting for now. */ if (key_link != NULL) - goto out; + { + if (systemd_message != NULL) + dbus_message_iter_abandon_container (&iter, &systemd_iter); + goto out; + } + + if (systemd_message != NULL) + { + if (!dbus_message_iter_close_container (&iter, &systemd_iter)) + { + BUS_SET_OOM (error); + _dbus_verbose ("No memory to close systemd message container\n"); + goto out; + } + + if (!bus_driver_send_or_activate (transaction, systemd_message, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_verbose ("bus_driver_send_or_activate() failed\n"); + goto out; + } + } if (!send_ack_reply (connection, transaction, message, error)) @@ -1123,6 +1270,8 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection, retval = TRUE; out: + if (systemd_message != NULL) + dbus_message_unref (systemd_message); _dbus_list_clear (&keys); _dbus_list_clear (&values); return retval; |