Merge branch 'master' of ssh://walters@git.freedesktop.org/git/dbus/dbus

This commit is contained in:
Colin Walters 2008-07-24 16:19:34 -04:00
commit d86df0220e
12 changed files with 531 additions and 20 deletions

View file

@ -51,6 +51,7 @@ struct BusActivation
* activations per se
*/
DBusHashTable *directories;
DBusHashTable *environment;
};
typedef struct
@ -671,6 +672,69 @@ update_directory (BusActivation *activation,
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 *context,
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 *activation)
_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 *activation,
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 (BusActivation *activation,
}
_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);

View file

@ -34,6 +34,11 @@ BusActivation* bus_activation_new (BusContext *context,
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,

View file

@ -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
<type> element "wins" (previous values are ignored).
<type> 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: <type>session</type>

View file

@ -810,6 +810,133 @@ send_ack_reply (DBusConnection *connection,
return TRUE;
}
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,
@ -1542,6 +1669,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,

View file

@ -53,6 +53,10 @@
<!-- valid replies are always allowed -->
<allow send_requested_reply="true"/>
<allow receive_requested_reply="true"/>
<!-- disallow changing the activation environment of system services -->
<deny send_destination="org.freedesktop.DBus"
send_interface="org.freedesktop.DBus"
send_member="UpdateActivationEnvironment"/>
</policy>
<!-- Config files are placed here that among other things, punch

View file

@ -880,6 +880,7 @@ write_status_and_exit (int fd, int status)
static void
do_exec (int child_err_report_fd,
char **argv,
char **envp,
DBusSpawnChildSetupFunc child_setup,
void *user_data)
{
@ -910,8 +911,17 @@ do_exec (int child_err_report_fd,
_dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
}
#endif
if (envp == NULL)
{
extern char **environ;
_dbus_assert (environ != NULL);
envp = environ;
}
execv (argv[0], argv);
execve (argv[0], argv, envp);
/* Exec failed */
write_err_and_exit (child_err_report_fd,
@ -1190,6 +1200,7 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
{
do_exec (child_err_report_pipe[WRITE_END],
argv,
env,
child_setup, user_data);
_dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
}
@ -1218,6 +1229,8 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
else
_dbus_babysitter_unref (sitter);
dbus_free_string_array (env);
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
return TRUE;

View file

@ -846,6 +846,31 @@ _dbus_string_test (void)
_dbus_string_free (&str);
}
{
const char two_strings[] = "one\ttwo";
if (!_dbus_string_init (&str))
_dbus_assert_not_reached ("no memory");
if (!_dbus_string_init (&other))
_dbus_assert_not_reached ("no memory");
if (!_dbus_string_append (&str, two_strings))
_dbus_assert_not_reached ("no memory");
if (!_dbus_string_split_on_byte (&str, '\t', &other))
_dbus_assert_not_reached ("no memory or delimiter not found");
if (strcmp (_dbus_string_get_data (&str), "one") != 0)
_dbus_assert_not_reached ("left side after split on tab is wrong");
if (strcmp (_dbus_string_get_data (&other), "two") != 0)
_dbus_assert_not_reached ("right side after split on tab is wrong");
_dbus_string_free (&str);
_dbus_string_free (&other);
}
return TRUE;
}

View file

@ -1677,6 +1677,48 @@ _dbus_string_replace_len (const DBusString *source,
return TRUE;
}
/**
* Looks for the first occurance of a byte, deletes that byte,
* and moves everything after the byte to the beginning of a
* separate string. Both strings must be initialized, valid
* strings.
*
* @param source the source string
* @param byte the byte to remove and split the string at
* @param tail the split off string
* @returns #FALSE if not enough memory or if byte could not be found
*
*/
dbus_bool_t
_dbus_string_split_on_byte (DBusString *source,
unsigned char byte,
DBusString *tail)
{
int byte_position;
char byte_string[2] = "";
int head_length;
int tail_length;
byte_string[0] = (char) byte;
if (!_dbus_string_find (source, 0, byte_string, &byte_position))
return FALSE;
head_length = byte_position;
tail_length = _dbus_string_get_length (source) - head_length - 1;
if (!_dbus_string_move_len (source, byte_position + 1, tail_length,
tail, 0))
return FALSE;
/* remove the trailing delimiter byte from the head now.
*/
if (!_dbus_string_set_length (source, head_length))
return FALSE;
return TRUE;
}
/* Unicode macros and utf8_validate() from GLib Owen Taylor, Havoc
* Pennington, and Tom Tromey are the authors and authorized relicense.
*/

View file

@ -201,6 +201,9 @@ dbus_bool_t _dbus_string_replace_len (const DBusString *source,
DBusString *dest,
int replace_at,
int replace_len);
dbus_bool_t _dbus_string_split_on_byte (DBusString *source,
unsigned char byte,
DBusString *tail);
void _dbus_string_get_unichar (const DBusString *str,
int start,
dbus_unichar_t *ch_return,

View file

@ -200,6 +200,48 @@ _dbus_clearenv (void)
return rc;
}
/**
* Gets a #NULL-terminated list of key=value pairs from the
* environment. Use dbus_free_string_array to free it.
*
* @returns the environment or #NULL on OOM
*/
char **
_dbus_get_environment (void)
{
int i, length;
extern char **environ;
char **environment;
_dbus_assert (environ != NULL);
for (length = 0; environ[length] != NULL; length++);
/* Add one for NULL */
length++;
environment = dbus_new0 (char *, length);
if (environment == NULL)
return NULL;
for (i = 0; environ[i] != NULL; i++)
{
environment[i] = _dbus_strdup (environ[i]);
if (environment[i] == NULL)
break;
}
if (environ[i] != NULL)
{
dbus_free_string_array (environment);
environment = NULL;
}
return environment;
}
/*
* init a pipe instance.
*

View file

@ -101,6 +101,7 @@ const char* _dbus_getenv (const char *varname);
dbus_bool_t _dbus_setenv (const char *varname,
const char *value);
dbus_bool_t _dbus_clearenv (void);
char ** _dbus_get_environment (void);
/** A process ID */
typedef unsigned long dbus_pid_t;

View file

@ -3678,6 +3678,40 @@
</sect3>
<sect3 id="bus-messages-update-activation-environment">
<title><literal>org.freedesktop.DBus.UpdateActivationEnvironment</literal></title>
<para>
As a method:
<programlisting>
UpdateActivationEnvironment (in ARRAY of DICT&lt;STRING,STRING&gt; environment)
</programlisting>
Message arguments:
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Argument</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry>ARRAY of DICT&lt;STRING,STRING&gt;</entry>
<entry>Environment to add or update</entry>
</row>
</tbody>
</tgroup>
</informaltable>
Normally, session bus activated services inherit the environment of the bus daemon. This method adds to or modifies that environment when activating services.
</para>
<para>
Some bus instances, such as the standard system bus, may disable access to this method for some or all callers.
</para>
</sect3>
<sect3 id="bus-messages-get-name-owner">
<title><literal>org.freedesktop.DBus.GetNameOwner</literal></title>
<para>