summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2006-10-01 20:05:39 +0000
committerHavoc Pennington <hp@redhat.com>2006-10-01 20:05:39 +0000
commit10fe37f58213d3895229208453c3e691e554ed72 (patch)
tree45b26b235471d398ef9d7d1331a00b02690d62b1 /tools
parent7020b573764bb86551d329e867c2e87172424c9b (diff)
2006-10-01 Havoc Pennington <hp@redhat.com>
* tools/dbus-launch.c (print_variables): if no syntax is given, don't print something that's sort-of-half-sh-syntax, just print a plain key-value pairs thing. * tools/dbus-launch-x11.c: use machine ID rather than hostname for the local machine representation (but still have the hostname in the display). Remove the hostname from the display if it is localhost. Change session files to be named ~/.dbus/session-bus/machine-display. Change X atoms to be underscore-prefixed so nobody whines about ICCCM compliance. Otherwise name them the same as the env variables. Change session file format to include key-value pairs and an explanatory comment. Keys are the same as the env variables. (set_address_in_x11): X property format can't depend on sizeof(pid_t) on a particular machine, fix to always be 32 bits * tools/dbus-launch.c: make --autolaunch take a machine id argument. If --autolaunch is used with a program to run, complain for now (but add a FIXME). Also, don't look for existing bus if there's a program to run (but add a FIXME). * dbus/dbus-sysdeps-unix.c (_dbus_get_autolaunch_address): pass machine uuid to dbus-launch (avoids linking dbus-launch to libdbus just to get this, and avoids duplicating uuid-reading code). * tools/dbus-launch.1: clarify various things
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile.am4
-rw-r--r--tools/dbus-launch-x11.c208
-rw-r--r--tools/dbus-launch.178
-rw-r--r--tools/dbus-launch.c93
-rw-r--r--tools/dbus-launch.h2
5 files changed, 300 insertions, 85 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
index fa93f621..e53b47a9 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,4 +1,6 @@
-INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_X_CFLAGS) -DDBUS_LOCALEDIR=\"@EXPANDED_DATADIR@/locale\" -DDBUS_COMPILATION -DDBUS_DAEMONDIR=\"@DBUS_DAEMONDIR@\"
+configdir=$(sysconfdir)/dbus-1
+
+INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_X_CFLAGS) -DDBUS_LOCALEDIR=\"@EXPANDED_DATADIR@/locale\" -DDBUS_COMPILATION -DDBUS_DAEMONDIR=\"@DBUS_DAEMONDIR@\" -DDBUS_MACHINE_UUID_FILE=\""$(configdir)/machine-id"\"
bin_PROGRAMS=dbus-send dbus-monitor dbus-launch dbus-cleanup-sockets dbus-uuidgen
diff --git a/tools/dbus-launch-x11.c b/tools/dbus-launch-x11.c
index 67aef04d..f0588ad8 100644
--- a/tools/dbus-launch-x11.c
+++ b/tools/dbus-launch-x11.c
@@ -24,6 +24,8 @@
#ifdef DBUS_BUILD_X11
#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
@@ -46,39 +48,53 @@ x_io_error_handler (Display *xdisplay)
return 0;
}
-static char *
-get_local_hostname (void)
+static void
+remove_prefix (char *s,
+ char *prefix)
{
- static const int increment = 128;
- static char *cache = NULL;
- char *buffer = NULL;
- int size = 0;
+ int plen;
+
+ plen = strlen (prefix);
- while (cache == NULL)
+ if (strncmp (s, prefix, plen) == 0)
{
- size += increment;
- buffer = realloc (buffer, size);
- if (buffer == NULL)
- return NULL; /* out of memory */
+ memmove (s, s + plen, strlen (s) - plen + 1);
+ }
+}
- if (gethostname (buffer, size - 1) == -1 &&
- errno != ENAMETOOLONG)
- return NULL;
+static const char*
+get_homedir (void)
+{
+ const char *home;
+
+ home = getenv ("HOME");
+ if (home == NULL)
+ {
+ /* try from the user database */
+ struct passwd *user = getpwuid (getuid());
+ if (user != NULL)
+ home = user->pw_dir;
+ }
- buffer[size - 1] = '\0'; /* to make sure */
- cache = buffer;
+ if (home == NULL)
+ {
+ fprintf (stderr, "Can't get user home directory\n");
+ exit (1);
}
- return cache;
+ return home;
}
+#define DBUS_DIR ".dbus"
+#define DBUS_SESSION_BUS_DIR "session-bus"
+
static char *
get_session_file (void)
{
- static const char prefix[] = "/.dbus-session-file_";
- char *hostname;
+ static const char prefix[] = "/" DBUS_DIR "/" DBUS_SESSION_BUS_DIR "/";
+ const char *machine;
+ const char *home;
char *display;
- char *home;
char *result;
char *p;
@@ -92,43 +108,46 @@ get_session_file (void)
/* remove the screen part of the display name */
p = strrchr (display, ':');
if (p != NULL)
- for ( ; *p; ++p)
- if (*p == '.')
+ {
+ for ( ; *p; ++p)
{
- *p = '\0';
- break;
+ 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)
+ /* Note that we leave the hostname in the display most of the
+ * time. The idea is that we want to be per-(machine,display,user)
+ * triplet to be extra-sure we get a bus we can connect to. Ideally
+ * we'd recognize when the hostname matches the machine we're on in
+ * all cases; we do try to drop localhost and localhost.localdomain
+ * as a special common case so that alternate spellings of DISPLAY
+ * don't result in extra bus instances.
+ *
+ * We also kill the ":" if there's nothing in front of it. This
+ * avoids an ugly double underscore in the filename.
+ */
+ remove_prefix (display, "localhost.localdomain:");
+ remove_prefix (display, "localhost:");
+ remove_prefix (display, ":");
+
+ /* replace the : in the display with _ if the : is still there.
+ * use _ instead of - since it can't be in hostnames.
+ */
+ for (p = display; *p; ++p)
{
- /* 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;
+ if (*p == ':')
+ *p = '_';
}
+
+ machine = get_machine_uuid ();
- result = malloc (strlen (home) + strlen (prefix) + strlen (hostname) +
+ home = get_homedir ();
+
+ result = malloc (strlen (home) + strlen (prefix) + strlen (machine) +
strlen (display) + 2);
if (result == NULL)
{
@@ -139,8 +158,8 @@ get_session_file (void)
strcpy (result, home);
strcat (result, prefix);
- strcat (result, hostname);
- strcat (result, "_");
+ strcat (result, machine);
+ strcat (result, "-");
strcat (result, display);
free (display);
@@ -148,6 +167,46 @@ get_session_file (void)
return result;
}
+static void
+ensure_session_directory (void)
+{
+ const char *home;
+ char *dir;
+
+ home = get_homedir ();
+
+ /* be sure we have space for / and nul */
+ dir = malloc (strlen (home) + strlen (DBUS_DIR) + strlen (DBUS_SESSION_BUS_DIR) + 3);
+ if (dir == NULL)
+ {
+ fprintf (stderr, "no memory\n");
+ exit (1);
+ }
+
+ strcpy (dir, home);
+ strcat (dir, "/");
+ strcat (dir, DBUS_DIR);
+
+ if (mkdir (dir, 0700) < 0)
+ {
+ /* only print a warning here, writing the session file itself will fail later */
+ if (errno != EEXIST)
+ fprintf (stderr, "Unable to create %s\n", dir);
+ }
+
+ strcat (dir, "/");
+ strcat (dir, DBUS_SESSION_BUS_DIR);
+
+ if (mkdir (dir, 0700) < 0)
+ {
+ /* only print a warning here, writing the session file itself will fail later */
+ if (errno != EEXIST)
+ fprintf (stderr, "Unable to create %s\n", dir);
+ }
+
+ free (dir);
+}
+
static Display *
open_x11 (void)
{
@@ -166,12 +225,12 @@ open_x11 (void)
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 const char selection_prefix[] = "_DBUS_SESSION_BUS_SELECTION_";
+ static const char address_prefix[] = "_DBUS_SESSION_BUS_ADDRESS";
+ static const char pid_prefix[] = "_DBUS_SESSION_BUS_PID";
static int init = FALSE;
char *atom_name;
- char *hostname;
+ const char *machine;
char *user_name;
struct passwd *user;
@@ -186,15 +245,9 @@ init_x_atoms (Display *display)
}
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;
- }
+ machine = get_machine_uuid ();
- atom_name = malloc (strlen (hostname) + strlen (user_name) + 2 +
+ atom_name = malloc (strlen (machine) + strlen (user_name) + 2 +
MAX (strlen (selection_prefix),
MAX (strlen (address_prefix),
strlen (pid_prefix))));
@@ -209,7 +262,7 @@ init_x_atoms (Display *display)
strcpy (atom_name, selection_prefix);
strcat (atom_name, user_name);
strcat (atom_name, "_");
- strcat (atom_name, hostname);
+ strcat (atom_name, machine);
selection_atom = XInternAtom (display, atom_name, FALSE);
/* create the address property atom */
@@ -285,7 +338,8 @@ set_address_in_x11(char *address, pid_t pid)
{
char *current_address;
Window wid;
-
+ int pid32;
+
/* lock the X11 display to make sure we're doing this atomically */
XGrabServer (xdisplay);
@@ -313,8 +367,14 @@ set_address_in_x11(char *address, pid_t pid)
/* Save the property in the window */
XChangeProperty (xdisplay, wid, address_atom, XA_STRING, 8, PropModeReplace,
(unsigned char *)address, strlen (address));
+ pid32 = pid;
+ if (sizeof(pid32) != 4)
+ {
+ fprintf (stderr, "int is not 32 bits!\n");
+ exit (1);
+ }
XChangeProperty (xdisplay, wid, pid_atom, XA_CARDINAL, 32, PropModeReplace,
- (unsigned char *)&pid, sizeof(pid) / 4);
+ (unsigned char *)&pid32, 1);
/* Now grab the selection */
XSetSelectionOwner (xdisplay, selection_atom, wid, CurrentTime);
@@ -337,6 +397,7 @@ set_address_in_file (char *address, pid_t pid, Window wid)
char *session_file;
FILE *f;
+ ensure_session_directory ();
session_file = get_session_file();
if (session_file == NULL)
return FALSE;
@@ -344,7 +405,18 @@ set_address_in_file (char *address, pid_t pid, Window wid)
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);
+ fprintf (f,
+ "# This file allows processes on the machine with id %s using \n"
+ "# display %s to find the D-Bus session bus with the below address.\n"
+ "# If the DBUS_SESSION_BUS_ADDRESS environment variable is set, it will\n"
+ "# be used rather than this file.\n"
+ "# See \"man dbus-launch\" for more details.\n"
+ "DBUS_SESSION_BUS_ADDRESS=%s\n"
+ "DBUS_SESSION_BUS_PID=%ld\n"
+ "DBUS_SESSION_BUS_WINDOWID=%ld\n",
+ get_machine_uuid (),
+ getenv ("DISPLAY"),
+ address, (long)pid, (long)wid);
fclose (f);
free (session_file);
diff --git a/tools/dbus-launch.1 b/tools/dbus-launch.1
index 3c505e7b..bcc30d7c 100644
--- a/tools/dbus-launch.1
+++ b/tools/dbus-launch.1
@@ -7,27 +7,36 @@
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] [\-\-autolaunch] [\-\-config-file=FILENAME] [PROGRAM] [ARGS...]
+.B dbus-launch [\-\-version] [\-\-sh-syntax] [\-\-csh-syntax] [\-\-auto-syntax] [\-\-exit-with-session] [\-\-autolaunch=MACHINEID] [\-\-config-file=FILENAME] [PROGRAM] [ARGS...]
.SH DESCRIPTION
-The \fIdbus-launch\fP command is used to start \fIdbus-daemon\fP
-from a shell script. It would normally be called from a user's login
+The \fIdbus-launch\fP command is used to start a session bus
+instance of \fIdbus-daemon\fP from a shell script.
+It would normally be called from a user's login
scripts. Unlike the daemon itself, \fIdbus-launch\fP exits, so
backticks or the $() construct can be used to read information from
\fIdbus-launch\fP.
-With no arguments, \fIdbus-launch\fP will simply print the values of
-DBUS_SESSION_BUS_ADDRESS and DBUS_SESSION_BUS_PID.
+With no arguments, \fIdbus-launch\fP will launch a session bus
+instance and print the address and pid of that instance to standard
+output.
You may specify a program to be run; in this case, \fIdbus-launch\fP
-will then set the appropriate environment variables and execute the
+will launch a session bus instance, set the appropriate environment
+variables so the specified program can find the bus, and then execute the
specified program, with the specified arguments. See below for
examples.
-Finally, you may use the \-\-sh-syntax, \-\-csh-syntax, or
-\-\-auto-syntax commands to cause \fIdbus-launch\fP to emit shell code
-to set up the environment. This is useful in shell scripts.
+If you launch a program, \fIdbus-launch\fP will not print the
+information about the new bus to standard output.
+
+When \fIdbus-launch\fP prints bus information to standard output, by
+default it is in a simple key-value pairs format. However, you may
+request several alternate syntaxes using the \-\-sh-syntax, \-\-csh-syntax,
+\-\-binary-syntax, or
+\-\-auto-syntax options. Several of these cause \fIdbus-launch\fP to emit shell code
+to set up the environment.
With the \-\-auto-syntax option, \fIdbus-launch\fP looks at the value
of the SHELL environment variable to determine which shell syntax
@@ -67,12 +76,60 @@ dbus-launch gnome-session
.fi
The above would likely be appropriate for ~/.xsession or ~/.Xclients.
+.SH AUTOMATIC LAUNCHING
+
+.PP
+If DBUS_SESSION_BUS_ADDRESS is not set for a process that tries to use
+D-Bus, by default the process will attempt to invoke dbus-launch with
+the --autolaunch option to start up a new session bus or find the
+existing bus address on the X display or in a file in
+~/.dbus/session-bus/
+
+.PP
+Whenever an autolaunch occurs, the application that had to
+start a new bus will be in its own little world; it can effectively
+end up starting a whole new session if it tries to use a lot of
+bus services. This can be suboptimal or even totally broken, depending
+on the app and what it tries to do.
+
+.PP
+There are two common reasons for autolaunch. One is ssh to a remote
+machine. The ideal fix for that would be forwarding of
+DBUS_SESSION_BUS_ADDRESS in the same way that DISPLAY is forwarded.
+In the meantime, you can edit the session.conf config file to
+have your session bus listen on TCP, and manually set
+DBUS_SESSION_BUS_ADDRESS, if you like.
+
+.PP
+The second common reason for autolaunch is an su to another user, and
+display of X applications running as the second user on the display
+belonging to the first user. Perhaps the ideal fix in this case
+would be to allow the second user to connect to the session bus of the
+first user, just as they can connect to the first user's display.
+However, a mechanism for that has not been coded.
+
+.PP
+You can always avoid autolaunch by manually setting
+DBUS_SESSION_BUS_ADDRESS. Autolaunch happens because the default
+address if none is set is "autolaunch:", so if any other address is
+set there will be no autolaunch. You can however include autolaunch in
+an explicit session bus address as a fallback, for example
+DBUS_SESSION_BUS_ADDRESS="something:,autolaunch:" - in that case if
+the first address doesn't work, processes will autolaunch. (The bus
+address variable contains a comma-separated list of addresses to try.)
+
.SH OPTIONS
The following options are supported:
.TP
.I "--auto-syntax"
Choose \-\-csh-syntax or \-\-sh-syntax based on the SHELL environment variable.
+.I "--binary-syntax"
+Write to stdout a nul-terminated bus address, then the bus PID as a
+binary integer of size sizeof(pid_t), then the bus X window ID as a
+binary integer of size sizeof(long). Integers are in the machine's
+byte order, not network byte order or any other canonical byte order.
+
.TP
.I "--config-file=FILENAME"
Pass \-\-config-file=FILENAME to the bus daemon, instead of passing it
@@ -90,11 +147,12 @@ server. If this process gets a HUP on stdin or loses its X connection,
it kills the message bus daemon.
.TP
-.I "--autolaunch"
+.I "--autolaunch=MACHINEID"
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.
+This option is used by libdbus, you probably do not want to use it manually.
.TP
.I "--sh-syntax"
diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c
index 1589c168..c743121b 100644
--- a/tools/dbus-launch.c
+++ b/tools/dbus-launch.c
@@ -1,7 +1,8 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-launch.c dbus-launch utility
*
- * Copyright (C) 2003 Red Hat, Inc.
+ * Copyright (C) 2003, 2006 Red Hat, Inc.
+ * Copyright (C) 2006 Thiago Macieira <thiago@kde.org>
*
* Licensed under the Academic Free License version 2.1
*
@@ -39,6 +40,27 @@
extern Display *xdisplay;
#endif
+static char* machine_uuid = NULL;
+
+const char*
+get_machine_uuid (void)
+{
+ return machine_uuid;
+}
+
+static void
+save_machine_uuid (const char *uuid_arg)
+{
+ if (strlen (uuid_arg) != 32)
+ {
+ fprintf (stderr, "machine ID '%s' looks like it's the wrong length, should be 32 hex digits",
+ uuid_arg);
+ exit (1);
+ }
+
+ machine_uuid = xstrdup (uuid_arg);
+}
+
void
verbose (const char *format,
...)
@@ -303,8 +325,9 @@ print_variables (const char *bus_address, pid_t bus_pid, long bus_wid,
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);
+ fflush (stdout);
}
- else
+ else if (bourne_shell_syntax)
{
printf ("DBUS_SESSION_BUS_ADDRESS='%s';\n", bus_address);
if (bourne_shell_syntax)
@@ -312,6 +335,15 @@ print_variables (const char *bus_address, pid_t bus_pid, long bus_wid,
printf ("DBUS_SESSION_BUS_PID=%ld;\n", (long) bus_pid);
if (bus_wid)
printf ("DBUS_SESSION_BUS_WINDOWID=%ld;\n", (long) bus_wid);
+ fflush (stdout);
+ }
+ else
+ {
+ printf ("DBUS_SESSION_BUS_ADDRESS=%s\n", bus_address);
+ printf ("DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid);
+ if (bus_wid)
+ printf ("DBUS_SESSION_BUS_WINDOWID=%ld\n", (long) bus_wid);
+ fflush (stdout);
}
}
@@ -614,8 +646,38 @@ main (int argc, char **argv)
version ();
else if (strcmp (arg, "--exit-with-session") == 0)
exit_with_session = TRUE;
+ else if (strstr (arg, "--autolaunch=") == arg)
+ {
+ const char *s;
+
+ if (autolaunch)
+ {
+ fprintf (stderr, "--autolaunch given twice\n");
+ exit (1);
+ }
+
+ autolaunch = TRUE;
+
+ s = strchr (arg, '=');
+ ++s;
+
+ save_machine_uuid (s);
+ }
+ else if (prev_arg &&
+ strcmp (prev_arg, "--autolaunch") == 0)
+ {
+ if (autolaunch)
+ {
+ fprintf (stderr, "--autolaunch given twice\n");
+ exit (1);
+ }
+
+ autolaunch = TRUE;
+
+ save_machine_uuid (arg);
+ }
else if (strcmp (arg, "--autolaunch") == 0)
- autolaunch = TRUE;
+ ; /* wait for next arg */
else if (strstr (arg, "--config-file=") == arg)
{
const char *file;
@@ -673,7 +735,7 @@ main (int argc, char **argv)
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");
@@ -682,7 +744,23 @@ main (int argc, char **argv)
char *address;
pid_t pid;
long wid;
+
+ if (get_machine_uuid () == NULL)
+ {
+ fprintf (stderr, "Machine UUID not provided as arg to --autolaunch\n");
+ exit (1);
+ }
+ /* FIXME right now autolaunch always does print_variables(), but it should really
+ * exec the child program instead if a child program was specified. For now
+ * we just exit if this conflict arises.
+ */
+ if (runprog)
+ {
+ fprintf (stderr, "Currently --autolaunch does not support running a program\n");
+ exit (1);
+ }
+
verbose ("Autolaunch enabled (using X11).\n");
if (!exit_with_session)
{
@@ -703,7 +781,7 @@ main (int argc, char **argv)
}
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);
@@ -902,7 +980,10 @@ main (int argc, char **argv)
close (bus_pid_to_launcher_pipe[READ_END]);
#ifdef DBUS_BUILD_X11
- if (xdisplay != NULL)
+ /* FIXME the runprog == NULL is broken - we need to launch the runprog with the existing bus,
+ * instead of just doing print_variables() if there's an existing bus.
+ */
+ if (xdisplay != NULL && runprog == NULL)
{
ret2 = x11_save_address (bus_address, bus_pid, &wid);
if (ret2 == 0)
diff --git a/tools/dbus-launch.h b/tools/dbus-launch.h
index 1b22f3df..aa6f771f 100644
--- a/tools/dbus-launch.h
+++ b/tools/dbus-launch.h
@@ -45,6 +45,8 @@ void verbose (const char *format, ...);
char *xstrdup (const char *str);
void kill_bus_and_exit (int exitcode);
+const char* get_machine_uuid (void);
+
#ifdef DBUS_BUILD_X11
/* defined in dbus-launch-x11.c */
int x11_init (void);