Commit e45e4382 authored by Havoc Pennington's avatar Havoc Pennington

2003-04-06 Havoc Pennington <hp@pobox.com>

	* bus/bus.c (bus_context_new): fix wrong handling of
	server_data_slot_unref() in the error case.

	* dbus/dbus-internals.h (_dbus_assert): change so it passes
	"(condition) != 0" to _dbus_real_assert so that
	"_dbus_assert (pointer)" doesn't cause a warning

	* bus/main.c (main): accept --print-address option to print out
	the message bus address

	* dbus/dbus-sysdeps.c (_dbus_generate_random_ascii): export this

	* dbus/dbus-transport.c (_dbus_transport_open): special error for
	"tmpdir" option to unix: address on client side

	* dbus/dbus-server.c (dbus_server_listen): handle "tmpdir" option
	to unix: address

	* configure.in (TEST_SOCKET_DIR): locate a temporary directory
	we can use to create sockets in the test suite.

	* bus/main.c (signal_handler): on SIGTERM, exit the daemon
	cleanly. To be used for testing.

	* dbus/dbus-spawn.c (babysit): use _dbus_set_signal_handler()

	* dbus/dbus-sysdeps.c (_dbus_set_signal_handler): new

	* dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new):
	handle trying to call this when there's no servers active
