1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-launch.h dbus-launch utility
4 * Copyright (C) 2006 Thiago Macieira <thiago@kde.org>
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "dbus-launch.h"
27 #include <sys/types.h>
36 #include <X11/Xatom.h>
38 Display *xdisplay = NULL;
39 static Atom selection_atom;
40 static Atom address_atom;
44 x_io_error_handler (Display *xdisplay)
46 verbose ("X IO error\n");
47 kill_bus_and_exit (0);
52 remove_prefix (char *s,
57 plen = strlen (prefix);
59 if (strncmp (s, prefix, plen) == 0)
61 memmove (s, s + plen, strlen (s) - plen + 1);
70 home = getenv ("HOME");
73 /* try from the user database */
74 struct passwd *user = getpwuid (getuid());
81 fprintf (stderr, "Can't get user home directory\n");
88 #define DBUS_DIR ".dbus"
89 #define DBUS_SESSION_BUS_DIR "session-bus"
92 get_session_file (void)
94 static const char prefix[] = "/" DBUS_DIR "/" DBUS_SESSION_BUS_DIR "/";
101 display = xstrdup (getenv ("DISPLAY"));
104 verbose ("X11 integration disabled because X11 is not running\n");
108 /* remove the screen part of the display name */
109 p = strrchr (display, ':');
122 /* Note that we leave the hostname in the display most of the
123 * time. The idea is that we want to be per-(machine,display,user)
124 * triplet to be extra-sure we get a bus we can connect to. Ideally
125 * we'd recognize when the hostname matches the machine we're on in
126 * all cases; we do try to drop localhost and localhost.localdomain
127 * as a special common case so that alternate spellings of DISPLAY
128 * don't result in extra bus instances.
130 * We also kill the ":" if there's nothing in front of it. This
131 * avoids an ugly double underscore in the filename.
133 remove_prefix (display, "localhost.localdomain:");
134 remove_prefix (display, "localhost:");
135 remove_prefix (display, ":");
137 /* replace the : in the display with _ if the : is still there.
138 * use _ instead of - since it can't be in hostnames.
140 for (p = display; *p; ++p)
146 machine = get_machine_uuid ();
148 home = get_homedir ();
150 result = malloc (strlen (home) + strlen (prefix) + strlen (machine) +
151 strlen (display) + 2);
159 strcpy (result, home);
160 strcat (result, prefix);
161 strcat (result, machine);
162 strcat (result, "-");
163 strcat (result, display);
166 verbose ("session file: %s\n", result);
171 ensure_session_directory (void)
176 home = get_homedir ();
178 /* be sure we have space for / and nul */
179 dir = malloc (strlen (home) + strlen (DBUS_DIR) + strlen (DBUS_SESSION_BUS_DIR) + 3);
182 fprintf (stderr, "no memory\n");
188 strcat (dir, DBUS_DIR);
190 if (mkdir (dir, 0700) < 0)
192 /* only print a warning here, writing the session file itself will fail later */
194 fprintf (stderr, "Unable to create %s\n", dir);
198 strcat (dir, DBUS_SESSION_BUS_DIR);
200 if (mkdir (dir, 0700) < 0)
202 /* only print a warning here, writing the session file itself will fail later */
204 fprintf (stderr, "Unable to create %s\n", dir);
213 if (xdisplay != NULL)
216 xdisplay = XOpenDisplay (NULL);
217 if (xdisplay != NULL)
219 verbose ("Connected to X11 display '%s'\n", DisplayString (xdisplay));
220 XSetIOErrorHandler (x_io_error_handler);
226 init_x_atoms (Display *display)
228 static const char selection_prefix[] = "_DBUS_SESSION_BUS_SELECTION_";
229 static const char address_prefix[] = "_DBUS_SESSION_BUS_ADDRESS";
230 static const char pid_prefix[] = "_DBUS_SESSION_BUS_PID";
231 static int init = FALSE;
240 user = getpwuid (getuid ());
243 verbose ("Could not determine the user informations; aborting X11 integration.\n");
246 user_name = xstrdup(user->pw_name);
248 machine = get_machine_uuid ();
250 atom_name = malloc (strlen (machine) + strlen (user_name) + 2 +
251 MAX (strlen (selection_prefix),
252 MAX (strlen (address_prefix),
253 strlen (pid_prefix))));
254 if (atom_name == NULL)
256 verbose ("Could not create X11 atoms; aborting X11 integration.\n");
261 /* create the selection atom */
262 strcpy (atom_name, selection_prefix);
263 strcat (atom_name, user_name);
264 strcat (atom_name, "_");
265 strcat (atom_name, machine);
266 selection_atom = XInternAtom (display, atom_name, FALSE);
268 /* create the address property atom */
269 strcpy (atom_name, address_prefix);
270 address_atom = XInternAtom (display, atom_name, FALSE);
272 /* create the PID property atom */
273 strcpy (atom_name, pid_prefix);
274 pid_atom = XInternAtom (display, atom_name, FALSE);
283 * Gets the daemon address from the X11 display.
284 * Returns FALSE if there was an error. Returning
285 * TRUE does not mean the address exists.
288 x11_get_address (char **paddress, pid_t *pid, long *wid)
299 /* locate the selection owner */
300 owner = XGetSelectionOwner (xdisplay, selection_atom);
302 return TRUE; /* no owner */
306 /* get the bus address */
307 XGetWindowProperty (xdisplay, owner, address_atom, 0, 1024, False,
308 XA_STRING, &type, &format, &items, &after,
309 (unsigned char **) &data);
310 if (type == None || after != 0 || data == NULL || format != 8)
311 return FALSE; /* error */
313 *paddress = xstrdup (data);
320 XGetWindowProperty (xdisplay, owner, pid_atom, 0, sizeof pid, False,
321 XA_CARDINAL, &type, &format, &items, &after,
322 (unsigned char **) &data);
323 if (type != None && after == 0 && data != NULL && format == 32)
324 *pid = (pid_t) *(long*) data;
328 return TRUE; /* success */
332 * Saves the address in the X11 display. Returns 0 on success.
333 * If an error occurs, returns -1. If the selection already exists,
334 * returns 1. (i.e. another daemon is already running)
337 set_address_in_x11(char *address, pid_t pid)
339 char *current_address;
343 /* lock the X11 display to make sure we're doing this atomically */
344 XGrabServer (xdisplay);
346 if (!x11_get_address (¤t_address, NULL, NULL))
349 XUngrabServer (xdisplay);
353 if (current_address != NULL)
355 /* someone saved the address in the meantime */
356 XUngrabServer (xdisplay);
357 free (current_address);
361 /* Create our window */
362 wid = XCreateSimpleWindow (xdisplay, RootWindow (xdisplay, 0), -20, -20, 10, 10,
363 0, WhitePixel (xdisplay, 0),
364 BlackPixel (xdisplay, 0));
365 verbose ("Created window %d\n", wid);
367 /* Save the property in the window */
368 XChangeProperty (xdisplay, wid, address_atom, XA_STRING, 8, PropModeReplace,
369 (unsigned char *)address, strlen (address));
371 if (sizeof(pid32) != 4)
373 fprintf (stderr, "int is not 32 bits!\n");
376 XChangeProperty (xdisplay, wid, pid_atom, XA_CARDINAL, 32, PropModeReplace,
377 (unsigned char *)&pid32, 1);
379 /* Now grab the selection */
380 XSetSelectionOwner (xdisplay, selection_atom, wid, CurrentTime);
382 /* Ungrab the server to let other people use it too */
383 XUngrabServer (xdisplay);
391 * Saves the session address in session file. Returns TRUE on
392 * success, FALSE if an error occurs.
395 set_address_in_file (char *address, pid_t pid, Window wid)
400 ensure_session_directory ();
401 session_file = get_session_file();
402 if (session_file == NULL)
405 f = fopen (session_file, "w");
407 return FALSE; /* some kind of error */
409 "# This file allows processes on the machine with id %s using \n"
410 "# display %s to find the D-Bus session bus with the below address.\n"
411 "# If the DBUS_SESSION_BUS_ADDRESS environment variable is set, it will\n"
412 "# be used rather than this file.\n"
413 "# See \"man dbus-launch\" for more details.\n"
414 "DBUS_SESSION_BUS_ADDRESS=%s\n"
415 "DBUS_SESSION_BUS_PID=%ld\n"
416 "DBUS_SESSION_BUS_WINDOWID=%ld\n",
419 address, (long)pid, (long)wid);
428 x11_save_address (char *address, pid_t pid, long *wid)
430 Window id = set_address_in_x11 (address, pid);
433 if (!set_address_in_file (address, pid, id))
446 return open_x11 () != NULL && init_x_atoms (xdisplay);
450 x11_handle_event (void)
452 if (xdisplay != NULL)
454 while (XPending (xdisplay))
457 XNextEvent (xdisplay, &ignored);
463 void dummy_dbus_launch_x11 (void) { }