Commit f6fa0104 authored by Thiago Macieira's avatar Thiago Macieira

* configure.in: add DBUS_BINDIR as a #define to C source code.

	* tools/dbus-launch.c
	* tools/dbus-launch.h
	* tools/dbus-launch-x11.c:
	* tools/dbus-launch.1: Add the --autolaunch option to
	dbus-launch, which makes it scan for an existing session
	started with --autolaunch. With that option, it also creates
	an X11 window and saves the bus address and PID to it.

	* dbus/dbus-sysdeps.h:
	* dbus/dbus-sysdeps-unix.c (_dbus_get_autolaunch_address): Add
	a function that runs "dbus-launch --autolaunch" to retrieve
	the running D-Bus session address (or start one if none was running)

	* dbus/dbus-transport.c: Add the handler for the "autolaunch:"
        address protocol, which tries to get the running session from
        dbus-launch.

	* dbus/dbus-bus.c:
	* dbus/dbus-internals.h: Make "autolaunch:" be the default
	D-Bus session bus address.

	* dbus/dbus-connection.c: Fix horrible typo in error message.
parent 5f292c61
2006-09-30 Thiago Macieira <thiago@kde.org>
* configure.in: add DBUS_BINDIR as a #define to C source code.
* tools/dbus-launch.c
* tools/dbus-launch.h
* tools/dbus-launch-x11.c:
* tools/dbus-launch.1: Add the --autolaunch option to
dbus-launch, which makes it scan for an existing session
started with --autolaunch. With that option, it also creates
an X11 window and saves the bus address and PID to it.
* dbus/dbus-sysdeps.h:
* dbus/dbus-sysdeps-unix.c (_dbus_get_autolaunch_address): Add
a function that runs "dbus-launch --autolaunch" to retrieve
the running D-Bus session address (or start one if none was running)
* dbus/dbus-transport.c: Add the handler for the "autolaunch:"
address protocol, which tries to get the running session from
dbus-launch.
* dbus/dbus-bus.c:
* dbus/dbus-internals.h: Make "autolaunch:" be the default
D-Bus session bus address.
* dbus/dbus-connection.c: Fix horrible typo in error message.
2006-09-18 John (J5) Palmieri <johnp@redhat.com>
* tools/Makefile.am: use @EXPANDED_DATADIR@ instead of @DATADIRNAME@
......
......@@ -1052,6 +1052,11 @@ fi
AC_SUBST(DBUS_DAEMONDIR)
AC_DEFINE_UNQUOTED(DBUS_DAEMONDIR,"$DBUS_DAEMONDIR", [Directory for installing the DBUS daemon])
#### Directory to install the other binaries
DBUS_BINDIR=$EXPANDED_BINDIR
AC_SUBST(DBUS_BINDIR)
AC_DEFINE_UNQUOTED(DBUS_BINDIR,"$DBUS_BINDIR", [Directory for installing the binaries])
#### Tell tests where to find certain stuff in builddir
DBUS_PWD=`pwd`
......
......@@ -175,6 +175,13 @@ init_connections_unlocked (void)
if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION],
"DBUS_SESSION_BUS_ADDRESS"))
return FALSE;
if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL)
bus_connection_addresses[DBUS_BUS_SESSION] =
_dbus_strdup (DBUS_SESSION_BUS_DEFAULT_ADDRESS);
if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL)
return FALSE;
_dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_SESSION] ?
bus_connection_addresses[DBUS_BUS_SESSION] : "none set");
}
......
......@@ -2783,7 +2783,7 @@ _dbus_connection_block_pending_call (DBusPendingCall *pending)
error_msg = generate_local_error_message (client_serial,
DBUS_ERROR_DISCONNECTED,
"Connection was dissconnected before a reply was recived");
"Connection was disconnected before a reply was received");
/* on OOM error_msg is set to NULL */
complete_pending_call_and_unlock (connection, pending, error_msg);
......
......@@ -37,6 +37,8 @@
DBUS_BEGIN_DECLS
#define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:"
void _dbus_warn (const char *format,
...) _DBUS_GNUC_PRINTF (1, 2);
......
......@@ -27,6 +27,7 @@
#include "dbus-sysdeps-unix.h"
#include "dbus-threads.h"
#include "dbus-protocol.h"
#include "dbus-transport.h"
#include "dbus-string.h"
#include <sys/types.h>
#include <stdlib.h>
......@@ -2275,6 +2276,118 @@ _dbus_get_tmpdir(void)
return tmpdir;
}
/**
* Determines the address of the session bus by querying a
* platform-specific method.
*
* If successful, returns #TRUE and appends the address to @p
* address. If a failure happens, returns #FALSE and
* sets an error in @p error.
*
* @param address a DBusString where the address can be stored
* @param error a DBusError to store the error in case of failure
* @returns #TRUE on success, #FALSE if an error happened
*/
dbus_bool_t
_dbus_get_autolaunch_address (DBusString *address, DBusError *error)
{
static char *argv[] = { DBUS_BINDIR "/dbus-launch", "--autolaunch",
"--binary-syntax", NULL };
int address_pipe[2];
pid_t pid;
int ret;
int status;
int orig_len = _dbus_string_get_length (address);
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
#define READ_END 0
#define WRITE_END 1
if (pipe (address_pipe) < 0)
{
dbus_set_error (error, _dbus_error_from_errno (errno),
"Failed to create a pipe: %s",
_dbus_strerror (errno));
_dbus_verbose ("Failed to create a pipe to call dbus-launch: %s\n",
_dbus_strerror (errno));
return FALSE;
}
pid = fork ();
if (pid < 0)
{
dbus_set_error (error, _dbus_error_from_errno (errno),
"Failed to fork(): %s",
_dbus_strerror (errno));
_dbus_verbose ("Failed to fork() to call dbus-launch: %s\n",
_dbus_strerror (errno));
return FALSE;
}
if (pid == 0)
{
/* child process */
int fd = open ("/dev/null", O_RDWR);
if (fd == -1)
/* huh?! can't open /dev/null? */
_exit (1);
/* set-up stdXXX */
close (address_pipe[READ_END]);
close (0); /* close stdin */
close (1); /* close stdout */
close (2); /* close stderr */
if (dup2 (fd, 0) == -1)
_exit (1);
if (dup2 (address_pipe[WRITE_END], 1) == -1)
_exit (1);
if (dup2 (fd, 2) == -1)
_exit (1);
close (fd);
close (address_pipe[WRITE_END]);
execv (argv[0], argv);
/* failed, try searching PATH */
argv[0] = "dbus-launch";
execvp ("dbus-launch", argv);
/* still nothing, we failed */
_exit (1);
}
/* parent process */
close (address_pipe[WRITE_END]);
ret = 0;
do
{
ret = _dbus_read (address_pipe[READ_END], address, 1024);
}
while (ret > 0);
/* reap the child process to avoid it lingering as zombie */
do
{
ret = waitpid (pid, &status, 0);
}
while (ret == -1 && errno == EINTR);
/* We succeeded if the process exited with status 0 and
anything was read */
if (!WIFEXITED (status) || WEXITSTATUS (status) != 0 ||
_dbus_string_get_length (address) == orig_len)
{
/* The process ended with error */
_dbus_string_set_length (address, orig_len);
dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
"Failed to execute dbus-launch to autolaunch D-Bus session");
return FALSE;
}
return TRUE;
}
/** @} end of sysdeps */
/* tests in dbus-sysdeps-util.c */
......@@ -376,6 +376,9 @@ dbus_bool_t _dbus_user_at_console (const char *username,
dbus_bool_t _dbus_parse_uid (const DBusString *uid_str,
dbus_uid_t *uid);
dbus_bool_t _dbus_get_autolaunch_address (DBusString *address,
DBusError *error);
DBUS_END_DECLS
#endif /* DBUS_SYSDEPS_H */
......@@ -201,13 +201,118 @@ _dbus_transport_finalize_base (DBusTransport *transport)
dbus_free (transport->expected_guid);
}
/**
* Verifies if a given D-Bus address is a valid address
* by attempting to connect to it. If it is, returns the
* opened DBusTransport object. If it isn't, returns #NULL
* and sets @p error.
*
* @param error address where an error can be returned.
* @returns a new transport, or #NULL on failure.
*/
static DBusTransport*
check_address (const char *address, DBusError *error)
{
DBusAddressEntry **entries;
DBusTransport *transport = NULL;
int len, i;
_dbus_assert (address != NULL);
_dbus_assert (*address != '\0');
if (!dbus_parse_address (address, &entries, &len, error))
return FALSE; /* not a valid address */
for (i = 0; i < len; i++)
{
transport = _dbus_transport_open (entries[i], error);
if (transport != NULL)
break;
}
dbus_address_entries_free (entries);
return transport;
}
/**
* Creates a new transport for the "autostart" method.
* This creates a client-side of a transport.
*
* @param error address where an error can be returned.
* @returns a new transport, or #NULL on failure.
*/
static DBusTransport*
_dbus_transport_new_for_autolaunch (DBusError *error)
{
DBusString address;
DBusTransport *result = NULL;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (!_dbus_string_init (&address))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
if (!_dbus_get_autolaunch_address (&address, error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto out;
}
result = check_address (_dbus_string_get_const_data (&address), error);
if (result == NULL)
_DBUS_ASSERT_ERROR_IS_SET (error);
else
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
out:
_dbus_string_free (&address);
return result;
}
static DBusTransportOpenResult
_dbus_transport_open_autolaunch (DBusAddressEntry *entry,
DBusTransport **transport_p,
DBusError *error)
{
const char *method;
method = dbus_address_entry_get_method (entry);
_dbus_assert (method != NULL);
if (strcmp (method, "autolaunch") == 0)
{
*transport_p = _dbus_transport_new_for_autolaunch (error);
if (*transport_p == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
}
else
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
return DBUS_TRANSPORT_OPEN_OK;
}
}
else
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
}
}
static const struct {
DBusTransportOpenResult (* func) (DBusAddressEntry *entry,
DBusTransport **transport_p,
DBusError *error);
} open_funcs[] = {
{ _dbus_transport_open_socket },
{ _dbus_transport_open_platform_specific }
{ _dbus_transport_open_platform_specific },
{ _dbus_transport_open_autolaunch }
#ifdef DBUS_BUILD_TESTS
, { _dbus_transport_open_debug_pipe }
#endif
......
......@@ -13,7 +13,8 @@ dbus_monitor_SOURCES= \
dbus-print-message.h
dbus_launch_SOURCES= \
dbus-launch.c
dbus-launch.c \
dbus-launch-x11.c
dbus_cleanup_sockets_SOURCES= \
dbus-cleanup-sockets.c
......
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-launch.h dbus-launch utility
*
* Copyright (C) 2006 Thiago Macieira <thiago@kde.org>
*
* 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-launch.h"
#ifdef DBUS_BUILD_X11
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
Display *xdisplay;
static Atom selection_atom;
static Atom address_atom;
static Atom pid_atom;
static int
x_io_error_handler (Display *xdisplay)
{
verbose ("X IO error\n");
kill_bus_and_exit (0);
return 0;
}
static char *
get_local_hostname (void)
{
static const int increment = 128;
static char *cache = NULL;
char *buffer = NULL;
int size = 0;
while (cache == NULL)
{
size += increment;
buffer = realloc (buffer, size);
if (buffer == NULL)
return NULL; /* out of memory */
if (gethostname (buffer, size - 1) == -1 &&
errno != ENAMETOOLONG)
return NULL;
buffer[size - 1] = '\0'; /* to make sure */
cache = buffer;
}
return cache;
}
static char *
get_session_file (void)
{
static const char prefix[] = "/.dbus-session-file_";
char *hostname;
char *display;
char *home;
char *result;
char *p;
display = xstrdup (getenv ("DISPLAY"));
if (display == NULL)
{
verbose ("X11 integration disabled because X11 is not running\n");
return NULL;
}
/* remove the screen part of the display name */
p = strrchr (display, ':');
if (p != NULL)
for ( ; *p; ++p)
if (*p == '.')
{
*p = '\0';
break;
}
/* replace the : in the display with _ */
for (p = display; *p; ++p)
if (*p == ':')
*p = '_';
hostname = get_local_hostname ();
if (hostname == NULL)
{
/* out of memory */
free (display);
return NULL;
}
home = getenv ("HOME");
if (home == NULL)
{
/* try from the user database */
struct passwd *user = getpwuid (getuid());
if (user == NULL)
{
verbose ("X11 integration disabled because the home directory"
" could not be determined\n");
free (display);
return NULL;
}
home = user->pw_dir;
}
result = malloc (strlen (home) + strlen (prefix) + strlen (hostname) +
strlen (display) + 2);
if (result == NULL)
{
/* out of memory */
free (display);
return NULL;
}
strcpy (result, home);
strcat (result, prefix);
strcat (result, hostname);
strcat (result, "_");
strcat (result, display);
free (display);
verbose ("session file: %s\n", result);
return result;
}
static Display *
open_x11 (void)
{
if (xdisplay != NULL)
return xdisplay;
xdisplay = XOpenDisplay (NULL);
if (xdisplay != NULL)
{
verbose ("Connected to X11 display '%s'\n", DisplayString (xdisplay));
XSetIOErrorHandler (x_io_error_handler);
}
return xdisplay;
}
static int
init_x_atoms (Display *display)
{
static const char selection_prefix[] = "DBUS_SESSION_SELECTION_";
static const char address_prefix[] = "DBUS_SESSION_ADDRESS";
static const char pid_prefix[] = "DBUS_SESSION_PID";
static int init = FALSE;
char *atom_name;
char *hostname;
char *user_name;
struct passwd *user;
if (init)
return TRUE;
user = getpwuid (getuid ());
if (user == NULL)
{
verbose ("Could not determine the user informations; aborting X11 integration.\n");
return FALSE;
}
user_name = xstrdup(user->pw_name);
hostname = get_local_hostname ();
if (hostname == NULL)
{
verbose ("Could not create X11 atoms; aborting X11 integration.\n");
free (user_name);
return FALSE;
}
atom_name = malloc (strlen (hostname) + strlen (user_name) + 2 +
MAX (strlen (selection_prefix),
MAX (strlen (address_prefix),
strlen (pid_prefix))));
if (atom_name == NULL)
{
verbose ("Could not create X11 atoms; aborting X11 integration.\n");
free (user_name);
return FALSE;
}
/* create the selection atom */
strcpy (atom_name, selection_prefix);
strcat (atom_name, user_name);
strcat (atom_name, "_");
strcat (atom_name, hostname);
selection_atom = XInternAtom (display, atom_name, FALSE);
/* create the address property atom */
strcpy (atom_name, address_prefix);
address_atom = XInternAtom (display, atom_name, FALSE);
/* create the PID property atom */
strcpy (atom_name, pid_prefix);
pid_atom = XInternAtom (display, atom_name, FALSE);
free (atom_name);
free (user_name);
init = TRUE;
return TRUE;
}
/*
* Gets the daemon address from the X11 display.
* Returns FALSE if there was an error. Returning
* TRUE does not mean the address exists.
*/
int
x11_get_address (char **paddress, pid_t *pid, long *wid)
{
Atom type;
Window owner;
int format;
unsigned long items;
unsigned long after;
char *data;
*paddress = NULL;
/* locate the selection owner */
owner = XGetSelectionOwner (xdisplay, selection_atom);
if (owner == None)
return TRUE; /* no owner */
if (wid != NULL)
*wid = (long) owner;
/* get the bus address */
XGetWindowProperty (xdisplay, owner, address_atom, 0, 1024, False,
XA_STRING, &type, &format, &items, &after,
(unsigned char **) &data);
if (type == None || after != 0 || data == NULL || format != 8)
return FALSE; /* error */
*paddress = xstrdup (data);
XFree (data);
/* get the PID */
if (pid != NULL)
{
*pid = 0;
XGetWindowProperty (xdisplay, owner, pid_atom, 0, sizeof pid, False,
XA_CARDINAL, &type, &format, &items, &after,
(unsigned char **) &data);
if (type != None && after == 0 && data != NULL && format == 32)
*pid = (pid_t) *(long*) data;
XFree (data);
}
return TRUE; /* success */
}
/*
* Saves the address in the X11 display. Returns 0 on success.
* If an error occurs, returns -1. If the selection already exists,
* returns 1. (i.e. another daemon is already running)
*/
static Window
set_address_in_x11(char *address, pid_t pid)
{
char *current_address;
Window wid;
/* lock the X11 display to make sure we're doing this atomically */
XGrabServer (xdisplay);
if (!x11_get_address (&current_address, NULL, NULL))
{
/* error! */
XUngrabServer (xdisplay);
return None;
}
if (current_address != NULL)
{
/* someone saved the address in the meantime */
XUngrabServer (xdisplay);
free (current_address);