diff options
31 files changed, 1262 insertions, 133 deletions
@@ -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. @@ -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 |