parent 2618e1a9
2003-04-06 Havoc Pennington <hp@pobox.com>
* bus/bus.c (bus_context_new): fix wrong handling of
server_data_slot_unref() in the error case.
* dbus/dbus-internals.h (_dbus_assert): change so it passes
"(condition) != 0" to _dbus_real_assert so that
"_dbus_assert (pointer)" doesn't cause a warning
* bus/main.c (main): accept --print-address option to print out
the message bus address
* dbus/dbus-sysdeps.c (_dbus_generate_random_ascii): export this
* dbus/dbus-transport.c (_dbus_transport_open): special error for
"tmpdir" option to unix: address on client side
* dbus/dbus-server.c (dbus_server_listen): handle "tmpdir" option
to unix: address
* configure.in (TEST_SOCKET_DIR): locate a temporary directory
we can use to create sockets in the test suite.
* bus/main.c (signal_handler): on SIGTERM, exit the daemon
cleanly. To be used for testing.
* dbus/dbus-spawn.c (babysit): use _dbus_set_signal_handler()
* dbus/dbus-sysdeps.c (_dbus_set_signal_handler): new
* dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new):
handle trying to call this when there's no servers active
2003-04-05 Havoc Pennington <hp@pobox.com>
* NEWS: update
......
......@@ -107,7 +107,10 @@ server_get_context (DBusServer *server)
bd = BUS_SERVER_DATA (server);
if (bd == NULL)
return NULL;
{
server_data_slot_unref ();
return NULL;
}
context = bd->context;
......@@ -314,7 +317,7 @@ bus_context_new (const DBusString *config_file,
BUS_SET_OOM (error);
return NULL;
}
if (!server_data_slot_ref ())
{
BUS_SET_OOM (error);
......@@ -339,6 +342,12 @@ bus_context_new (const DBusString *config_file,
context->refcount = 1;
/* we need another ref of the server data slot for the context
* to own
*/
if (!server_data_slot_ref ())
_dbus_assert_not_reached ("second ref of server data slot failed");
#ifdef DBUS_BUILD_TESTS
context->activation_timeout = 6000; /* 6 seconds */
#else
......@@ -542,6 +551,7 @@ bus_context_new (const DBusString *config_file,
bus_config_parser_unref (parser);
_dbus_string_free (&full_address);
dbus_free_string_array (auth_mechanisms);
server_data_slot_unref ();
return context;
......@@ -678,6 +688,12 @@ bus_context_get_type (BusContext *context)
return context->type;
}
const char*
bus_context_get_address (BusContext *context)
{
return context->address;
}
BusRegistry*
bus_context_get_registry (BusContext *context)
{
......
......@@ -46,6 +46,7 @@ void bus_context_shutdown (BusContext *context)
void bus_context_ref (BusContext *context);
void bus_context_unref (BusContext *context);
const char* bus_context_get_type (BusContext *context);
const char* bus_context_get_address (BusContext *context);
BusRegistry* bus_context_get_registry (BusContext *context);
BusConnections* bus_context_get_connections (BusContext *context);
BusActivation* bus_context_get_activation (BusContext *context);
......
......@@ -26,11 +26,29 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
static BusContext *context;
static dbus_bool_t got_sighup = FALSE;
static void
signal_handler (int sig)
{
switch (sig)
{
case SIGHUP:
got_sighup = TRUE;
case SIGTERM:
bus_loop_quit (bus_context_get_loop (context));
break;
}
}
static void
usage (void)
{
fprintf (stderr, "dbus-daemon-1 [--session] [--system] [--config-file=FILE] [--version]\n");
fprintf (stderr, "dbus-daemon-1 [--version] [--session] [--system] [--config-file=FILE] [--print-address[=descriptor]]\n");
exit (1);
}
......@@ -57,17 +75,36 @@ check_two_config_files (const DBusString *config_file,
}
}
static void
check_two_addr_descriptors (const DBusString *addr_fd,
const char *extra_arg)
{
if (_dbus_string_get_length (addr_fd) > 0)
{
fprintf (stderr, "--%s specified but printing address to %s already requested\n",
extra_arg, _dbus_string_get_const_data (addr_fd));
exit (1);
}
}
int
main (int argc, char **argv)
{
BusContext *context;
DBusError error;
DBusString config_file;
DBusString addr_fd;
const char *prev_arg;
int print_addr_fd;
int i;
dbus_bool_t print_address;
if (!_dbus_string_init (&config_file))
return 1;
if (!_dbus_string_init (&addr_fd))
return 1;
print_address = FALSE;
prev_arg = NULL;
i = 1;
......@@ -117,6 +154,32 @@ main (int argc, char **argv)
}
else if (strcmp (arg, "--config-file") == 0)
; /* wait for next arg */
else if (strstr (arg, "--print-address=") == arg)
{
const char *desc;
check_two_addr_descriptors (&addr_fd, "print-address");
desc = strchr (arg, '=');
++desc;
if (!_dbus_string_append (&addr_fd, desc))
exit (1);
print_address = TRUE;
}
else if (prev_arg &&
strcmp (prev_arg, "--print-address") == 0)
{
check_two_addr_descriptors (&addr_fd, "print-address");
if (!_dbus_string_append (&addr_fd, arg))
exit (1);
print_address = TRUE;
}
else if (strcmp (arg, "--print-address") == 0)
print_address = TRUE; /* and we'll get the next arg if appropriate */
else
usage ();
......@@ -130,6 +193,27 @@ main (int argc, char **argv)
fprintf (stderr, "No configuration file specified.\n");
usage ();
}
print_addr_fd = -1;
if (print_address)
{
print_addr_fd = 1; /* stdout */
if (_dbus_string_get_length (&addr_fd) > 0)
{
long val;
int end;
if (!_dbus_string_parse_int (&addr_fd, 0, &val, &end) ||
end != _dbus_string_get_length (&addr_fd) ||
val < 0 || val > _DBUS_INT_MAX)
{
fprintf (stderr, "Invalid file descriptor: \"%s\"\n",
_dbus_string_get_const_data (&addr_fd));
exit (1);
}
print_addr_fd = val;
}
}
dbus_error_init (&error);
context = bus_context_new (&config_file, &error);
......@@ -139,14 +223,56 @@ main (int argc, char **argv)
_dbus_warn ("Failed to start message bus: %s\n",
error.message);
dbus_error_free (&error);
return 1;
exit (1);
}
/* Note that we don't know whether the print_addr_fd is
* one of the sockets we're using to listen on, or some
* other random thing. But I think the answer is "don't do
* that then"
*/
if (print_addr_fd >= 0)
{
DBusString addr;
const char *a = bus_context_get_address (context);
int bytes;
_dbus_assert (a != NULL);
if (!_dbus_string_init (&addr) ||
!_dbus_string_append (&addr, a) ||
!_dbus_string_append (&addr, "\n"))
exit (1);
bytes = _dbus_string_get_length (&addr);
if (_dbus_write (print_addr_fd, &addr, 0, bytes) != bytes)
{
_dbus_warn ("Failed to print message bus address: %s\n",
_dbus_strerror (errno));
exit (1);
}
if (print_addr_fd > 2)
_dbus_close (print_addr_fd, NULL);
_dbus_string_free (&addr);
}
/* FIXME we have to handle this properly below _dbus_set_signal_handler (SIGHUP, signal_handler); */
_dbus_set_signal_handler (SIGTERM, signal_handler);
_dbus_verbose ("We are on D-Bus...\n");
bus_loop_run (bus_context_get_loop (context));
bus_context_shutdown (context);
bus_context_unref (context);
/* If we exited on TERM we just exit, if we exited on
* HUP we restart the daemon.
*/
if (got_sighup)
{
/* FIXME execv (argv) basically */
}
return 0;
}
......@@ -8,19 +8,7 @@
<!-- Our well-known bus type, don't change this -->
<type>session</type>
<!-- FIXME - this is fairly complicated to fix.
Propose the following:
- add "unix:tmpdir=/tmp" which means unix domain transport
creates a socket with a random secure name
- add dbus_server_get_address() that gets the actual
server address
- add command line option or env variable to the daemon
causing it to print its list of addresses to a given
file descriptor
- session manager or whatever launches the session bus
reads the address from there and sets the env variable
-->
<listen>unix:path=/tmp/foobar</listen>
<listen>unix:tmpdir=@DBUS_SESSION_SOCKET_DIR@</listen>
<policy context="default">
<!-- Allow everything -->
......
......@@ -31,8 +31,10 @@ AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode]
AC_ARG_ENABLE(asserts, [ --enable-asserts include assertion checks],enable_asserts=$enableval,enable_asserts=yes)
AC_ARG_ENABLE(gcov, [ --enable-gcov compile with coverage profiling instrumentation (gcc only)],enable_gcov=$enableval,enable_gcov=no)
AC_ARG_WITH(xml, [ --with-xml=[libxml/expat] XML library to use])
AC_ARG_WITH(init-scripts, [ --with-init-scripts=[redhat] Style of init scripts to install])
AC_ARG_WITH(xml, [ --with-xml=[libxml/expat] XML library to use])
AC_ARG_WITH(init-scripts, [ --with-init-scripts=[redhat] Style of init scripts to install])
AC_ARG_WITH(session-socket-dir, [ --with-session-socket-dir=[dirname] Where to put sockets for the per-login-session message bus])
AC_ARG_WITH(test-socket-dir, [ --with-test-socket-dir=[dirname] Where to put sockets for make check])
dnl DBUS_BUILD_TESTS controls unit tests built in to .c files
dnl and also some stuff in the test/ subdir
......@@ -123,6 +125,9 @@ else
fi
fi
# compress spaces in cflags
CFLAGS=`echo "$CFLAGS" | sed -e 's/ +/ /g'`
if test x$enable_gcov = xyes; then
## so that config.h changes when you toggle gcov support
AC_DEFINE_UNQUOTED(DBUS_GCOV_ENABLED, 1, [Defined if gcov is enabled to force a rebuild due to config.h changing])
......@@ -160,6 +165,7 @@ AC_DEFINE_UNQUOTED(DBUS_INT64_TYPE, $dbusint64, [64-bit integer type])
## byte order
AC_C_BIGENDIAN
#### Various functions
AC_CHECK_LIB(socket,socket)
AC_CHECK_LIB(nsl,gethostbyname)
......@@ -443,6 +449,32 @@ TEST_PATH(EXIT_BINARY, test-exit)
TEST_PATH(SEGFAULT_BINARY, test-segfault)
TEST_PATH(SLEEP_FOREVER_BINARY, test-sleep-forever)
#### Find socket directories
if ! test -z "$TMPDIR" ; then
DEFAULT_SOCKET_DIR=$TMPDIR
elif ! test -z "$TEMP" ; then
DEFAULT_SOCKET_DIR=$TEMP
elif ! test -z "$TMP" ; then
DEFAULT_SOCKET_DIR=$TMP
else
DEFAULT_SOCKET_DIR=/tmp
fi
if ! test -z "$with_test_socket_dir" ; then
TEST_SOCKET_DIR="$with_test_socket_dir"
else
TEST_SOCKET_DIR=$DEFAULT_SOCKET_DIR
fi
AC_SUBST(TEST_SOCKET_DIR)
if ! test -z "$with_session_socket_dir" ; then
DBUS_SESSION_SOCKET_DIR="$with_session_socket_dir"
else
DBUS_SESSION_SOCKET_DIR=$DEFAULT_SOCKET_DIR
fi
AC_SUBST(DBUS_SESSION_SOCKET_DIR)
AC_OUTPUT([
Doxyfile
bus/system.conf
......@@ -466,21 +498,23 @@ echo "
D-BUS $VERSION
==============
prefix: ${prefix}
source code location: ${srcdir}
compiler: ${CC}
cflags: ${CFLAGS}
Maintainer mode: ${USE_MAINTAINER_MODE}
gcc coverage profiling: ${enable_gcov}
Building unit tests: ${enable_tests}
Building verbose mode: ${enable_verbose_mode}
Building assertions: ${enable_asserts}
Building Qt bindings: ${have_qt}
Building GLib bindings: ${have_glib}
Using XML parser: ${with_xml}
System bus socket: ${EXPANDED_LOCALSTATEDIR}/${DBUS_SYSTEM_SOCKET}
Init scripts style: ${with_init_scripts}
prefix: ${prefix}
source code location: ${srcdir}
compiler: ${CC}
cflags: ${CFLAGS}
Maintainer mode: ${USE_MAINTAINER_MODE}
gcc coverage profiling: ${enable_gcov}
Building unit tests: ${enable_tests}
Building verbose mode: ${enable_verbose_mode}
Building assertions: ${enable_asserts}
Building Qt bindings: ${have_qt}
Building GLib bindings: ${have_glib}
Using XML parser: ${with_xml}
Init scripts style: ${with_init_scripts}
System bus socket: ${EXPANDED_LOCALSTATEDIR}/${DBUS_SYSTEM_SOCKET}
Session bus socket dir: ${DBUS_SESSION_SOCKET_DIR}
'make check' socket dir: ${TEST_SOCKET_DIR}
"
if test x$enable_tests = xyes; then
......
......@@ -93,7 +93,7 @@ message_from_error (const char *error)
else if (strcmp (error, DBUS_ERROR_AUTH_FAILED) == 0)
return "Could not authenticate to server";
else if (strcmp (error, DBUS_ERROR_NO_SERVER) == 0)
return "No server";
return "No server available at address";
else if (strcmp (error, DBUS_ERROR_TIMEOUT) == 0)
return "Connection timed out";
else if (strcmp (error, DBUS_ERROR_NO_NETWORK) == 0)
......
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-internals.h random utility stuff (internal to D-BUS implementation)
*
* Copyright (C) 2002 Red Hat, Inc.
* Copyright (C) 2002, 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
......@@ -81,7 +81,7 @@ void _dbus_real_assert (dbus_bool_t condition,
const char *file,
int line);
#define _dbus_assert(condition) \
_dbus_real_assert ((condition), #condition, __FILE__, __LINE__)
_dbus_real_assert ((condition) != 0, #condition, __FILE__, __LINE__)
#endif /* !DBUS_DISABLE_ASSERT */
#ifdef DBUS_DISABLE_ASSERT
......
......@@ -220,13 +220,19 @@ _dbus_transport_debug_pipe_new (const char *server_name,
DBusString address;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (server_pipe_hash == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL);
return NULL;
}
server = _dbus_hash_table_lookup_string (server_pipe_hash,
server_name);
if (server == NULL ||
((DBusServerDebugPipe*)server)->disconnected)
{
dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, NULL);
dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL);
return NULL;
}
......
......@@ -305,18 +305,68 @@ dbus_server_listen (const char *address,
if (strcmp (method, "unix") == 0)
{
const char *path = dbus_address_entry_get_value (entries[i], "path");
if (path == NULL)
const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir");
if (path == NULL && tmpdir == NULL)
{
address_problem_type = "unix";
address_problem_field = "path";
address_problem_field = "path or tmpdir";
goto bad_address;
}
server = _dbus_server_new_for_domain_socket (path, error);
if (path && tmpdir)
{
address_problem_other = "cannot specify both \"path\" and \"tmpdir\" at the same time";
goto bad_address;
}
if (server)
break;
if (tmpdir != NULL)
{
DBusString full_path;
DBusString filename;
if (!_dbus_string_init (&full_path))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto out;
}
if (!_dbus_string_init (&filename))
{
_dbus_string_free (&full_path);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto out;
}
if (!_dbus_string_append (&filename,
"dbus-") ||
!_dbus_generate_random_ascii (&filename, 10) ||
!_dbus_string_append (&full_path, tmpdir) ||
!_dbus_concat_dir_and_file (&full_path, &filename))
{
_dbus_string_free (&full_path);
_dbus_string_free (&filename);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto out;
}
/* FIXME - we will unconditionally unlink() the path.
* unlink() does not follow symlinks, but would like
* independent confirmation this is safe enough. See
* also _dbus_listen_unix_socket() and comments therein.
*/
server =
_dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
error);
_dbus_string_free (&full_path);
_dbus_string_free (&filename);
}
else
{
server = _dbus_server_new_for_domain_socket (path, error);
}
}
else if (strcmp (method, "tcp") == 0)
{
......@@ -361,9 +411,6 @@ dbus_server_listen (const char *address,
}
server = _dbus_server_debug_new (name, error);
if (server)
break;
}
else if (strcmp (method, "debug-pipe") == 0)
{
......@@ -377,9 +424,6 @@ dbus_server_listen (const char *address,
}
server = _dbus_server_debug_pipe_new (name, error);
if (server)
break;
}
#endif
else
......@@ -387,7 +431,12 @@ dbus_server_listen (const char *address,
address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
goto bad_address;
}
if (server)
break;
}
out:
dbus_address_entries_free (entries);
return server;
......
......@@ -916,9 +916,7 @@ babysit_signal_handler (int signo)
static void
babysit (pid_t grandchild_pid,
int parent_pipe)
{
struct sigaction act;
sigset_t empty_mask;
{
int sigchld_pipe[2];
/* I thought SIGCHLD would just wake up the poll, but
......@@ -933,12 +931,8 @@ babysit (pid_t grandchild_pid,
}
babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
sigemptyset (&empty_mask);
act.sa_handler = babysit_signal_handler;
act.sa_mask = empty_mask;
act.sa_flags = 0;
sigaction (SIGCHLD, &act, 0);
_dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
write_pid (parent_pipe, grandchild_pid);
......
......@@ -2007,36 +2007,6 @@ _dbus_file_get_contents (DBusString *str,
}
}
static dbus_bool_t
append_unique_chars (DBusString *str)
{
static const char letters[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int i;
int len;
#define N_UNIQUE_CHARS 8
if (!_dbus_generate_random_bytes (str, N_UNIQUE_CHARS))
return FALSE;
len = _dbus_string_get_length (str);
i = len - N_UNIQUE_CHARS;
while (i < len)
{
_dbus_string_set_byte (str, i,
letters[_dbus_string_get_byte (str, i) %
(sizeof (letters) - 1)]);
++i;
}
_dbus_assert (_dbus_string_validate_ascii (str, len - N_UNIQUE_CHARS,
N_UNIQUE_CHARS));
return TRUE;
}
/**
* Writes a string out to a file. If the file exists,
* it will be atomically overwritten by the new data.
......@@ -2083,8 +2053,9 @@ _dbus_string_save_to_file (const DBusString *str,
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return FALSE;
}
if (!append_unique_chars (&tmp_filename))
#define N_TMP_FILENAME_RANDOM_BYTES 8
if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return FALSE;
......@@ -2487,13 +2458,52 @@ _dbus_directory_close (DBusDirIter *iter)
dbus_free (iter);
}
static dbus_bool_t
pseudorandom_generate_random_bytes (DBusString *str,
int n_bytes)
{
int old_len;
unsigned long tv_usec;
int i;
old_len = _dbus_string_get_length (str);
/* fall back to pseudorandom */
_dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
n_bytes);
_dbus_get_current_time (NULL, &tv_usec);
srand (tv_usec);
i = 0;
while (i < n_bytes)
{
double r;
unsigned int b;
r = rand ();
b = (r / (double) RAND_MAX) * 255.0;
if (!_dbus_string_append_byte (str, b))
goto failed;
++i;
}
return TRUE;
failed:
_dbus_string_set_length (str, old_len);
return FALSE;
}
/**
* Generates the given number of random bytes,
* using the best mechanism we can come up with.
*
* @param str the string
* @param n_bytes the number of random bytes to append to string
* @returns #TRUE on success, #FALSE if no memory or other failure
* @returns #TRUE on success, #FALSE if no memory
*/
dbus_bool_t
_dbus_generate_random_bytes (DBusString *str,
......@@ -2501,6 +2511,12 @@ _dbus_generate_random_bytes (DBusString *str,
{
int old_len;
int fd;
/* FALSE return means "no memory", if it could
* mean something else then we'd need to return
* a DBusError. So we always fall back to pseudorandom
* if the I/O fails.
*/
old_len = _dbus_string_get_length (str);
fd = -1;
......@@ -2508,52 +2524,58 @@ _dbus_generate_random_bytes (DBusString *str,
/* note, urandom on linux will fall back to pseudorandom */
fd = open ("/dev/urandom", O_RDONLY);
if (fd < 0)
return pseudorandom_generate_random_bytes (str, n_bytes);
if (_dbus_read (fd, str, n_bytes) != n_bytes)
{
unsigned long tv_usec;
int i;
close (fd);
_dbus_string_set_length (str, old_len);
return pseudorandom_generate_random_bytes (str, n_bytes);
}
/* fall back to pseudorandom */
_dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
n_bytes);
_dbus_get_current_time (NULL, &tv_usec);
srand (tv_usec);
i = 0;
while (i < n_bytes)
{
double r;
unsigned int b;
r = rand ();
b = (r / (double) RAND_MAX) * 255.0;
if (!_dbus_string_append_byte (str, b))
goto failed;
++i;
}
_dbus_verbose ("Read %d bytes from /dev/urandom\n",
n_bytes);
close (fd);
return TRUE;
}
return TRUE;