summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago@kde.org>2006-09-30 19:38:34 +0000
committerThiago Macieira <thiago@kde.org>2006-09-30 19:38:34 +0000
commitf6fa010403cb2badd88ce096ae91f664418508d1 (patch)
tree67227726b518356870813b33bc346bda9be32e18
parent5f292c611fc60bf3115dcf3d1213fdedc36fc65c (diff)
* 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.
-rw-r--r--ChangeLog27
-rw-r--r--configure.in5
-rw-r--r--dbus/dbus-bus.c7
-rw-r--r--dbus/dbus-connection.c2
-rw-r--r--dbus/dbus-internals.h2
-rw-r--r--dbus/dbus-sysdeps-unix.c113
-rw-r--r--dbus/dbus-sysdeps.h3
-rw-r--r--dbus/dbus-transport.c107
-rw-r--r--tools/Makefile.am3
-rw-r--r--tools/dbus-launch-x11.c392
-rw-r--r--tools/dbus-launch.19
-rw-r--r--tools/dbus-launch.c301
-rw-r--r--tools/dbus-launch.h56
13 files changed, 900 insertions, 127 deletions
diff --git a/ChangeLog b/ChangeLog
index 49a32704..55a88c88 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+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@
diff --git a/configure.in b/configure.in
index e87fdef0..0c70bb31 100644
--- a/configure.in
+++ b/configure.in
@@ -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`
diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c
index 5f5c3395..eb6b3ab3 100644
--- a/dbus/dbus-bus.c
+++ b/dbus/dbus-bus.c
@@ -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");
}
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index 2b4dd8d8..d60816c3 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -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);
diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
index a12821db..520d6dfe 100644
--- a/dbus/dbus-internals.h
+++ b/dbus/dbus-internals.h
@@ -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);
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index 38adebb1..c0540175 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -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 */
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index c1ed533a..3541a721 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -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 */
diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
index 89d79ffe..f43dd3d2 100644
--- a/dbus/dbus-transport.c
+++ b/dbus/dbus-transport.c
@@ -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
diff --git a/tools/Makefile.am b/tools/Makefile.am
index eb19ddb7..05c3618e 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -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
diff --git a/tools/dbus-launch-x11.c b/tools/dbus-launch-x11.c
new file mode 100644
index 00000000..ac356219
--- /dev/null
+++ b/tools/dbus-launch-x11.c
@@ -0,0 +1,392 @@
+/* -*- 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);
+ return None;
+ }
+
+ /* Create our window */
+ wid = XCreateSimpleWindow (xdisplay, RootWindow (xdisplay, 0), -20, -20, 10, 10,
+ 0, WhitePixel (xdisplay, 0),
+ BlackPixel (xdisplay, 0));
+ verbose ("Created window %d\n", wid);
+
+ /* Save the property in the window */
+ XChangeProperty (xdisplay, wid, address_atom, XA_STRING, 8, PropModeReplace,
+ (unsigned char *)address, strlen (address));
+ XChangeProperty (xdisplay, wid, pid_atom, XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *)&pid, sizeof(pid) / 4);
+
+ /* Now grab the selection */
+ XSetSelectionOwner (xdisplay, selection_atom, wid, CurrentTime);
+
+ /* Ungrab the server to let other people use it too */
+ XUngrabServer (xdisplay);
+
+ XFlush (xdisplay);
+
+ return wid;
+}
+
+/*
+ * Saves the session address in session file. Returns TRUE on
+ * success, FALSE if an error occurs.
+ */
+static int
+set_address_in_file (char *address, pid_t pid, Window wid)
+{
+ char *session_file;
+ FILE *f;
+
+ session_file = get_session_file();
+ if (session_file == NULL)
+ return FALSE;
+
+ f = fopen (session_file, "w");
+ if (f == NULL)
+ return FALSE; /* some kind of error */
+ fprintf (f, "%s\n%ld\n%ld\n", address, (long)pid, (long)wid);
+
+ fclose (f);
+ free (session_file);
+
+ return TRUE;
+}
+
+int
+x11_save_address (char *address, pid_t pid, long *wid)
+{
+ Window id = set_address_in_x11 (address, pid);
+ if (id != None)
+ {
+ if (!set_address_in_file (address, pid, id))
+ return FALSE;
+
+ if (wid != NULL)
+ *wid = (long) id;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int
+x11_init (void)
+{
+ return open_x11 () != NULL && init_x_atoms (xdisplay);
+}
+
+void
+x11_handle_event (void)
+{
+ if (xdisplay != NULL)
+ {
+ while (XPending (xdisplay))
+ {
+ XEvent ignored;
+ XNextEvent (xdisplay, &ignored);
+ }
+ }
+}
+
+#else
+void dummy_dbus_launch_x11 (void) { }
+#endif
diff --git a/tools/dbus-launch.1 b/tools/dbus-launch.1
index a3180f69..3c505e7b 100644
--- a/tools/dbus-launch.1
+++ b/tools/dbus-launch.1
@@ -7,7 +7,7 @@
dbus-launch \- Utility to start a message bus from a shell script
.SH SYNOPSIS
.PP
-.B dbus-launch [\-\-version] [\-\-sh-syntax] [\-\-csh-syntax] [\-\-auto-syntax] [\-\-exit-with-session] [\-\-config-file=FILENAME] [PROGRAM] [ARGS...]
+.B dbus-launch [\-\-version] [\-\-sh-syntax] [\-\-csh-syntax] [\-\-auto-syntax] [\-\-exit-with-session] [\-\-autolaunch] [\-\-config-file=FILENAME] [PROGRAM] [ARGS...]
.SH DESCRIPTION
@@ -90,6 +90,13 @@ server. If this process gets a HUP on stdin or loses its X connection,
it kills the message bus daemon.
.TP
+.I "--autolaunch"
+This option implies that \fIdbus-launch\fP should scan for a
+previously-started session and reuse the values found there. If no
+session is found, it will start a new session. The
+\-\-exit-with-session option is implied if \-\-autolaunch is given.
+
+.TP
.I "--sh-syntax"
Emit Bourne-shell compatible code to set up environment variables.
diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c
index 18a6d156..fb993e4e 100644
--- a/tools/dbus-launch.c
+++ b/tools/dbus-launch.c
@@ -20,7 +20,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#include <config.h>
+#include "dbus-launch.h"
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
@@ -32,22 +32,14 @@
#include <signal.h>
#include <stdarg.h>
#include <sys/select.h>
+#include <time.h>
+
#ifdef DBUS_BUILD_X11
#include <X11/Xlib.h>
+extern Display *xdisplay;
#endif
-#ifndef TRUE
-#define TRUE (1)
-#endif
-
-#ifndef FALSE
-#define FALSE (0)
-#endif
-
-#undef MAX
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-
-static void
+void
verbose (const char *format,
...)
{
@@ -95,7 +87,7 @@ version (void)
exit (0);
}
-static char *
+char *
xstrdup (const char *str)
{
int len;
@@ -276,8 +268,8 @@ do_waitpid (pid_t pid)
static pid_t bus_pid_to_kill = -1;
-static void
-kill_bus_and_exit (void)
+void
+kill_bus_and_exit (int exitcode)
{
verbose ("Killing message bus and exiting babysitter\n");
@@ -290,18 +282,38 @@ kill_bus_and_exit (void)
sleep (3);
kill (bus_pid_to_kill, SIGKILL);
- exit (0);
+ exit (exitcode);
}
-#ifdef DBUS_BUILD_X11
-static int
-x_io_error_handler (Display *xdisplay)
+static void
+print_variables (const char *bus_address, pid_t bus_pid, long bus_wid,
+ int c_shell_syntax, int bourne_shell_syntax,
+ int binary_syntax)
{
- verbose ("X IO error\n");
- kill_bus_and_exit ();
- return 0;
+ if (binary_syntax)
+ {
+ write (1, bus_address, strlen (bus_address) + 1);
+ write (1, &bus_pid, sizeof bus_pid);
+ write (1, &bus_wid, sizeof bus_wid);
+ return;
+ }
+ else if (c_shell_syntax)
+ {
+ printf ("setenv DBUS_SESSION_BUS_ADDRESS '%s';\n", bus_address);
+ printf ("set DBUS_SESSION_BUS_PID=%ld;\n", (long) bus_pid);
+ if (bus_wid)
+ printf ("set DBUS_SESSION_BUS_WINDOWID=%ld;\n", (long) bus_wid);
+ }
+ else
+ {
+ printf ("DBUS_SESSION_BUS_ADDRESS='%s';\n", bus_address);
+ if (bourne_shell_syntax)
+ printf ("export DBUS_SESSION_BUS_ADDRESS;\n");
+ printf ("DBUS_SESSION_BUS_PID=%ld;\n", (long) bus_pid);
+ if (bus_wid)
+ printf ("DBUS_SESSION_BUS_WINDOWID=%ld;\n", (long) bus_wid);
+ }
}
-#endif
static int got_sighup = FALSE;
@@ -326,9 +338,6 @@ kill_bus_when_session_ends (void)
fd_set err_set;
struct sigaction act;
sigset_t empty_mask;
-#ifdef DBUS_BUILD_X11
- Display *xdisplay;
-#endif
/* install SIGHUP handler */
got_sighup = FALSE;
@@ -340,17 +349,14 @@ kill_bus_when_session_ends (void)
sigaction (SIGTERM, &act, NULL);
#ifdef DBUS_BUILD_X11
- xdisplay = XOpenDisplay (NULL);
+ x11_init();
if (xdisplay != NULL)
{
- verbose ("Successfully opened X display\n");
x_fd = ConnectionNumber (xdisplay);
- XSetIOErrorHandler (x_io_error_handler);
}
else
x_fd = -1;
#else
- verbose ("Compiled without X11 support\n");
x_fd = -1;
#endif
@@ -393,7 +399,7 @@ kill_bus_when_session_ends (void)
if (got_sighup)
{
verbose ("Got SIGHUP, exiting\n");
- kill_bus_and_exit ();
+ kill_bus_and_exit (0);
}
#ifdef DBUS_BUILD_X11
@@ -405,15 +411,7 @@ kill_bus_when_session_ends (void)
verbose ("X fd condition reading = %d error = %d\n",
FD_ISSET (x_fd, &read_set),
FD_ISSET (x_fd, &err_set));
-
- if (xdisplay != NULL)
- {
- while (XPending (xdisplay))
- {
- XEvent ignored;
- XNextEvent (xdisplay, &ignored);
- }
- }
+ x11_handle_event ();
#endif
if (tty_fd >= 0)
@@ -431,7 +429,7 @@ kill_bus_when_session_ends (void)
bytes_read, errno);
if (bytes_read == 0)
- kill_bus_and_exit (); /* EOF */
+ kill_bus_and_exit (0); /* EOF */
else if (bytes_read < 0 && errno != EINTR)
{
/* This shouldn't happen I don't think; to avoid
@@ -439,14 +437,14 @@ kill_bus_when_session_ends (void)
*/
fprintf (stderr, "dbus-launch: error reading from stdin: %s\n",
strerror (errno));
- kill_bus_and_exit ();
+ kill_bus_and_exit (0);
}
}
else if (FD_ISSET (tty_fd, &err_set))
{
verbose ("TTY has error condition\n");
- kill_bus_and_exit ();
+ kill_bus_and_exit (0);
}
}
}
@@ -455,19 +453,14 @@ kill_bus_when_session_ends (void)
static void
babysit (int exit_with_session,
pid_t child_pid,
- int read_bus_pid_fd, /* read pid from here */
- int write_bus_pid_fd) /* forward pid to here */
+ int read_bus_pid_fd) /* read pid from here */
{
int ret;
-#define MAX_PID_LEN 64
- char buf[MAX_PID_LEN];
- long val;
- char *end;
int dev_null_fd;
const char *s;
- verbose ("babysitting, exit_with_session = %d, child_pid = %ld, read_bus_pid_fd = %d, write_bus_pid_fd = %d\n",
- exit_with_session, (long) child_pid, read_bus_pid_fd, write_bus_pid_fd);
+ verbose ("babysitting, exit_with_session = %d, child_pid = %ld, read_bus_pid_fd = %d\n",
+ exit_with_session, (long) child_pid, read_bus_pid_fd);
/* We chdir ("/") since we are persistent and daemon-like, and fork
* again so dbus-launch can reap the parent. However, we don't
@@ -536,41 +529,26 @@ babysit (int exit_with_session,
/* Child continues */
verbose ("=== Babysitter process created\n");
- verbose ("Reading PID from daemon\n");
- /* Now read data */
- switch (read_line (read_bus_pid_fd, buf, MAX_PID_LEN))
+ verbose ("Reading PID from bus\n");
+
+ switch (read_pid (read_bus_pid_fd, &bus_pid_to_kill))
{
case READ_STATUS_OK:
break;
case READ_STATUS_EOF:
- fprintf (stderr, "EOF reading PID from bus daemon\n");
+ fprintf (stderr, "EOF in dbus-launch reading PID from bus daemon\n");
exit (1);
break;
case READ_STATUS_ERROR:
- fprintf (stderr, "Error reading PID from bus daemon: %s\n",
- strerror (errno));
+ fprintf (stderr, "Error in dbus-launch reading PID from bus daemon: %s\n",
+ strerror (errno));
exit (1);
break;
}
- end = NULL;
- val = strtol (buf, &end, 0);
- if (buf == end || end == NULL)
- {
- fprintf (stderr, "Failed to parse bus PID \"%s\": %s\n",
- buf, strerror (errno));
- exit (1);
- }
-
- bus_pid_to_kill = val;
-
verbose ("Got PID %ld from daemon\n",
(long) bus_pid_to_kill);
- /* Write data to launcher */
- write_pid (write_bus_pid_fd, bus_pid_to_kill);
- close (write_bus_pid_fd);
-
if (exit_with_session)
{
/* Bus is now started and launcher has needed info;
@@ -597,9 +575,11 @@ main (int argc, char **argv)
const char *runprog = NULL;
int remaining_args = 0;
int exit_with_session;
+ int binary_syntax = FALSE;
int c_shell_syntax = FALSE;
int bourne_shell_syntax = FALSE;
int auto_shell_syntax = FALSE;
+ int autolaunch = FALSE;
int i;
int ret;
int bus_pid_to_launcher_pipe[2];
@@ -628,10 +608,14 @@ main (int argc, char **argv)
else if (strcmp (arg, "-s") == 0 ||
strcmp (arg, "--sh-syntax") == 0)
bourne_shell_syntax = TRUE;
+ else if (strcmp (arg, "--binary-syntax") == 0)
+ binary_syntax = TRUE;
else if (strcmp (arg, "--version") == 0)
version ();
else if (strcmp (arg, "--exit-with-session") == 0)
exit_with_session = TRUE;
+ else if (strcmp (arg, "--autolaunch") == 0)
+ autolaunch = TRUE;
else if (strstr (arg, "--config-file=") == arg)
{
const char *file;
@@ -672,9 +656,6 @@ main (int argc, char **argv)
++i;
}
- if (exit_with_session)
- verbose ("--exit-with-session enabled\n");
-
if (auto_shell_syntax)
{
if ((shname = getenv ("SHELL")) != NULL)
@@ -688,8 +669,52 @@ main (int argc, char **argv)
bourne_shell_syntax = TRUE;
}
+ if (exit_with_session)
+ verbose ("--exit-with-session enabled\n");
+
+ if (autolaunch)
+ {
+#ifndef DBUS_BUILD_X11
+ fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n"
+ "Cannot continue.\n");
+ exit (1);
+#else
+ char *address;
+ pid_t pid;
+ long wid;
+
+ verbose ("Autolaunch enabled (using X11).\n");
+ if (!exit_with_session)
+ {
+ verbose ("--exit-with-session automatically enabled\n");
+ exit_with_session = TRUE;
+ }
+
+ if (!x11_init ())
+ {
+ fprintf (stderr, "Autolaunch error: X11 initialization failed.\n");
+ exit (1);
+ }
+
+ if (!x11_get_address (&address, &pid, &wid))
+ {
+ fprintf (stderr, "Autolaunch error: X11 communication error.\n");
+ exit (1);
+ }
+
+ if (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);
+ exit (0);
+ }
+#endif
+ }
+
if (pipe (bus_pid_to_launcher_pipe) < 0 ||
- pipe (bus_address_to_launcher_pipe) < 0)
+ pipe (bus_address_to_launcher_pipe) < 0 ||
+ pipe (bus_pid_to_babysitter_pipe) < 0)
{
fprintf (stderr,
"Failed to create pipe: %s\n",
@@ -697,9 +722,6 @@ main (int argc, char **argv)
exit (1);
}
- bus_pid_to_babysitter_pipe[READ_END] = -1;
- bus_pid_to_babysitter_pipe[WRITE_END] = -1;
-
ret = fork ();
if (ret < 0)
{
@@ -716,17 +738,9 @@ main (int argc, char **argv)
char write_address_fd_as_string[MAX_FD_LEN];
verbose ("=== Babysitter's intermediate parent created\n");
-
+
/* Fork once more to create babysitter */
- if (pipe (bus_pid_to_babysitter_pipe) < 0)
- {
- fprintf (stderr,
- "Failed to create pipe: %s\n",
- strerror (errno));
- exit (1);
- }
-
ret = fork ();
if (ret < 0)
{
@@ -741,6 +755,7 @@ main (int argc, char **argv)
verbose ("=== Babysitter's intermediate parent continues\n");
close (bus_pid_to_launcher_pipe[READ_END]);
+ close (bus_pid_to_launcher_pipe[WRITE_END]);
close (bus_address_to_launcher_pipe[READ_END]);
close (bus_address_to_launcher_pipe[WRITE_END]);
close (bus_pid_to_babysitter_pipe[WRITE_END]);
@@ -750,8 +765,7 @@ main (int argc, char **argv)
* daemon
*/
babysit (exit_with_session, ret,
- bus_pid_to_babysitter_pipe[READ_END],
- bus_pid_to_launcher_pipe[WRITE_END]);
+ bus_pid_to_babysitter_pipe[READ_END]);
exit (0);
}
@@ -763,10 +777,10 @@ main (int argc, char **argv)
close (bus_pid_to_launcher_pipe[READ_END]);
close (bus_address_to_launcher_pipe[READ_END]);
close (bus_pid_to_babysitter_pipe[READ_END]);
- close (bus_pid_to_launcher_pipe[WRITE_END]);
+ close (bus_pid_to_babysitter_pipe[WRITE_END]);
sprintf (write_pid_fd_as_string,
- "%d", bus_pid_to_babysitter_pipe[WRITE_END]);
+ "%d", bus_pid_to_launcher_pipe[WRITE_END]);
sprintf (write_address_fd_as_string,
"%d", bus_address_to_launcher_pipe[WRITE_END]);
@@ -809,14 +823,20 @@ main (int argc, char **argv)
else
{
/* Parent */
-#define MAX_ADDR_LEN 512
+#define MAX_PID_LEN 64
pid_t bus_pid;
char bus_address[MAX_ADDR_LEN];
+ char buf[MAX_PID_LEN];
+ char *end;
+ long wid = 0;
+ long val;
+ int ret2;
verbose ("=== Parent dbus-launch continues\n");
close (bus_pid_to_launcher_pipe[WRITE_END]);
close (bus_address_to_launcher_pipe[WRITE_END]);
+ close (bus_pid_to_babysitter_pipe[READ_END]);
verbose ("Waiting for babysitter's intermediate parent\n");
@@ -851,25 +871,70 @@ main (int argc, char **argv)
close (bus_address_to_launcher_pipe[READ_END]);
- verbose ("Reading PID from babysitter\n");
-
- switch (read_pid (bus_pid_to_launcher_pipe[READ_END], &bus_pid))
- {
- case READ_STATUS_OK:
- break;
- case READ_STATUS_EOF:
- fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n");
- exit (1);
- break;
- case READ_STATUS_ERROR:
- fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n",
- strerror (errno));
- exit (1);
- break;
- }
+ verbose ("Reading PID from daemon\n");
+ /* Now read data */
+ switch (read_line (bus_pid_to_launcher_pipe[READ_END], buf, MAX_PID_LEN))
+ {
+ case READ_STATUS_OK:
+ break;
+ case READ_STATUS_EOF:
+ fprintf (stderr, "EOF reading PID from bus daemon\n");
+ exit (1);
+ break;
+ case READ_STATUS_ERROR:
+ fprintf (stderr, "Error reading PID from bus daemon: %s\n",
+ strerror (errno));
+ exit (1);
+ break;
+ }
+
+ end = NULL;
+ val = strtol (buf, &end, 0);
+ if (buf == end || end == NULL)
+ {
+ fprintf (stderr, "Failed to parse bus PID \"%s\": %s\n",
+ buf, strerror (errno));
+ exit (1);
+ }
+
+ bus_pid = val;
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);
+ }
+#endif
+
+ /* Forward the pid to the babysitter */
+ write_pid (bus_pid_to_babysitter_pipe[WRITE_END], bus_pid);
+ close (bus_pid_to_babysitter_pipe[WRITE_END]);
+
if (runprog)
{
char *envvar;
@@ -904,18 +969,8 @@ main (int argc, char **argv)
}
else
{
- if (c_shell_syntax)
- printf ("setenv DBUS_SESSION_BUS_ADDRESS '%s';\n", bus_address);
- else
- {
- printf ("DBUS_SESSION_BUS_ADDRESS='%s';\n", bus_address);
- if (bourne_shell_syntax)
- printf ("export DBUS_SESSION_BUS_ADDRESS;\n");
- }
- if (c_shell_syntax)
- printf ("set DBUS_SESSION_BUS_PID=%ld;\n", (long) bus_pid);
- else
- printf ("DBUS_SESSION_BUS_PID=%ld;\n", (long) bus_pid);
+ print_variables (bus_address, bus_pid, wid, c_shell_syntax,
+ bourne_shell_syntax, binary_syntax);
}
verbose ("dbus-launch exiting\n");
diff --git a/tools/dbus-launch.h b/tools/dbus-launch.h
new file mode 100644
index 00000000..1b22f3df
--- /dev/null
+++ b/tools/dbus-launch.h
@@ -0,0 +1,56 @@
+/* -*- 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
+ *
+ */
+
+#ifndef DBUS_LAUNCH_H
+#define DBUS_LAUNCH_H
+
+#include <config.h>
+#include <sys/types.h>
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#undef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#define MAX_ADDR_LEN 512
+
+/* defined in dbus-launch.c */
+void verbose (const char *format, ...);
+char *xstrdup (const char *str);
+void kill_bus_and_exit (int exitcode);
+
+#ifdef DBUS_BUILD_X11
+/* defined in dbus-launch-x11.c */
+int x11_init (void);
+int x11_get_address (char **paddress, pid_t *pid, long *wid);
+int x11_save_address (char *address, pid_t pid, long *wid);
+void x11_handle_event (void);
+#endif
+
+#endif