summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2006-10-01 03:18:47 +0000
committerHavoc Pennington <hp@redhat.com>2006-10-01 03:18:47 +0000
commitd8155bf51bf6484a94e734601526bf211053a5e1 (patch)
tree0185753a00e18f73efe79533624b54714e03071d
parentf6fa010403cb2badd88ce096ae91f664418508d1 (diff)
2006-09-30 Havoc Pennington <hp@redhat.com>
* configure.in (LT_CURRENT, LT_AGE): increment current and age to reflect addition of interfaces. * doc/dbus-specification.xml: describe a new org.freedesktop.DBus.Peer.GetMachineId method * dbus/dbus-string.c (_dbus_string_skip_white_reverse): new function (_dbus_string_skip_white, _dbus_string_skip_blank): use new DBUS_IS_ASCII_BLANK, DBUS_IS_ASCII_WHITE macros and fix assertion at end of skip_white (_dbus_string_chop_white): new function * bus/connection.c (bus_connections_setup_connection): call dbus_connection_set_route_peer_messages. * dbus/dbus-connection.c (_dbus_connection_peer_filter_unlocked_no_update): modify to support a GetMachineId method. Also, support a new flag to let the bus pass peer methods through to apps on the bus, which can be set with dbus_connection_set_route_peer_messages. Finally, handle and return an error for anything unknown on the Peer interface, which will allow us to extend the Peer interface in the future without fear that we're now intercepting something apps were wanting to see. * tools/dbus-uuidgen.c: a thin wrapper around the functions in dbus/dbus-uuidgen.c * dbus/dbus-uuidgen.c: implement the bulk of the dbus-uuidgen binary here, since most of the code is already in libdbus * dbus/dbus-sysdeps.c (_dbus_read_local_machine_uuid): read the uuid from the system config file * dbus/dbus-internals.c (_dbus_generate_uuid, _dbus_uuid_encode) (_dbus_read_uuid_file_without_creating) (_dbus_create_uuid_file_exclusively, _dbus_read_uuid_file): new uuid-related functions, partly factored out from dbus-server.c * dbus/dbus-sysdeps.c (_dbus_error_from_errno): convert EEXIST to DBUS_ERROR_FILE_EXISTS instead of EEXIST * dbus/dbus-protocol.h (DBUS_ERROR_FILE_EXISTS): add file exists error * tools/dbus-cleanup-sockets.1: explain what the point of this thing is a bit more * autogen.sh (run_configure): add --config-cache to default configure args * dbus/dbus-internals.h (_DBUS_ASSERT_ERROR_IS_SET): disable the error set/clear assertions when DBUS_DISABLE_CHECKS is defined * tools/dbus-launch.c (main): if xdisplay hasn't been opened, don't try to save address, fixes crash in make check
-rw-r--r--ChangeLog61
-rwxr-xr-xautogen.sh2
-rw-r--r--bus/connection.c2
-rw-r--r--bus/dispatch.c84
-rw-r--r--configure.in4
-rw-r--r--dbus/Makefile.am6
-rw-r--r--dbus/dbus-connection.c169
-rw-r--r--dbus/dbus-connection.h4
-rw-r--r--dbus/dbus-internals.c252
-rw-r--r--dbus/dbus-internals.h33
-rw-r--r--dbus/dbus-protocol.h2
-rw-r--r--dbus/dbus-server-protected.h10
-rw-r--r--dbus/dbus-server.c28
-rw-r--r--dbus/dbus-string-private.h12
-rw-r--r--dbus/dbus-string-util.c37
-rw-r--r--dbus/dbus-string.c92
-rw-r--r--dbus/dbus-string.h4
-rw-r--r--dbus/dbus-sysdeps-unix.c32
-rw-r--r--dbus/dbus-sysdeps.c2
-rw-r--r--dbus/dbus-sysdeps.h7
-rw-r--r--dbus/dbus-threads.c3
-rw-r--r--dbus/dbus-uuidgen.c123
-rw-r--r--dbus/dbus-uuidgen.h47
-rw-r--r--doc/dbus-specification.xml33
-rw-r--r--tools/Makefile.am8
-rw-r--r--tools/dbus-cleanup-sockets.117
-rw-r--r--tools/dbus-launch-x11.c2
-rw-r--r--tools/dbus-launch.c59
-rw-r--r--tools/dbus-uuidgen.191
-rw-r--r--tools/dbus-uuidgen.c161
-rwxr-xr-xtools/run-with-tmp-session-bus.sh8
31 files changed, 1262 insertions, 133 deletions
diff --git a/ChangeLog b/ChangeLog
index 55a88c88..d9bf6aa7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,64 @@
+2006-09-30 Havoc Pennington <hp@redhat.com>
+
+ * configure.in (LT_CURRENT, LT_AGE): increment current and age to
+ reflect addition of interfaces.
+
+ * doc/dbus-specification.xml: describe a new
+ org.freedesktop.DBus.Peer.GetMachineId method
+
+ * dbus/dbus-string.c (_dbus_string_skip_white_reverse): new function
+ (_dbus_string_skip_white, _dbus_string_skip_blank): use new
+ DBUS_IS_ASCII_BLANK, DBUS_IS_ASCII_WHITE macros and fix assertion
+ at end of skip_white
+ (_dbus_string_chop_white): new function
+
+ * bus/connection.c (bus_connections_setup_connection): call
+ dbus_connection_set_route_peer_messages.
+
+ * dbus/dbus-connection.c
+ (_dbus_connection_peer_filter_unlocked_no_update): modify to
+ support a GetMachineId method.
+
+ Also, support a new flag to let the bus pass peer methods through
+ to apps on the bus, which can be set with
+ dbus_connection_set_route_peer_messages.
+
+ Finally, handle and return an error for anything unknown on the
+ Peer interface, which will allow us to extend the Peer interface
+ in the future without fear that we're now intercepting something
+ apps were wanting to see.
+
+ * tools/dbus-uuidgen.c: a thin wrapper around the functions in
+ dbus/dbus-uuidgen.c
+
+ * dbus/dbus-uuidgen.c: implement the bulk of the dbus-uuidgen
+ binary here, since most of the code is already in libdbus
+
+ * dbus/dbus-sysdeps.c (_dbus_read_local_machine_uuid): read the
+ uuid from the system config file
+
+ * dbus/dbus-internals.c (_dbus_generate_uuid, _dbus_uuid_encode)
+ (_dbus_read_uuid_file_without_creating)
+ (_dbus_create_uuid_file_exclusively, _dbus_read_uuid_file): new
+ uuid-related functions, partly factored out from dbus-server.c
+
+ * dbus/dbus-sysdeps.c (_dbus_error_from_errno): convert EEXIST to
+ DBUS_ERROR_FILE_EXISTS instead of EEXIST
+
+ * dbus/dbus-protocol.h (DBUS_ERROR_FILE_EXISTS): add file exists error
+
+ * tools/dbus-cleanup-sockets.1: explain what the point of this
+ thing is a bit more
+
+ * autogen.sh (run_configure): add --config-cache to default
+ configure args
+
+ * dbus/dbus-internals.h (_DBUS_ASSERT_ERROR_IS_SET): disable the
+ error set/clear assertions when DBUS_DISABLE_CHECKS is defined
+
+ * tools/dbus-launch.c (main): if xdisplay hasn't been opened,
+ don't try to save address, fixes crash in make check
+
2006-09-30 Thiago Macieira <thiago@kde.org>
* configure.in: add DBUS_BINDIR as a #define to C source code.
diff --git a/autogen.sh b/autogen.sh
index 6435fd5e..76561338 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -83,7 +83,7 @@ for arg in $*; do
done
if $run_configure; then
- $srcdir/configure --enable-maintainer-mode "$@"
+ $srcdir/configure --enable-maintainer-mode --config-cache "$@"
echo
echo "Now type 'make' to compile $PROJECT."
else
diff --git a/bus/connection.c b/bus/connection.c
index a7f3c1e9..df888f47 100644
--- a/bus/connection.c
+++ b/bus/connection.c
@@ -564,6 +564,8 @@ bus_connections_setup_connection (BusConnections *connections,
return FALSE;
}
+ dbus_connection_set_route_peer_messages (connection, TRUE);
+
retval = FALSE;
dbus_error_init (&error);
diff --git a/bus/dispatch.c b/bus/dispatch.c
index e1dd001f..d8b6ffb4 100644
--- a/bus/dispatch.c
+++ b/bus/dispatch.c
@@ -2941,6 +2941,87 @@ check_existent_ping (BusContext *context,
* but the correct thing may include OOM errors.
*/
static dbus_bool_t
+check_existent_get_machine_id (BusContext *context,
+ DBusConnection *connection)
+{
+ DBusMessage *message;
+ dbus_uint32_t serial;
+ const char *machine_id;
+
+ message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME,
+ "/org/freedesktop/TestSuite",
+ "org.freedesktop.DBus.Peer",
+ "GetMachineId");
+
+ if (message == NULL)
+ return TRUE;
+
+ if (!dbus_connection_send (connection, message, &serial))
+ {
+ dbus_message_unref (message);
+ return TRUE;
+ }
+
+ dbus_message_unref (message);
+ message = NULL;
+
+ bus_test_run_everything (context);
+
+ /* Note: if this test is run in OOM mode, it will block when the bus
+ * doesn't send a reply due to OOM.
+ */
+ block_connection_until_message_from_bus (context, connection, "reply from running GetMachineId");
+
+ message = pop_message_waiting_for_memory (connection);
+ if (message == NULL)
+ {
+ _dbus_warn ("Failed to pop message! Should have been reply from GetMachineId message\n");
+ return FALSE;
+ }
+
+ if (dbus_message_get_reply_serial (message) != serial)
+ {
+ _dbus_warn ("Wrong reply serial\n");
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ {
+ _dbus_warn ("Unexpected message return during GetMachineId\n");
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ machine_id = NULL;
+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &machine_id, DBUS_TYPE_INVALID))
+ {
+ _dbus_warn ("Did not get a machine ID in reply to GetMachineId\n");
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ if (machine_id == NULL || strlen (machine_id) != 32)
+ {
+ _dbus_warn ("Machine id looks bogus: '%s'\n", machine_id ? machine_id : "null");
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ /* We can't check that the machine id is correct because during make check it is
+ * just made up for each process separately
+ */
+
+ dbus_message_unref (message);
+ message = NULL;
+
+ return TRUE;
+}
+
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
+static dbus_bool_t
check_existent_service_auto_start (BusContext *context,
DBusConnection *connection)
{
@@ -3115,6 +3196,9 @@ check_existent_service_auto_start (BusContext *context,
if (!check_existent_ping (context, connection))
goto out;
+ if (!check_existent_get_machine_id (context, connection))
+ goto out;
+
if (!check_existent_hello_from_self (context, connection))
goto out;
diff --git a/configure.in b/configure.in
index 0c70bb31..bfe50d6b 100644
--- a/configure.in
+++ b/configure.in
@@ -25,7 +25,7 @@ AM_MAINTAINER_MODE
#
## increment if the interface has additions, changes, removals.
-LT_CURRENT=4
+LT_CURRENT=5
## increment any time the source changes; set to
## 0 if you increment CURRENT
@@ -34,7 +34,7 @@ LT_REVISION=0
## increment if any interfaces have been added; set to 0
## if any interfaces have been changed or removed. removal has
## precedence over adding, so set to 0 if both happened.
-LT_AGE=1
+LT_AGE=2
AC_SUBST(LT_CURRENT)
AC_SUBST(LT_REVISION)
diff --git a/dbus/Makefile.am b/dbus/Makefile.am
index 84ee5609..ba326c14 100644
--- a/dbus/Makefile.am
+++ b/dbus/Makefile.am
@@ -1,5 +1,7 @@
-INCLUDES=-I$(top_builddir) -I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) -DDBUS_COMPILATION
+configdir=$(sysconfdir)/dbus-1
+
+INCLUDES=-I$(top_builddir) -I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) -DDBUS_COMPILATION -DDBUS_MACHINE_UUID_FILE=\""$(configdir)/machine-id"\"
dbusincludedir=$(includedir)/dbus-1.0/dbus
dbusarchincludedir=$(libdir)/dbus-1.0/include/dbus
@@ -80,6 +82,8 @@ DBUS_LIB_SOURCES= \
dbus-transport-socket.h \
dbus-transport-unix.c \
dbus-transport-unix.h \
+ dbus-uuidgen.c \
+ dbus-uuidgen.h \
dbus-watch.c \
dbus-watch.h
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index d60816c3..254eb008 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-connection.c DBusConnection object
*
- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc.
+ * Copyright (C) 2002-2006 Red Hat Inc.
*
* Licensed under the Academic Free License version 2.1
*
@@ -246,6 +246,8 @@ struct DBusConnection
unsigned int io_path_acquired : 1; /**< Someone has transport io path (can use the transport to read/write messages) */
unsigned int exit_on_disconnect : 1; /**< If #TRUE, exit after handling disconnect signal */
+
+ unsigned int route_peer_messages : 1; /**< If #TRUE, if org.freedesktop.DBus.Peer messages have a bus name, don't handle them automatically */
#ifndef DBUS_DISABLE_CHECKS
unsigned int have_connection_lock : 1; /**< Used to check locking */
@@ -1175,6 +1177,8 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
connection->objects = objects;
connection->exit_on_disconnect = FALSE;
connection->shareable = FALSE;
+ connection->route_peer_messages = FALSE;
+
#ifndef DBUS_DISABLE_CHECKS
connection->generation = _dbus_current_generation;
#endif
@@ -3575,15 +3579,20 @@ dbus_connection_get_dispatch_status (DBusConnection *connection)
}
/**
-* Filter funtion for handling the Peer standard interface
-**/
+ * Filter funtion for handling the Peer standard interface.
+ */
static DBusHandlerResult
_dbus_connection_peer_filter_unlocked_no_update (DBusConnection *connection,
DBusMessage *message)
{
- if (dbus_message_is_method_call (message,
- DBUS_INTERFACE_PEER,
- "Ping"))
+ if (connection->route_peer_messages && dbus_message_get_destination (message) != NULL)
+ {
+ /* This means we're letting the bus route this message */
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ else if (dbus_message_is_method_call (message,
+ DBUS_INTERFACE_PEER,
+ "Ping"))
{
DBusMessage *ret;
dbus_bool_t sent;
@@ -3601,9 +3610,68 @@ _dbus_connection_peer_filter_unlocked_no_update (DBusConnection *connection,
return DBUS_HANDLER_RESULT_HANDLED;
}
-
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ else if (dbus_message_is_method_call (message,
+ DBUS_INTERFACE_PEER,
+ "GetMachineId"))
+ {
+ DBusMessage *ret;
+ dbus_bool_t sent;
+ DBusString uuid;
+
+ ret = dbus_message_new_method_return (message);
+ if (ret == NULL)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ sent = FALSE;
+ _dbus_string_init (&uuid);
+ if (_dbus_get_local_machine_uuid_encoded (&uuid))
+ {
+ const char *v_STRING = _dbus_string_get_const_data (&uuid);
+ if (dbus_message_append_args (ret,
+ DBUS_TYPE_STRING, &v_STRING,
+ DBUS_TYPE_INVALID))
+ {
+ sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL);
+ }
+ }
+ _dbus_string_free (&uuid);
+
+ dbus_message_unref (ret);
+
+ if (!sent)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else if (dbus_message_has_interface (message, DBUS_INTERFACE_PEER))
+ {
+ /* We need to bounce anything else with this interface, otherwise apps
+ * could start extending the interface and when we added extensions
+ * here to DBusConnection we'd break those apps.
+ */
+
+ DBusMessage *ret;
+ dbus_bool_t sent;
+
+ ret = dbus_message_new_error (message,
+ DBUS_ERROR_UNKNOWN_METHOD,
+ "Unknown method invoked on org.freedesktop.DBus.Peer interface");
+ if (ret == NULL)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL);
+
+ dbus_message_unref (ret);
+
+ if (!sent)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else
+ {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
}
/**
@@ -4409,6 +4477,35 @@ dbus_connection_set_unix_user_function (DBusConnection *connection,
}
/**
+ *
+ * Normally #DBusConnection automatically handles all messages to the
+ * org.freedesktop.DBus.Peer interface. However, the message bus wants
+ * to be able to route methods on that interface through the bus and
+ * to other applications. If routing peer messages is enabled, then
+ * messages with the org.freedesktop.DBus.Peer interface that also
+ * have a bus destination name set will not be automatically
+ * handled by the #DBusConnection and instead will be dispatched
+ * normally to the application.
+ *
+ *
+ * If a normal application sets this flag, it can break things badly.
+ * So don't set this unless you are the message bus.
+ *
+ * @param connection the connection
+ * @param value #TRUE to pass through org.freedesktop.DBus.Peer messages with a bus name set
+ */
+void
+dbus_connection_set_route_peer_messages (DBusConnection *connection,
+ dbus_bool_t value)
+{
+ _dbus_return_if_fail (connection != NULL);
+
+ CONNECTION_LOCK (connection);
+ connection->route_peer_messages = TRUE;
+ CONNECTION_UNLOCK (connection);
+}
+
+/**
* Adds a message filter. Filters are handlers that are run on all
* incoming messages, prior to the objects registered with
* dbus_connection_register_object_path(). Filters are run in the
@@ -4968,4 +5065,58 @@ dbus_connection_get_outgoing_size (DBusConnection *connection)
return res;
}
+/**
+ * Obtains the machine UUID of the machine this process is running on.
+ *
+ * The returned string must be freed with dbus_free().
+ *
+ * This UUID is guaranteed to remain the same until the next reboot
+ * (unless the sysadmin foolishly changes it and screws themselves).
+ * It will usually remain the same across reboots also, but hardware
+ * configuration changes or rebuilding the machine could break that.
+ *
+ * The idea is that two processes with the same machine ID should be
+ * able to use shared memory, UNIX domain sockets, process IDs, and other
+ * features of the OS that require both processes to be running
+ * on the same OS kernel instance.
+ *
+ * The machine ID can also be used to create unique per-machine
+ * instances. For example, you could use it in bus names or
+ * X selection names.
+ *
+ * The machine ID is preferred over the machine hostname, because
+ * the hostname is frequently set to "localhost.localdomain" and
+ * may also change at runtime.
+ *
+ * You can get the machine ID of a remote application by invoking the
+ * method GetMachineId from interface org.freedesktop.DBus.Peer.
+ *
+ * If the remote application has the same machine ID as the one
+ * returned by this function, then the remote application is on the
+ * same machine as your application.
+ *
+ * @returns a 32-byte-long hex-encoded UUID string, or #NULL if insufficient memory
+ */
+char*
+dbus_get_local_machine_id (void)
+{
+ DBusString uuid;
+ char *s;
+
+ s = NULL;
+ _dbus_string_init (&uuid);
+ if (!_dbus_get_local_machine_uuid_encoded (&uuid) ||
+ !_dbus_string_steal_data (&uuid, &s))
+ {
+ _dbus_string_free (&uuid);
+ return FALSE;
+ }
+ else
+ {
+ _dbus_string_free (&uuid);
+ return s;
+ }
+
+}
+
/** @} */
diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h
index ed90a7f6..1e78c1f3 100644
--- a/dbus/dbus-connection.h
+++ b/dbus/dbus-connection.h
@@ -151,6 +151,8 @@ void dbus_connection_set_unix_user_function (DBusConnection
DBusAllowUnixUserFunction function,
void *data,
DBusFreeFunction free_data_function);
+void dbus_connection_set_route_peer_messages (DBusConnection *connection,
+ dbus_bool_t value);
int dbus_watch_get_fd (DBusWatch *watch);
@@ -258,6 +260,8 @@ dbus_bool_t dbus_connection_get_unix_fd (DBusConnection
dbus_bool_t dbus_connection_get_socket (DBusConnection *connection,
int *fd);
+char* dbus_get_local_machine_id (void);
+
DBUS_END_DECLS
#endif /* DBUS_CONNECTION_H */
diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c
index 8567ebb5..707b4005 100644
--- a/dbus/dbus-internals.c
+++ b/dbus/dbus-internals.c
@@ -413,6 +413,258 @@ _dbus_string_array_contains (const char **array,
return FALSE;
}
+/**
+ * Generates a new UUID. If you change how this is done,
+ * there's some text about it in the spec that should also change.
+ *
+ * @param uuid the uuid to initialize
+ */
+void
+_dbus_generate_uuid (DBusGUID *uuid)
+{
+ long now;
+ char *p;
+ int ts_size;
+
+ _dbus_get_current_time (&now, NULL);
+
+ uuid->as_uint32s[0] = now;
+
+ ts_size = sizeof (uuid->as_uint32s[0]);
+ p = ((char*)uuid->as_bytes) + ts_size;
+
+ _dbus_generate_random_bytes_buffer (p,
+ sizeof (uuid->as_bytes) - ts_size);
+}
+
+/**
+ * Hex-encode a UUID.
+ *
+ * @param uuid the uuid
+ * @param encoded string to append hex uuid to
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_uuid_encode (const DBusGUID *uuid,
+ DBusString *encoded)
+{
+ DBusString binary;
+ _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
+ return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded));
+}
+
+static dbus_bool_t
+_dbus_read_uuid_file_without_creating (const DBusString *filename,
+ DBusGUID *uuid,
+ DBusError *error)
+{
+ DBusString contents;
+ DBusString decoded;
+ int end;
+
+ _dbus_string_init (&contents);
+ _dbus_string_init (&decoded);
+
+ if (!_dbus_file_get_contents (&contents, filename, error))
+ goto error;
+
+ _dbus_string_chop_white (&contents);
+
+ if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
+ {
+ dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
+ "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
+ _dbus_string_get_const_data (filename),
+ DBUS_UUID_LENGTH_HEX,
+ _dbus_string_get_length (&contents));
+ goto error;
+ }
+
+ if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
+ {
+ _DBUS_SET_OOM (error);
+ goto error;
+ }
+
+ if (end == 0)
+ {
+ dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
+ "UUID file '%s' contains invalid hex data",
+ _dbus_string_get_const_data (filename));
+ goto error;
+ }
+
+ if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
+ {
+ dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
+ "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
+ _dbus_string_get_const_data (filename),
+ _dbus_string_get_length (&decoded),
+ DBUS_UUID_LENGTH_BYTES);
+ goto error;
+ }
+
+ _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
+
+ _dbus_string_free (&decoded);
+ _dbus_string_free (&contents);
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ return TRUE;
+
+ error:
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ _dbus_string_free (&contents);
+ _dbus_string_free (&decoded);
+ return FALSE;
+}
+
+static dbus_bool_t
+_dbus_create_uuid_file_exclusively (const DBusString *filename,
+ DBusGUID *uuid,
+ DBusError *error)
+{
+ DBusString encoded;
+
+ _dbus_string_init (&encoded);
+
+ _dbus_generate_uuid (uuid);
+
+ if (!_dbus_uuid_encode (uuid, &encoded))
+ {
+ _DBUS_SET_OOM (error);
+ goto error;
+ }
+
+ /* FIXME this is racy; we need a save_file_exclusively
+ * function. But in practice this should be fine for now.
+ *
+ * - first be sure we can create the file and it
+ * doesn't exist by creating it empty with O_EXCL
+ * - then create it by creating a temporary file and
+ * overwriting atomically with rename()
+ */
+ if (!_dbus_create_file_exclusively (filename, error))
+ goto error;
+
+ if (!_dbus_string_append_byte (&encoded, '\n'))
+ {
+ _DBUS_SET_OOM (error);
+ goto error;
+ }
+
+ if (!_dbus_string_save_to_file (&encoded, filename, error))
+ goto error;
+
+
+ _dbus_string_free (&encoded);
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ return TRUE;
+
+ error:
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ _dbus_string_free (&encoded);
+ return FALSE;
+}
+
+/**
+ * Reads (and optionally writes) a uuid to a file. Initializes the uuid
+ * unless an error is returned.
+ *
+ * @param filename the name of the file
+ * @param uuid uuid to be initialized with the loaded uuid
+ * @param create_if_not_found #TRUE to create a new uuid and save it if the file doesn't exist
+ * @param error the error return
+ * @returns #FALSE if the error is set
+ */
+dbus_bool_t
+_dbus_read_uuid_file (const DBusString *filename,
+ DBusGUID *uuid,
+ dbus_bool_t create_if_not_found,
+ DBusError *error)
+{
+ DBusError read_error;
+
+ dbus_error_init (&read_error);
+
+ if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error))
+ return TRUE;
+
+ if (!create_if_not_found)
+ {
+ dbus_move_error (&read_error, error);
+ return FALSE;
+ }
+
+ /* If the file exists and contains junk, we want to keep that error
+ * message instead of overwriting it with a "file exists" error
+ * message when we try to write
+ */
+ if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT))
+ {
+ dbus_move_error (&read_error, error);
+ return FALSE;
+ }
+ else
+ {
+ dbus_error_free (&read_error);
+ return _dbus_create_uuid_file_exclusively (filename, uuid, error);
+ }
+}
+
+_DBUS_DEFINE_GLOBAL_LOCK (machine_uuid);
+static int machine_uuid_initialized_generation = 0;
+static DBusGUID machine_uuid;
+
+/**
+ * Gets the hex-encoded UUID of the machine this function is
+ * executed on. This UUID is guaranteed to be the same for a given
+ * machine at least until it next reboots, though it also
+ * makes some effort to be the same forever, it may change if the
+ * machine is reconfigured or its hardware is modified.
+ *
+ * @param uuid_str string to append hex-encoded machine uuid to
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_get_local_machine_uuid_encoded (DBusString *uuid_str)
+{
+ dbus_bool_t ok;
+
+ _DBUS_LOCK (machine_uuid);
+ if (machine_uuid_initialized_generation != _dbus_current_generation)
+ {
+ DBusError error;
+ dbus_error_init (&error);
+ if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE,
+ &error))
+ {
+#ifndef DBUS_BUILD_TESTS
+ /* For the test suite, we may not be installed so just continue silently
+ * here. But in a production build, we want to be nice and loud about
+ * this.
+ */
+ _dbus_warn ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n",
+ error.message);
+ _dbus_warn ("See the manual page for dbus-uuidgen to correct this issue.\n");
+ _dbus_warn ("Continuing with a bogus made-up machine UUID, which may cause problems.");
+#endif
+
+ dbus_error_free (&error);
+
+ _dbus_generate_uuid (&machine_uuid);
+ }
+ }
+
+ ok = _dbus_uuid_encode (&machine_uuid, uuid_str);
+
+ _DBUS_UNLOCK (machine_uuid);
+
+ return ok;
+}
+
#ifdef DBUS_BUILD_TESTS
/**
* Returns a string describing the given name.
diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
index 520d6dfe..204ac1f9 100644
--- a/dbus/dbus-internals.h
+++ b/dbus/dbus-internals.h
@@ -157,8 +157,16 @@ extern const char _dbus_return_if_fail_warning_format[];
#define _DBUS_STRUCT_OFFSET(struct_type, member) \
((long) ((unsigned char*) &((struct_type*) 0)->member))
+#ifdef DBUS_DISABLE_CHECKS
+/* this is an assert and not an error, but in the typical --disable-checks case (you're trying
+ * to really minimize code size), disabling these assertions makes sense.
+ */
+#define _DBUS_ASSERT_ERROR_IS_SET(error)
+#define _DBUS_ASSERT_ERROR_IS_CLEAR(error)
+#else
#define _DBUS_ASSERT_ERROR_IS_SET(error) _dbus_assert ((error) == NULL || dbus_error_is_set ((error)))
#define _DBUS_ASSERT_ERROR_IS_CLEAR(error) _dbus_assert ((error) == NULL || !dbus_error_is_set ((error)))
+#endif
#define _dbus_return_if_error_is_set(error) _dbus_return_if_fail ((error) == NULL || !dbus_error_is_set ((error)))
#define _dbus_return_val_if_error_is_set(error, val) _dbus_return_val_if_fail ((error) == NULL || !dbus_error_is_set ((error)), (val))
@@ -288,7 +296,8 @@ _DBUS_DECLARE_GLOBAL_LOCK (message_cache);
_DBUS_DECLARE_GLOBAL_LOCK (shared_connections);
_DBUS_DECLARE_GLOBAL_LOCK (win_fds);
_DBUS_DECLARE_GLOBAL_LOCK (sid_atom_cache);
-#define _DBUS_N_GLOBAL_LOCKS (13)
+_DBUS_DECLARE_GLOBAL_LOCK (machine_uuid);
+#define _DBUS_N_GLOBAL_LOCKS (14)
dbus_bool_t _dbus_threads_init_debug (void);
@@ -300,6 +309,28 @@ void _dbus_set_bad_address (DBusError *error,
const char *address_problem_field,
const char *address_problem_other);
+#define DBUS_UUID_LENGTH_BYTES 16
+#define DBUS_UUID_LENGTH_HEX (DBUS_UUID_LENGTH_BYTES * 2)
+
+/**
+ * A globally unique ID ; we have one for each DBusServer, and also one for each
+ * machine with libdbus installed on it.
+ */
+union DBusGUID
+{
+ dbus_uint32_t as_uint32s[DBUS_UUID_LENGTH_BYTES / 4];
+ char as_bytes[DBUS_UUID_LENGTH_BYTES];
+};
+
+void _dbus_generate_uuid (DBusGUID *uuid);
+dbus_bool_t _dbus_uuid_encode (const DBusGUID *uuid,
+ DBusString *encoded);
+dbus_bool_t _dbus_read_uuid_file (const DBusString *filename,
+ DBusGUID *uuid,
+ dbus_bool_t create_if_not_found,
+ DBusError *error);
+
+dbus_bool_t _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str);
DBUS_END_DECLS
diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h
index 3fb5e495..4cfb6d16 100644
--- a/dbus/dbus-protocol.h
+++ b/dbus/dbus-protocol.h
@@ -242,6 +242,7 @@ extern "C" {
#define DBUS_ERROR_DISCONNECTED "org.freedesktop.DBus.Error.Disconnected"
#define DBUS_ERROR_INVALID_ARGS "org.freedesktop.DBus.Error.InvalidArgs"
#define DBUS_ERROR_FILE_NOT_FOUND "org.freedesktop.DBus.Error.FileNotFound"
+#define DBUS_ERROR_FILE_EXISTS "org.freedesktop.DBus.Error.FileExists"
#define DBUS_ERROR_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod"
#define DBUS_ERROR_TIMED_OUT "org.freedesktop.DBus.Error.TimedOut"
#define DBUS_ERROR_MATCH_RULE_NOT_FOUND "org.freedesktop.DBus.Error.MatchRuleNotFound"
@@ -253,6 +254,7 @@ extern "C" {
#define DBUS_ERROR_SPAWN_FAILED "org.freedesktop.DBus.Error.Spawn.Failed"
#define DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN "org.freedesktop.DBus.Error.UnixProcessIdUnknown"
#define DBUS_ERROR_INVALID_SIGNATURE "org.freedesktop.DBus.Error.InvalidSignature"
+#define DBUS_ERROR_INVALID_FILE_CONTENT "org.freedesktop.DBus.Error.InvalidFileContent"
#define DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"
#define DBUS_INTROSPECT_1_0_XML_NAMESPACE "http://www.freedesktop.org/standards/dbus"
diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h
index 6bbcebaf..3846c8c0 100644
--- a/dbus/dbus-server-protected.h
+++ b/dbus/dbus-server-protected.h
@@ -37,16 +37,6 @@
DBUS_BEGIN_DECLS
typedef struct DBusServerVTable DBusServerVTable;
-typedef union DBusGUID DBusGUID;
-
-/**
- * A server's globally unique ID
- */
-union DBusGUID
-{
- dbus_uint32_t as_uint32s[4];
- unsigned char as_bytes[16];
-};
/**
* Virtual table to be implemented by all server "subclasses"
diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c
index 883b361b..3b9ee341 100644
--- a/dbus/dbus-server.c
+++ b/dbus/dbus-server.c
@@ -53,24 +53,6 @@
* @{
*/
-static void
-init_guid (DBusGUID *guid)
-{
- long now;
- char *p;
- int ts_size;
-
- _dbus_get_current_time (&now, NULL);
-
- guid->as_uint32s[0] = now;
-
- ts_size = sizeof (guid->as_uint32s[0]);
- p = ((char*)guid->as_bytes) + ts_size;
-
- _dbus_generate_random_bytes_buffer (p,
- sizeof (guid->as_bytes) - ts_size);
-}
-
/* this is a little fragile since it assumes the address doesn't
* already have a guid, but it shouldn't
*/
@@ -116,8 +98,6 @@ _dbus_server_init_base (DBusServer *server,
const DBusServerVTable *vtable,
const DBusString *address)
{
- DBusString guid_raw;
-
server->vtable = vtable;
server->refcount.value = 1;
@@ -128,13 +108,9 @@ _dbus_server_init_base (DBusServer *server,
if (!_dbus_string_init (&server->guid_hex))
return FALSE;
- init_guid (&server->guid);
+ _dbus_generate_uuid (&server->guid);
- _dbus_string_init_const_len (&guid_raw, (signed char*) server->guid.as_bytes,
- sizeof (server->guid.as_bytes));
- if (!_dbus_string_hex_encode (&guid_raw, 0,
- &server->guid_hex,
- _dbus_string_get_length (&server->guid_hex)))
+ if (!_dbus_uuid_encode (&server->guid, &server->guid_hex))
goto failed;
server->address = copy_address_with_guid_appended (address,
diff --git a/dbus/dbus-string-private.h b/dbus/dbus-string-private.h
index fbdde70a..65f62794 100644
--- a/dbus/dbus-string-private.h
+++ b/dbus/dbus-string-private.h
@@ -107,6 +107,18 @@ typedef struct
#define DBUS_CONST_STRING_PREAMBLE(str) const DBusRealString *real = (DBusRealString*) str; \
DBUS_GENERIC_STRING_PREAMBLE (real)
+/**
+ * Checks for ASCII blank byte
+ * @param c the byte
+ */
+#define DBUS_IS_ASCII_BLANK(c) ((c) == ' ' || (c) == '\t')
+
+/**
+ * Checks for ASCII whitespace byte
+ * @param c the byte
+ */
+#define DBUS_IS_ASCII_WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')
+
/** @} */
DBUS_END_DECLS
diff --git a/dbus/dbus-string-util.c b/dbus/dbus-string-util.c
index ddb9d750..260ef875 100644
--- a/dbus/dbus-string-util.c
+++ b/dbus/dbus-string-util.c
@@ -111,43 +111,6 @@ _dbus_string_find_byte_backward (const DBusString *str,
return i >= 0;
}
-/**
- * Skips whitespace from start, storing the first non-whitespace in *end.
- * (whitespace is space, tab, newline, CR).
- *
- * @param str the string
- * @param start where to start
- * @param end where to store the first non-whitespace byte index
- */
-void
-_dbus_string_skip_white (const DBusString *str,
- int start,
- int *end)
-{
- int i;
- DBUS_CONST_STRING_PREAMBLE (str);
- _dbus_assert (start <= real->len);
- _dbus_assert (start >= 0);
-
- i = start;
- while (i < real->len)
- {
- if (!(real->str[i] == ' ' ||
- real->str[i] == '\n' ||
- real->str[i] == '\r' ||
- real->str[i] == '\t'))
- break;
-
- ++i;
- }
-
- _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
- real->str[i] == '\t'));
-
- if (end)
- *end = i;
-}
-
/** @} */
#ifdef DBUS_BUILD_TESTS
diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c
index e35b9e1a..86cb986f 100644
--- a/dbus/dbus-string.c
+++ b/dbus/dbus-string.c
@@ -1924,20 +1924,84 @@ _dbus_string_skip_blank (const DBusString *str,
i = start;
while (i < real->len)
{
- if (!(real->str[i] == ' ' ||
- real->str[i] == '\t'))
+ if (!DBUS_IS_ASCII_BLANK (real->str[i]))
break;
++i;
}
- _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
- real->str[i] == '\t'));
+ _dbus_assert (i == real->len || !DBUS_IS_ASCII_WHITE (real->str[i]));
if (end)
*end = i;
}
+
+/**
+ * Skips whitespace from start, storing the first non-whitespace in *end.
+ * (whitespace is space, tab, newline, CR).
+ *
+ * @param str the string
+ * @param start where to start
+ * @param end where to store the first non-whitespace byte index
+ */
+void
+_dbus_string_skip_white (const DBusString *str,
+ int start,
+ int *end)
+{
+ int i;
+ DBUS_CONST_STRING_PREAMBLE (str);
+ _dbus_assert (start <= real->len);
+ _dbus_assert (start >= 0);
+
+ i = start;
+ while (i < real->len)
+ {
+ if (!DBUS_IS_ASCII_WHITE (real->str[i]))
+ break;
+
+ ++i;
+ }
+
+ _dbus_assert (i == real->len || !(DBUS_IS_ASCII_WHITE (real->str[i])));
+
+ if (end)
+ *end = i;
+}
+
+/**
+ * Skips whitespace from end, storing the start index of the trailing
+ * whitespace in *start. (whitespace is space, tab, newline, CR).
+ *
+ * @param str the string
+ * @param end where to start scanning backward
+ * @param start where to store the start of whitespace chars
+ */
+void
+_dbus_string_skip_white_reverse (const DBusString *str,
+ int end,
+ int *start)
+{
+ int i;
+ DBUS_CONST_STRING_PREAMBLE (str);
+ _dbus_assert (end <= real->len);
+ _dbus_assert (end >= 0);
+
+ i = end;
+ while (i > 0)
+ {
+ if (!DBUS_IS_ASCII_WHITE (real->str[i-1]))
+ break;
+ --i;
+ }
+
+ _dbus_assert (i >= 0 && (i == 0 || !(DBUS_IS_ASCII_WHITE (real->str[i-1]))));
+
+ if (start)
+ *start = i;
+}
+
/**
* Assigns a newline-terminated or \\r\\n-terminated line from the front
* of the string to the given dest string. The dest string's previous
@@ -2043,6 +2107,26 @@ _dbus_string_delete_leading_blanks (DBusString *str)
#endif
/**
+ * Deletes leading and trailing whitespace
+ *
+ * @param str the string
+ */
+void
+_dbus_string_chop_white(DBusString *str)
+{
+ int i;
+
+ _dbus_string_skip_white (str, 0, &i);
+
+ if (i > 0)
+ _dbus_string_delete (str, 0, i);
+
+ _dbus_string_skip_white_reverse (str, _dbus_string_get_length (str), &i);
+
+ _dbus_string_set_length (str, i);
+}
+
+/**
* Tests two DBusString for equality.
*
* @todo memcmp is probably faster
diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h
index 854ed941..47fd1b41 100644
--- a/dbus/dbus-string.h
+++ b/dbus/dbus-string.h
@@ -233,6 +233,9 @@ void _dbus_string_skip_blank (const DBusString *str,
void _dbus_string_skip_white (const DBusString *str,
int start,
int *end);
+void _dbus_string_skip_white_reverse (const DBusString *str,
+ int end,
+ int *start);
dbus_bool_t _dbus_string_equal (const DBusString *a,
const DBusString *b);
dbus_bool_t _dbus_string_equal_c_str (const DBusString *a,
@@ -253,6 +256,7 @@ dbus_bool_t _dbus_string_pop_line (DBusString *source,
DBusString *dest);
void _dbus_string_delete_first_word (DBusString *str);
void _dbus_string_delete_leading_blanks (DBusString *str);
+void _dbus_string_chop_white (DBusString *str);
dbus_bool_t _dbus_string_append_byte_as_hex (DBusString *str,
int byte);
dbus_bool_t _dbus_string_hex_encode (const DBusString *source,
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index c0540175..d0538010 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -2297,10 +2297,12 @@ _dbus_get_autolaunch_address (DBusString *address, DBusError *error)
pid_t pid;
int ret;
int status;
- int orig_len = _dbus_string_get_length (address);
+ int orig_len;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ orig_len = _dbus_string_get_length (address);
+
#define READ_END 0
#define WRITE_END 1
if (pipe (address_pipe) < 0)
@@ -2388,6 +2390,34 @@ _dbus_get_autolaunch_address (DBusString *address, DBusError *error)
return TRUE;
}
+/**
+ * Reads the uuid of the machine we're running on from
+ * the dbus configuration. Optionally try to create it
+ * (only root can do this usually).
+ *
+ * On UNIX, reads a file that gets created by dbus-uuidgen
+ * in a post-install script. On Windows, if there's a standard
+ * machine uuid we could just use that, but I can't find one
+ * with the right properties (the hardware profile guid can change
+ * without rebooting I believe). If there's no standard one
+ * we might want to use the registry instead of a file for
+ * this, and I'm not sure how we'd ensure the uuid gets created.
+ *
+ * @param guid to init with the machine's uuid
+ * @param create_if_not_found try to create the uuid if it doesn't exist
+ * @param error the error return
+ * @returns #FALSE if the error is set
+ */
+dbus_bool_t
+_dbus_read_local_machine_uuid (DBusGUID *machine_id,
+ dbus_bool_t create_if_not_found,
+ DBusError *error)
+{
+ DBusString filename;
+ _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE);
+ return _dbus_read_uuid_file (&filename, machine_id, create_if_not_found, error);
+}
+
/** @} end of sysdeps */
/* tests in dbus-sysdeps-util.c */
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index d09f33e6..2db45900 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -919,7 +919,7 @@ _dbus_error_from_errno (int error_number)
#endif
#ifdef EEXIST
case EEXIST:
- return DBUS_ERROR_FILE_NOT_FOUND;
+ return DBUS_ERROR_FILE_EXISTS;
#endif
#ifdef ENOENT
case ENOENT:
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index 3541a721..7db23e57 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -379,6 +379,13 @@ dbus_bool_t _dbus_parse_uid (const DBusString *uid_str,
dbus_bool_t _dbus_get_autolaunch_address (DBusString *address,
DBusError *error);
+typedef union DBusGUID DBusGUID;
+
+dbus_bool_t _dbus_read_local_machine_uuid (DBusGUID *machine_id,
+ dbus_bool_t create_if_not_found,
+ DBusError *error);
+
+
DBUS_END_DECLS
#endif /* DBUS_SYSDEPS_H */
diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
index 8c7eb5ef..c4ccd66e 100644
--- a/dbus/dbus-threads.c
+++ b/dbus/dbus-threads.c
@@ -450,7 +450,8 @@ init_locks (void)
LOCK_ADDR (shutdown_funcs),
LOCK_ADDR (system_users),
LOCK_ADDR (message_cache),
- LOCK_ADDR (shared_connections)
+ LOCK_ADDR (shared_connections),
+ LOCK_ADDR (machine_uuid)
#undef LOCK_ADDR
};
diff --git a/dbus/dbus-uuidgen.c b/dbus/dbus-uuidgen.c
new file mode 100644
index 00000000..8da83960
--- /dev/null
+++ b/dbus/dbus-uuidgen.c
@@ -0,0 +1,123 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-uuidgen.c The guts of the dbus-uuidgen binary live in libdbus, in this file.
+ *
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include "dbus-uuidgen.h"
+#include "dbus-internals.h"
+#include "dbus-string.h"
+#include "dbus-protocol.h"
+
+#ifdef DBUS_WIN
+#error "dbus-uuidgen should not be needed on Windows"
+#endif
+
+/**
+ * @defgroup DBusInternalsUuidgen dbus-uuidgen implementation
+ * @ingroup DBusInternals
+ * @brief Functions for dbus-uuidgen binary
+ *
+ * These are not considered part of the ABI, and if you call them
+ * you will get screwed by future changes.
+ *
+ * @{
+ */
+
+static dbus_bool_t
+return_uuid (DBusGUID *uuid,
+ char **uuid_p,
+ DBusError *error)
+{
+ if (uuid_p)
+ {
+ DBusString encoded;
+ _dbus_string_init (&encoded);
+ if (!_dbus_uuid_encode (uuid, &encoded) ||
+ !_dbus_string_steal_data (&encoded, uuid_p))
+ {
+ _DBUS_SET_OOM (error);
+ _dbus_string_free (&encoded);
+ return FALSE;
+ }
+ _dbus_string_free (&encoded);
+ }
+ return TRUE;
+}
+
+/**
+ * For use by the dbus-uuidgen binary ONLY, do not call this.
+ * We can and will change this function without modifying
+ * the libdbus soname.
+ *
+ * @param filename the file or #NULL for the machine ID file
+ * @param uuid_p out param to return the uuid
+ * @param create_if_not_found whether to create it if not already there
+ * @param error error return
+ * @param returns #FALSE if error is set
+ */
+dbus_bool_t
+dbus_internal_do_not_use_get_uuid (const char *filename,
+ char **uuid_p,
+ dbus_bool_t create_if_not_found,
+ DBusError *error)
+{
+ DBusGUID uuid;
+
+ if (filename)
+ {
+ DBusString filename_str;
+ _dbus_string_init_const (&filename_str, filename);
+ if (!_dbus_read_uuid_file (&filename_str, &uuid, create_if_not_found, error))
+ goto error;
+ }
+ else
+ {
+ if (!_dbus_read_local_machine_uuid (&uuid, create_if_not_found, error))
+ goto error;
+ }
+
+ if (!return_uuid(&uuid, uuid_p, error))
+ goto error;
+
+ return TRUE;
+
+ error:
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ return FALSE;
+}
+
+/**
+ * For use by the dbus-uuidgen binary ONLY, do not call this.
+ * We can and will change this function without modifying
+ * the libdbus soname.
+ *
+ * @param uuid_p out param to return the uuid
+ * @param returns #FALSE if no memory
+ */
+dbus_bool_t
+dbus_internal_do_not_use_create_uuid (char **uuid_p)
+{
+ DBusGUID uuid;
+
+ _dbus_generate_uuid (&uuid);
+ return return_uuid (&uuid, uuid_p, NULL);
+}
+
+/** @} */
diff --git a/dbus/dbus-uuidgen.h b/dbus/dbus-uuidgen.h
new file mode 100644
index 00000000..2b5b28fe
--- /dev/null
+++ b/dbus/dbus-uuidgen.h
@@ -0,0 +1,47 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-uuidgen.h The guts of the dbus-uuidgen binary live in libdbus, in this file.
+ *
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifdef DBUS_INSIDE_DBUS_H
+#error "You can't include dbus-uuidgen.h in the public header dbus.h"
+#endif
+
+#ifndef DBUS_UUIDGEN_H
+#define DBUS_UUIDGEN_H
+
+#include <dbus/dbus-types.h>
+#include <dbus/dbus-errors.h>
+
+DBUS_BEGIN_DECLS
+
+dbus_bool_t dbus_internal_do_not_use_get_uuid (const char *filename,
+ char **uuid_p,
+ dbus_bool_t create_if_not_found,
+ DBusError *error);
+dbus_bool_t dbus_internal_do_not_use_ensure_uuid (const char *filename,
+ char **uuid_p,
+ DBusError *error);
+dbus_bool_t dbus_internal_do_not_use_create_uuid (char **uuid_p);
+
+
+DBUS_END_DECLS
+
+#endif /* DBUS_UUIDGEN_H */
diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml
index d8e9911f..41d3fb9b 100644
--- a/doc/dbus-specification.xml
+++ b/doc/dbus-specification.xml
@@ -2290,9 +2290,10 @@
<title><literal>org.freedesktop.DBus.Peer</literal></title>
<para>
The <literal>org.freedesktop.DBus.Peer</literal> interface
- has one method:
+ has two methods:
<programlisting>
org.freedesktop.DBus.Peer.Ping ()
+ org.freedesktop.DBus.Peer.GetMachineId (out STRING machine_uuid)
</programlisting>
</para>
<para>
@@ -2300,9 +2301,33 @@
<literal>org.freedesktop.DBus.Peer.Ping</literal>, an application should do
nothing other than reply with a <literal>METHOD_RETURN</literal> as
usual. It does not matter which object path a ping is sent to. The
- reference implementation should simply handle this method on behalf of
- all objects, though it doesn't yet. (The point is, you're really pinging
- the peer process, not a specific object.)
+ reference implementation handles this method automatically.
+ </para>
+ <para>
+ On receipt of the <literal>METHOD_CALL</literal> message
+ <literal>org.freedesktop.DBus.Peer.GetMachineId</literal>, an application should
+ reply with a <literal>METHOD_RETURN</literal> containing a hex-encoded
+ UUID representing the identity of the machine the process is running on.
+ This UUID must be the same for all processes on a single system at least
+ until that system next reboots. It should be the same across reboots
+ if possible, but may change due to reconfiguration or hardware changes.
+ It does not matter which object path a GetMachineId is sent to. The
+ reference implementation handles this method automatically.
+ </para>
+ <para>
+ The UUID must contain 128 bits of data and be hex-encoded (meaning, the hex
+ string contains 32 ASCII characters). The hex-encoded string may not contain
+ hyphens or other non-hex-digit characters, and it must be exactly 32 characters long.
+ To generate a UUID, the recommended algorithm is to put the current time in seconds
+ since the UNIX epoch in the last 32 bits of the UUID, and to put randomly-generated bits
+ in the first 96 bits of the UUID.
+ </para>
+ <para>
+ The UUID is intended to be per-instance-of-the-operating-system, so may represent
+ a virtual machine running on a hypervisor, rather than a physical machine.
+ Basically if two processes see the same UUID, they should also see the same
+ shared memory, UNIX domain sockets, process IDs, and other features that require
+ a running OS kernel in common between the processes.
</para>
</sect2>
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 05c3618e..a3d786c4 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,6 +1,6 @@
INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_X_CFLAGS) -DDBUS_LOCALEDIR=\"@EXPANDED_DATADIR@/locale\" -DDBUS_COMPILATION -DDBUS_DAEMONDIR=\"@DBUS_DAEMONDIR@\"
-bin_PROGRAMS=dbus-send dbus-monitor dbus-launch dbus-cleanup-sockets
+bin_PROGRAMS=dbus-send dbus-monitor dbus-launch dbus-cleanup-sockets dbus-uuidgen
dbus_send_SOURCES= \
dbus-print-message.c \
@@ -19,11 +19,15 @@ dbus_launch_SOURCES= \
dbus_cleanup_sockets_SOURCES= \
dbus-cleanup-sockets.c
+dbus_uuidgen_SOURCES= \
+ dbus-uuidgen.c
+
dbus_send_LDADD= $(top_builddir)/dbus/libdbus-1.la
dbus_monitor_LDADD= $(top_builddir)/dbus/libdbus-1.la
+dbus_uuidgen_LDADD= $(top_builddir)/dbus/libdbus-1.la
dbus_launch_LDADD= $(DBUS_X_LIBS)
-man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1
+man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1 dbus-uuidgen.1
EXTRA_DIST = $(man_MANS) run-with-tmp-session-bus.sh
CLEANFILES = \
run-with-tmp-session-bus.conf
diff --git a/tools/dbus-cleanup-sockets.1 b/tools/dbus-cleanup-sockets.1
index e093ab0f..ca669f49 100644
--- a/tools/dbus-cleanup-sockets.1
+++ b/tools/dbus-cleanup-sockets.1
@@ -11,8 +11,8 @@ dbus-cleanup-sockets \- clean up leftover sockets in a directory
.SH DESCRIPTION
-The \fIdbus-cleanup-sockets\fP command cleans up sockets used for
-D-Bus connections. See http://www.freedesktop.org/software/dbus/ for
+The \fIdbus-cleanup-sockets\fP command cleans up unused D-Bus
+connection sockets. See http://www.freedesktop.org/software/dbus/ for
more information about the big picture.
.PP
@@ -21,6 +21,19 @@ in the standard default socket directory for the
per-user-login-session message bus; this is usually /tmp.
Optionally, you can pass a different directory on the command line.
+.PP
+On Linux, this program is essentially useless, because D-Bus defaults
+to using "abstract sockets" that exist only in memory and don't have a
+corresponding file in /tmp.
+
+.PP
+On most other flavors of UNIX, it's possible for the socket files to
+leak when programs using D-Bus exit abnormally or without closing
+their D-Bus connections. Thus, it might be interesting to run
+dbus-cleanup-sockets in a cron job to mop up any leaked sockets.
+Or you can just ignore the leaked sockets, they aren't really hurting
+anything, other than cluttering the output of "ls /tmp"
+
.SH AUTHOR
dbus-cleanup-sockets was adapted by Havoc Pennington from
linc-cleanup-sockets written by Michael Meeks.
diff --git a/tools/dbus-launch-x11.c b/tools/dbus-launch-x11.c
index ac356219..67aef04d 100644
--- a/tools/dbus-launch-x11.c
+++ b/tools/dbus-launch-x11.c
@@ -33,7 +33,7 @@
#include <X11/Xlib.h>
#include <X11/Xatom.h>
-Display *xdisplay;
+Display *xdisplay = NULL;
static Atom selection_atom;
static Atom address_atom;
static Atom pid_atom;
diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c
index fb993e4e..1589c168 100644
--- a/tools/dbus-launch.c
+++ b/tools/dbus-launch.c
@@ -799,7 +799,7 @@ main (int argc, char **argv)
fprintf (stderr,
"Failed to execute message bus daemon %s: %s. Will try again without full path.\n",
DBUS_DAEMONDIR"/dbus-daemon", strerror (errno));
-
+
/*
* If it failed, try running without full PATH. Note this is needed
* because the build process builds the run-with-tmp-session-bus.conf
@@ -902,33 +902,36 @@ main (int argc, char **argv)
close (bus_pid_to_launcher_pipe[READ_END]);
#ifdef DBUS_BUILD_X11
- ret2 = x11_save_address (bus_address, bus_pid, &wid);
- if (ret2 == 0)
- {
- /* another window got added. Return its address */
- char *address;
- pid_t pid;
- long wid;
-
- if (x11_get_address (&address, &pid, &wid) && address != NULL)
- {
- verbose ("dbus-daemon is already running. Returning existing parameters.\n");
- print_variables (address, pid, wid, c_shell_syntax,
- bourne_shell_syntax, binary_syntax);
- free (address);
-
- bus_pid_to_kill = bus_pid;
- kill_bus_and_exit (0);
- }
-
- /* if failed, fall through */
- }
- if (ret2 <= 0)
- {
- fprintf (stderr, "Error saving bus information.\n");
- bus_pid_to_kill = bus_pid;
- kill_bus_and_exit (1);
- }
+ if (xdisplay != NULL)
+ {
+ ret2 = x11_save_address (bus_address, bus_pid, &wid);
+ if (ret2 == 0)
+ {
+ /* another window got added. Return its address */
+ char *address;
+ pid_t pid;
+ long wid;
+
+ if (x11_get_address (&address, &pid, &wid) && address != NULL)
+ {
+ verbose ("dbus-daemon is already running. Returning existing parameters.\n");
+ print_variables (address, pid, wid, c_shell_syntax,
+ bourne_shell_syntax, binary_syntax);
+ free (address);
+
+ bus_pid_to_kill = bus_pid;
+ kill_bus_and_exit (0);
+ }
+
+ /* if failed, fall through */
+ }
+ if (ret2 <= 0)
+ {
+ fprintf (stderr, "Error saving bus information.\n");
+ bus_pid_to_kill = bus_pid;
+ kill_bus_and_exit (1);
+ }
+ }
#endif
/* Forward the pid to the babysitter */
diff --git a/tools/dbus-uuidgen.1 b/tools/dbus-uuidgen.1
new file mode 100644
index 00000000..7b533723
--- /dev/null
+++ b/tools/dbus-uuidgen.1
@@ -0,0 +1,91 @@
+.\"
+.\" dbus-uuidgen manual page.
+.\" Copyright (C) 2006 Red Hat, Inc.
+.\"
+.TH dbus-uuidgen 1
+.SH NAME
+dbus-uuidgen \- Utility to generate UUIDs
+.SH SYNOPSIS
+.PP
+.B dbus-uuidgen [\-\-version] [\-\-ensure[=FILENAME]] [\-\-get[=FILENAME]]
+
+.SH DESCRIPTION
+
+The \fIdbus-uuidgen\fP command generates or reads a universally unique ID.
+
+.PP
+See http://www.freedesktop.org/software/dbus/ for more information
+about D-Bus.
+
+.PP
+The primary usage of \fIdbus-uuidgen\fP is to run in the post-install
+script of a D-Bus package like this:
+.nf
+ dbus-uuidgen --ensure
+.fi
+
+.PP
+This will ensure that /etc/dbus-1/machine-id exists and has the uuid in it.
+It won't overwrite an existing uuid, since this id should remain fixed
+for a single machine until the next reboot at least.
+
+.PP
+The important properties of the machine UUID are that 1) it remains
+unchanged until the next reboot and 2) it is different for any two
+running instances of the OS kernel. That is, if two processes see the
+same UUID, they should also see the same shared memory, UNIX domain
+sockets, local X displays, localhost.localdomain resolution, process
+IDs, and so forth.
+
+.PP
+If you run \fIdbus-uuidgen\fP with no options it just prints a new uuid made
+up out of thin air. This is similar to the regular "uuidgen" command.
+
+.PP
+If you run it with --get, it prints the machine uuid by default, or
+the uuid in the specified file if you specify a file.
+
+.PP
+The D-Bus UUID has no relationship to RFC 4122 and does not generate
+UUIDs compatible with that spec.
+
+.PP
+If you try to change an existing /etc/dbus-1/machine-id on a running
+system, it will probably result in bad things happening. Don't try
+to change this file. Also, don't make it the same on two different
+systems; it needs to be different anytime there are two different
+kernels running.
+
+.PP
+If you need to share /etc between two different kernels, a possible solution
+is to symlink the machine ID to /var, and run "dbus-uuidgen
+--ensure=/var/whatever" from an early boot script or the system
+message bus boot script.
+
+.SH OPTIONS
+The following options are supported:
+.TP
+.I "--get[=FILENAME]"
+If a filename is not given, defaults to sysconfdir/dbus-1/machine-id
+(sysconfdir is usually /etc). If this file exists and is valid, the
+uuid in the file is printed on stdout. Otherwise, the command exits
+with a nonzero status.
+
+.TP
+.I "--ensure[=FILENAME]"
+If a filename is not given, defaults to sysconfdir/dbus-1/machine-id
+(sysconfdir is usually /etc). If this file exists then it will be
+validated, and a failure code returned if it contains the wrong thing.
+If the file does not exist, it will be created with a new uuid in it.
+On success, prints no output.
+
+.TP
+.I "--version"
+Print the version of dbus-uuidgen
+
+.SH AUTHOR
+See http://www.freedesktop.org/software/dbus/doc/AUTHORS
+
+.SH BUGS
+Please send bug reports to the D-Bus mailing list or bug tracker,
+see http://www.freedesktop.org/software/dbus/
diff --git a/tools/dbus-uuidgen.c b/tools/dbus-uuidgen.c
new file mode 100644
index 00000000..569bdb07
--- /dev/null
+++ b/tools/dbus-uuidgen.c
@@ -0,0 +1,161 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-uuidgen.c Utility program to create UUIDs
+ *
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dbus/dbus-uuidgen.h>
+#include <dbus/dbus.h>
+
+static void
+usage (char *name, int ecode)
+{
+ if (name == NULL)
+ name = "dbus-uuidgen";
+
+ fprintf (stderr, "Usage: %s [--ensure[=FILENAME]] [--get[=FILENAME]]\n", name);
+ exit (ecode);
+}
+
+static void
+version (void)
+{
+ printf ("D-Bus UUID Generator %s\n"
+ "Copyright (C) 2006 Red Hat, Inc.\n"
+ "This is free software; see the source for copying conditions.\n"
+ "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
+ VERSION);
+ exit (0);
+}
+
+static dbus_bool_t
+get_arg (const char *arg,
+ const char *option,
+ const char **value_p)
+{
+ const char *fn;
+
+ if (strlen(arg) < strlen(option))
+ return FALSE;
+
+ fn = arg + strlen(option);
+
+ if (!(*fn == '=' || *fn == ' ' || *fn == '\0'))
+ {
+ usage (NULL, 1);
+ }
+
+ if (*fn == '=')
+ ++fn;
+
+ while (*fn == ' ' && *fn != '\0')
+ ++fn;
+
+ if (*fn != '\0')
+ {
+ *value_p = fn;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int i;
+ const char *filename;
+ dbus_bool_t ensure_uuid;
+ dbus_bool_t get_uuid;
+ DBusError error;
+
+ ensure_uuid = FALSE;
+ get_uuid = FALSE;
+
+ filename = NULL;
+
+ for (i = 1; i < argc; i++)
+ {
+ char *arg = argv[i];
+
+ if (strncmp (arg, "--ensure", strlen("--ensure")) == 0)
+ {
+ get_arg (arg, "--ensure", &filename);
+ ensure_uuid = TRUE;
+ }
+ else if (strncmp (arg, "--get", strlen("--get")) == 0)
+ {
+ get_arg (arg, "--get", &filename);
+ get_uuid = TRUE;
+ }
+ else if (strcmp (arg, "--help") == 0)
+ usage (argv[0], 0);
+ else if (strcmp (arg, "--version") == 0)
+ version ();
+ else
+ usage (argv[0], 1);
+ }
+
+ if (get_uuid && ensure_uuid)
+ {
+ fprintf (stderr, "Can't specify both --get and --ensure\n");
+ exit (1);
+ }
+
+ dbus_error_init (&error);
+
+ if (get_uuid || ensure_uuid)
+ {
+ char *uuid;
+ if (dbus_internal_do_not_use_get_uuid (filename, &uuid, ensure_uuid, &error))
+ {
+ if (get_uuid) /* print nothing on --ensure */
+ printf ("%s\n", uuid);
+ dbus_free (uuid);
+ }
+ }
+ else
+ {
+ char *uuid;
+ if (dbus_internal_do_not_use_create_uuid (&uuid))
+ {
+ printf ("%s\n", uuid);
+ dbus_free (uuid);
+ }
+ else
+ {
+ dbus_set_error (&error, DBUS_ERROR_NO_MEMORY, "No memory");
+ }
+ }
+
+ if (dbus_error_is_set (&error))
+ {
+ fprintf (stderr, "%s\n", error.message);
+ dbus_error_free (&error);
+ exit (1);
+ }
+ else
+ {
+ exit (0);
+ }
+}
diff --git a/tools/run-with-tmp-session-bus.sh b/tools/run-with-tmp-session-bus.sh
index 880924b7..b72a56a5 100755
--- a/tools/run-with-tmp-session-bus.sh
+++ b/tools/run-with-tmp-session-bus.sh
@@ -34,7 +34,11 @@ cat $DBUS_TOP_BUILDDIR/bus/session.conf | \
echo "Created configuration file $CONFIG_FILE" >&2
-export PATH=$DBUS_TOP_BUILDDIR/bus:$PATH
+if ! test -e "$DBUS_TOP_BUILDDIR"/bus/dbus-daemon ; then
+ die "$DBUS_TOP_BUILDDIR/bus/dbus-daemon does not exist"
+fi
+
+export PATH="$DBUS_TOP_BUILDDIR"/bus:$PATH
## the libtool script found by the path search should already do this, but
export LD_LIBRARY_PATH=$DBUS_TOP_BUILDDIR/dbus/.libs:$LD_LIBRARY_PATH
@@ -46,7 +50,7 @@ echo "Running $DBUS_TOP_BUILDDIR/tools/dbus-launch --sh-syntax --config-file=$CO
eval `$DBUS_TOP_BUILDDIR/tools/dbus-launch --sh-syntax --config-file=$CONFIG_FILE`
if test -z "$DBUS_SESSION_BUS_PID" ; then
- die "Failed to launch message bus for introspection generation to run"
+ die "Failed to launch message bus for test script to run"
fi
echo "Started bus pid $DBUS_SESSION_BUS_PID at $DBUS_SESSION_BUS_ADDRESS" >&2