From 608bf093dc76ae845f2447457f8529000fdb4da2 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Jul 19 2008 00:05:15 +0000 Subject: allow changing the activation environment --- diff --git a/activation-env.patch b/activation-env.patch new file mode 100644 index 0000000..efa7b60 --- /dev/null +++ b/activation-env.patch @@ -0,0 +1,766 @@ +diff -up dbus-1.2.1/bus/activation.c.activation-env dbus-1.2.1/bus/activation.c +--- dbus-1.2.1/bus/activation.c.activation-env 2008-07-18 19:53:24.000000000 -0400 ++++ dbus-1.2.1/bus/activation.c 2008-07-18 19:56:13.000000000 -0400 +@@ -51,6 +51,7 @@ struct BusActivation + * activations per se + */ + DBusHashTable *directories; ++ DBusHashTable *environment; + }; + + typedef struct +@@ -671,6 +672,69 @@ update_directory (BusActivation *a + return retval; + } + ++static dbus_bool_t ++populate_environment (BusActivation *activation) ++{ ++ DBusString key; ++ DBusString value; ++ int i; ++ char **environment; ++ dbus_bool_t retval; ++ ++ environment = _dbus_get_environment (); ++ ++ if (environment == NULL) ++ return FALSE; ++ ++ if (!_dbus_string_init (&key)) ++ { ++ dbus_free_string_array (environment); ++ return FALSE; ++ } ++ ++ if (!_dbus_string_init (&value)) ++ { ++ _dbus_string_free (&key); ++ dbus_free_string_array (environment); ++ return FALSE; ++ } ++ ++ for (i = 0; environment[i] != NULL; i++) ++ { ++ if (!_dbus_string_append (&key, environment[i])) ++ break; ++ ++ if (_dbus_string_split_on_byte (&key, '=', &value)) ++ { ++ char *hash_key, *hash_value; ++ ++ if (!_dbus_string_steal_data (&key, &hash_key)) ++ break; ++ ++ if (!_dbus_string_steal_data (&value, &hash_value)) ++ break; ++ ++ if (!_dbus_hash_table_insert_string (activation->environment, ++ hash_key, hash_value)) ++ break; ++ } ++ _dbus_string_set_length (&key, 0); ++ _dbus_string_set_length (&value, 0); ++ } ++ ++ if (environment[i] != NULL) ++ goto out; ++ ++ retval = TRUE; ++out: ++ ++ _dbus_string_free (&key); ++ _dbus_string_free (&value); ++ dbus_free_string_array (environment); ++ ++ return retval; ++} ++ + BusActivation* + bus_activation_new (BusContext *context, + const DBusString *address, +@@ -779,6 +843,22 @@ bus_activation_new (BusContext *c + link = _dbus_list_get_next_link (directories, link); + } + ++ activation->environment = _dbus_hash_table_new (DBUS_HASH_STRING, ++ (DBusFreeFunction) dbus_free, ++ (DBusFreeFunction) dbus_free); ++ ++ if (activation->environment == NULL) ++ { ++ BUS_SET_OOM (error); ++ goto failed; ++ } ++ ++ if (!populate_environment (activation)) ++ { ++ BUS_SET_OOM (error); ++ goto failed; ++ } ++ + return activation; + + failed: +@@ -813,41 +893,51 @@ bus_activation_unref (BusActivation *act + _dbus_hash_table_unref (activation->pending_activations); + if (activation->directories) + _dbus_hash_table_unref (activation->directories); +- ++ if (activation->environment) ++ _dbus_hash_table_unref (activation->environment); ++ + dbus_free (activation); + } + +-static void +-child_setup (void *data) ++static dbus_bool_t ++add_bus_environment (BusActivation *activation, ++ DBusError *error) + { +- BusActivation *activation = data; + const char *type; + +- /* If no memory, we simply have the child exit, so it won't try +- * to connect to the wrong thing. +- */ +- if (!_dbus_setenv ("DBUS_STARTER_ADDRESS", activation->server_address)) +- _dbus_exit (1); ++ if (!bus_activation_set_environment_variable (activation, ++ "DBUS_STARTER_ADDRESS", ++ activation->server_address, ++ error)) ++ return FALSE; + + type = bus_context_get_type (activation->context); + if (type != NULL) + { +- if (!_dbus_setenv ("DBUS_STARTER_BUS_TYPE", type)) +- _dbus_exit (1); ++ if (!bus_activation_set_environment_variable (activation, ++ "DBUS_STARTER_BUS_TYPE", type, ++ error)) ++ return FALSE; + + if (strcmp (type, "session") == 0) + { +- if (!_dbus_setenv ("DBUS_SESSION_BUS_ADDRESS", +- activation->server_address)) +- _dbus_exit (1); ++ if (!bus_activation_set_environment_variable (activation, ++ "DBUS_SESSION_BUS_ADDRESS", ++ activation->server_address, ++ error)) ++ return FALSE; + } + else if (strcmp (type, "system") == 0) + { +- if (!_dbus_setenv ("DBUS_SYSTEM_BUS_ADDRESS", +- activation->server_address)) +- _dbus_exit (1); ++ if (!bus_activation_set_environment_variable (activation, ++ "DBUS_SYSTEM_BUS_ADDRESS", ++ activation->server_address, ++ error)) ++ return FALSE; + } + } ++ ++ return TRUE; + } + + typedef struct +@@ -1389,6 +1479,95 @@ activation_find_entry (BusActivation *ac + return entry; + } + ++static char ** ++bus_activation_get_environment (BusActivation *activation) ++{ ++ char **environment; ++ int i, length; ++ DBusString entry; ++ DBusHashIter iter; ++ ++ length = _dbus_hash_table_get_n_entries (activation->environment); ++ ++ environment = dbus_new0 (char *, length + 1); ++ ++ if (environment == NULL) ++ return NULL; ++ ++ i = 0; ++ _dbus_hash_iter_init (activation->environment, &iter); ++ ++ if (!_dbus_string_init (&entry)) ++ { ++ dbus_free_string_array (environment); ++ return NULL; ++ } ++ ++ while (_dbus_hash_iter_next (&iter)) ++ { ++ const char *key, *value; ++ ++ key = (const char *) _dbus_hash_iter_get_string_key (&iter); ++ value = (const char *) _dbus_hash_iter_get_value (&iter); ++ ++ if (!_dbus_string_append_printf (&entry, "%s=%s", key, value)) ++ break; ++ ++ if (!_dbus_string_steal_data (&entry, environment + i)) ++ break; ++ i++; ++ } ++ ++ _dbus_string_free (&entry); ++ ++ if (i != length) ++ { ++ dbus_free_string_array (environment); ++ environment = NULL; ++ } ++ ++ return environment; ++} ++ ++dbus_bool_t ++bus_activation_set_environment_variable (BusActivation *activation, ++ const char *key, ++ const char *value, ++ DBusError *error) ++{ ++ char *hash_key; ++ char *hash_value; ++ dbus_bool_t retval; ++ ++ retval = FALSE; ++ hash_key = NULL; ++ hash_value = NULL; ++ hash_key = _dbus_strdup (key); ++ ++ if (hash_key == NULL) ++ goto out; ++ ++ hash_value = _dbus_strdup (value); ++ ++ if (hash_value == NULL) ++ goto out; ++ ++ if (!_dbus_hash_table_insert_string (activation->environment, ++ hash_key, hash_value)) ++ goto out; ++ ++ retval = TRUE; ++out: ++ if (retval == FALSE) ++ { ++ dbus_free (hash_key); ++ dbus_free (hash_value); ++ BUS_SET_OOM (error); ++ } ++ ++ return retval; ++} ++ + dbus_bool_t + bus_activation_activate_service (BusActivation *activation, + DBusConnection *connection, +@@ -1688,20 +1867,38 @@ bus_activation_activate_service (BusActi + } + _dbus_string_free (&command); + ++ if (!add_bus_environment (activation, error)) ++ { ++ _DBUS_ASSERT_ERROR_IS_SET (error); ++ dbus_free_string_array (argv); ++ return FALSE; ++ } ++ ++ envp = bus_activation_get_environment (activation); ++ ++ if (envp == NULL) ++ { ++ BUS_SET_OOM (error); ++ dbus_free_string_array (argv); ++ return FALSE; ++ } ++ + _dbus_verbose ("Spawning %s ...\n", argv[0]); + if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv, + envp, +- child_setup, activation, ++ NULL, activation, + error)) + { + _dbus_verbose ("Failed to spawn child\n"); + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_free_string_array (argv); ++ dbus_free_string_array (envp); + + return FALSE; + } + + dbus_free_string_array (argv); ++ envp = NULL; + + _dbus_assert (pending_activation->babysitter != NULL); + +diff -up dbus-1.2.1/bus/activation.h.activation-env dbus-1.2.1/bus/activation.h +--- dbus-1.2.1/bus/activation.h.activation-env 2008-07-18 19:53:32.000000000 -0400 ++++ dbus-1.2.1/bus/activation.h 2008-07-18 19:56:13.000000000 -0400 +@@ -34,6 +34,11 @@ BusActivation* bus_activation_new + DBusError *error); + BusActivation* bus_activation_ref (BusActivation *activation); + void bus_activation_unref (BusActivation *activation); ++ ++dbus_bool_t bus_activation_set_environment_variable (BusActivation *activation, ++ const char *key, ++ const char *value, ++ DBusError *error); + dbus_bool_t bus_activation_activate_service (BusActivation *activation, + DBusConnection *connection, + BusTransaction *transaction, +diff -up dbus-1.2.1/bus/dbus-daemon.1.in.activation-env dbus-1.2.1/bus/dbus-daemon.1.in +--- dbus-1.2.1/bus/dbus-daemon.1.in.activation-env 2008-07-18 19:53:43.000000000 -0400 ++++ dbus-1.2.1/bus/dbus-daemon.1.in 2008-07-18 19:56:13.000000000 -0400 +@@ -138,7 +138,21 @@ Root element. + The well-known type of the message bus. Currently known values are + "system" and "session"; if other values are set, they should be + either added to the D-Bus specification, or namespaced. The last +- element "wins" (previous values are ignored). ++ element "wins" (previous values are ignored). This element ++only controls which message bus specific environment variables are ++set in activated clients. Most of the policy that distinguishes a ++session bus from the system bus is controlled from the other elements ++in the configuration file. ++ ++.PP ++If the well-known type of the message bus is "session", then the ++DBUS_STARTER_BUS_TYPE environment variable will be set to "session" ++and the DBUS_SESSION_BUS_ADDRESS environment variable will be set ++to the address of the session bus. Likewise, if the type of the ++message bus is "system", then the DBUS_STARTER_BUS_TYPE environment ++variable will be set to "system" and the DBUS_SESSION_BUS_ADDRESS ++environment variable will be set to the address of the system bus ++(which is normally well known anyway). + + .PP + Example: session +diff -up dbus-1.2.1/bus/driver.c.activation-env dbus-1.2.1/bus/driver.c +--- dbus-1.2.1/bus/driver.c.activation-env 2008-07-18 19:53:54.000000000 -0400 ++++ dbus-1.2.1/bus/driver.c 2008-07-18 19:56:13.000000000 -0400 +@@ -811,6 +811,133 @@ send_ack_reply (DBusConnection *connecti + } + + static dbus_bool_t ++bus_driver_handle_update_activation_environment (DBusConnection *connection, ++ BusTransaction *transaction, ++ DBusMessage *message, ++ DBusError *error) ++{ ++ dbus_bool_t retval; ++ BusActivation *activation; ++ DBusMessageIter iter; ++ DBusMessageIter dict_iter; ++ DBusMessageIter dict_entry_iter; ++ int msg_type; ++ int array_type; ++ int key_type; ++ DBusList *keys, *key_link; ++ DBusList *values, *value_link; ++ ++ _DBUS_ASSERT_ERROR_IS_CLEAR (error); ++ ++ activation = bus_connection_get_activation (connection); ++ ++ dbus_message_iter_init (message, &iter); ++ ++ /* The message signature has already been checked for us, ++ * so let's just assert it's right. ++ */ ++ msg_type = dbus_message_iter_get_arg_type (&iter); ++ ++ _dbus_assert (msg_type == DBUS_TYPE_ARRAY); ++ ++ dbus_message_iter_recurse (&iter, &dict_iter); ++ ++ retval = FALSE; ++ ++ /* Then loop through the sent dictionary, add the location of ++ * the environment keys and values to lists. The result will ++ * be in reverse order, so we don't have to constantly search ++ * for the end of the list in a loop. ++ */ ++ keys = NULL; ++ values = NULL; ++ while ((array_type = dbus_message_iter_get_arg_type (&dict_iter)) == DBUS_TYPE_DICT_ENTRY) ++ { ++ dbus_message_iter_recurse (&dict_iter, &dict_entry_iter); ++ ++ while ((key_type = dbus_message_iter_get_arg_type (&dict_entry_iter)) == DBUS_TYPE_STRING) ++ { ++ char *key; ++ char *value; ++ int value_type; ++ ++ dbus_message_iter_get_basic (&dict_entry_iter, &key); ++ dbus_message_iter_next (&dict_entry_iter); ++ ++ value_type = dbus_message_iter_get_arg_type (&dict_entry_iter); ++ ++ if (value_type != DBUS_TYPE_STRING) ++ break; ++ ++ dbus_message_iter_get_basic (&dict_entry_iter, &value); ++ ++ if (!_dbus_list_append (&keys, key)) ++ { ++ BUS_SET_OOM (error); ++ break; ++ } ++ ++ if (!_dbus_list_append (&values, value)) ++ { ++ BUS_SET_OOM (error); ++ break; ++ } ++ ++ dbus_message_iter_next (&dict_entry_iter); ++ } ++ ++ if (key_type != DBUS_TYPE_INVALID) ++ break; ++ ++ dbus_message_iter_next (&dict_iter); ++ } ++ ++ if (array_type != DBUS_TYPE_INVALID) ++ goto out; ++ ++ _dbus_assert (_dbus_list_get_length (&keys) == _dbus_list_get_length (&values)); ++ ++ key_link = keys; ++ value_link = values; ++ while (key_link != NULL) ++ { ++ const char *key; ++ const char *value; ++ ++ key = key_link->data; ++ value = value_link->data; ++ ++ 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; ++ } ++ key_link = _dbus_list_get_next_link (&keys, key_link); ++ value_link = _dbus_list_get_next_link (&values, value_link); ++ } ++ ++ /* FIXME: We can fail early having set only some of the environment variables, ++ * (because of OOM failure). It's sort of hard to fix and it doesn't really ++ * matter, so we're punting for now. ++ */ ++ if (key_link != NULL) ++ goto out; ++ ++ if (!send_ack_reply (connection, transaction, ++ message, error)) ++ goto out; ++ ++ retval = TRUE; ++ ++ out: ++ _dbus_list_clear (&keys); ++ _dbus_list_clear (&values); ++ return retval; ++} ++ ++static dbus_bool_t + bus_driver_handle_add_match (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, +@@ -1467,6 +1594,10 @@ struct + DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING, + DBUS_TYPE_UINT32_AS_STRING, + bus_driver_handle_activate_service }, ++ { "UpdateActivationEnvironment", ++ DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, ++ "", ++ bus_driver_handle_update_activation_environment }, + { "NameHasOwner", + DBUS_TYPE_STRING_AS_STRING, + DBUS_TYPE_BOOLEAN_AS_STRING, +diff -up dbus-1.2.1/bus/system.conf.in.activation-env dbus-1.2.1/bus/system.conf.in +--- dbus-1.2.1/bus/system.conf.in.activation-env 2008-07-18 19:54:03.000000000 -0400 ++++ dbus-1.2.1/bus/system.conf.in 2008-07-18 19:56:13.000000000 -0400 +@@ -56,6 +56,10 @@ + + + ++ ++ + + +