-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/* dbus-launch.h dbus-launch utility
*
* Copyright (C) 2006 Thiago Macieira <thiago@kde.org>
*
* 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "dbus-launch.h"
#ifdef DBUS_BUILD_X11
#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
-Display *xdisplay;
+Display *xdisplay = NULL;
static Atom selection_atom;
static Atom address_atom;
static Atom pid_atom;
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;
+ machine = get_machine_uuid ();
+ if (machine == NULL)
+ return NULL;
+
display = xstrdup (getenv ("DISPLAY"));
if (display == NULL)
{
/* 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 _ */
+ /* 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)
- if (*p == ':')
- *p = '_';
-
- hostname = get_local_hostname ();
- if (hostname == NULL)
{
- /* out of memory */
- free (display);
- return NULL;
+ if (*p == ':')
+ *p = '_';
}
-
- 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) +
+
+ home = get_homedir ();
+
+ result = malloc (strlen (home) + strlen (prefix) + strlen (machine) +
strlen (display) + 2);
if (result == NULL)
{
strcpy (result, home);
strcat (result, prefix);
- strcat (result, hostname);
- strcat (result, "_");
+ strcat (result, machine);
+ strcat (result, "-");
strcat (result, display);
free (display);
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)
{
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;
if (init)
return TRUE;
+ machine = get_machine_uuid ();
+ if (machine == NULL)
+ return FALSE;
+
user = getpwuid (getuid ());
if (user == NULL)
{
}
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 +
+ atom_name = malloc (strlen (machine) + strlen (user_name) + 2 +
MAX (strlen (selection_prefix),
MAX (strlen (address_prefix),
strlen (pid_prefix))));
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 */
set_address_in_x11(char *address, pid_t pid)
{
char *current_address;
- Window wid;
-
+ Window wid = None;
+ unsigned long pid32; /* Xlib property functions want _long_ not 32-bit for format "32" */
+
/* lock the X11 display to make sure we're doing this atomically */
XGrabServer (xdisplay);
if (!x11_get_address (¤t_address, NULL, NULL))
{
/* error! */
- XUngrabServer (xdisplay);
- return None;
+ goto out;
}
if (current_address != NULL)
{
/* someone saved the address in the meantime */
- XUngrabServer (xdisplay);
free (current_address);
- return None;
+ goto out;
}
/* Create our window */
- wid = XCreateSimpleWindow (xdisplay, RootWindow (xdisplay, 0), -20, -20, 10, 10,
- 0, WhitePixel (xdisplay, 0),
- BlackPixel (xdisplay, 0));
+ wid = XCreateWindow (xdisplay, RootWindow (xdisplay, 0), -20, -20, 10, 10,
+ 0, CopyFromParent, InputOnly, CopyFromParent,
+ 0, NULL);
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));
+ pid32 = pid;
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);
+ out:
/* Ungrab the server to let other people use it too */
XUngrabServer (xdisplay);
+ /* And make sure that the ungrab gets sent to X11 */
XFlush (xdisplay);
return wid;
char *session_file;
FILE *f;
+ ensure_session_directory ();
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);
+ 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);