[patch] Auto session bus launch from libdbus, take 2
Havoc Pennington
hp at redhat.com
Fri Sep 15 18:57:40 PDT 2006
Hi,
Thiago Macieira wrote:
> Here goes another patch.
Looks good to me, I only have nitpicky/what-things-are-named kind of
comments, no major structural changes.
> Worthy of note:
> * the session file is created, but never erased
> * the session file is never read from (libdbus-1 always forks and calls
> dbus-launch)
Is the intent that we would add code to libdbus to read it?
Here are my nitpicks:
> + if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL)
> + bus_connection_addresses[DBUS_BUS_SESSION] =
> + _dbus_strdup (DBUS_SESSION_BUS_DEFAULT_ADDRESS);
> +
> _dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_SESSION] ?
> bus_connection_addresses[DBUS_BUS_SESSION] : "none set");
This effectively handles out of memory OK, but it's a little odd since
the code looks like it's not ever supposed to have a null
DBUS_BUS_SESSION, even though it does work. I can't think of a fix
really so I guess I'm just whining ;-)
> +#define DBUS_SESSION_BUS_DEFAULT_METHOD "session"
> +#define DBUS_SESSION_BUS_DEFAULT_ADDRESS DBUS_SESSION_BUS_DEFAULT_METHOD ":"
This gives me an idea, which is to go ahead and define methods
"autolaunch" and "homefile" then the default address could be
"homefile:,autolaunch:" thus getting the automatic fallback behavior.
I think this was a great idea to define autostart as an address method,
which means DBUS_SESSION_BUS_ADDRESS replaces it completely; if you have
a bad address env variable, an error is better than autostarting a new
bus. But if people want to force autostart they can put the autostart
address in their env variable.
This new address type(s) should be mentioned in the man page. Well, I'm
not sure the old addresses are in there, but I hope they are. Surely
they are somewhere in the docs. Wherever they are in the docs, we should
also mention any new address types there, let's put it that way ;-)
> +DBusTransport *
> +_dbus_transport_open_sysdep (DBusAddressEntry *entry,
> + DBusError *error)
The unix domain socket transport is also unix-specific, but
isn't (for the moment) in this file. presumably we want to
handle these two or three platform-specific methods
(unix:,session:/homefile:/autolaunch:) in a similar way.
I'm not sure what that way is yet but the rough theory
I had was to move most of dbus-transport-unix.c to a
dbus-transport-socket.c also used on Windows and have it handle tcp:.
Then have dbus-transport-unix.c just handle unix: and chain to
dbus-transport-socket.c.
I would not want to mix the dbus-transport-socket.c change into this
patch, but the following might make sense:
- export:
char* _dbus_autolaunch_bus_unix(DBusError *error)
which returns the address of the autolaunched bus.
- use that function in dbus-transport-unix.c to implement
_dbus_transport_new_autolaunch()
Then the code will stay about the same when we clean it up to have
dbus-transport-socket.c.
> +{
> + static char *cached_address = 0;
I'm not sure this cache is needed, since the session bus is stored
globally in dbus-bus.c, once the connection is open we won't try to open
the transport again. The cache would however prevent the bus from ever
being respawned if killed, and it will also break dbus_shutdown(). So
maybe it's best to just skip it until it shows up in a profile ?
> + /* child process */
> + int fd = open ("/dev/null", O_RDWR);
> +
> + /* set-up stdXXX */
> + close (address_pipe[READ_END]);
> + close (0); /* close stdin */
> + close (1); /* close stdout */
> + close (2); /* close stderr */
> + dup2 (fd, 0);
> + dup2 (address_pipe[WRITE_END], 1);
> + dup2 (fd, 2);
> + close (fd);
> + close (address_pipe[WRITE_END]);
It makes me a tiny bit nervous to ignore all those return values, while
I agree they won't fail in practice, not printing any errors could hide
bugs or something. Not a mandatory fix but would be nice.
> + do
> + {
> + ret = _dbus_read (address_pipe[READ_END], &address, 1024);
> + }
> + while (ret == 1024);
Technically read() is allowed to return <1024 even if EOF has not been
reached, isn't it? Unless _dbus_read calls read() multiple times until
it fills the buffer (don't remember)
> + else if (strcmp (method, DBUS_SESSION_BUS_DEFAULT_METHOD) == 0)
> + {
> + transport = _dbus_transport_open_sysdep (entry, error);
> + }
This could just be _new_autolaunch or whatever here
I think using the DEFAULT_METHOD macro is not right here because here we
want this specific method, not the default method. i.e. maybe the
default method could be changed to foobar: but still we want to handle
session: or autolaunch: in this spot.
> #ifdef DBUS_BUILD_X11
> #include <X11/Xlib.h>
> +extern Display *xdisplay;
> #endif
just put this in dbus-launch.h ?
> + if (bus_wid)
> + printf ("DBUS_SESSION_BUS_WID=%ld;\n", (long) bus_wid);
> + }
I'd spell out instead of the WID abbreviation, PID is a standard
abbreviation but WID not so much.
> + else if (strcmp (arg, "--x11-integration") == 0)
> + x11_integration = TRUE;
I think something more descriptive than --x11-integration would be good.
Maybe --exit-with-x-session and/or --use-existing-x-property ?
Should be sure the option is added to the man page, whatever it is called.
> verbose ("dbus-launch exiting\n");
> --- /dev/null 2006-09-12 17:30:44.756285750 +0200
> +++ dbus-launch.h 2006-09-15 14:34:19.000000000 +0200
> @@ -0,0 +1,56 @@
> +/* -*- mode: C; c-file-style: "gnu" -*- */
> +/* dbus-launch.c dbus-launch utility
This should be dbus-launch.h
> --- /dev/null 2006-09-12 17:30:44.756285750 +0200
> +++ dbus-launch-x11.c 2006-09-15 15:56:18.000000000 +0200
> @@ -0,0 +1,387 @@
> +/* -*- mode: C; c-file-style: "gnu" -*- */
> +/* dbus-launch.c dbus-launch utility
dbus-launch-x11.c
> +static char *
> +get_local_hostname (void)
I do still think the guid approach would be easy and more robust, given
all the localhost.localdomain hosts in the world. However, I guess
there's no real compatibility guarantee on how we do this so we can
change it later.
> + 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 ();
Remember the display can also have the hostname in it already, really
what you want is ONLY the display number which is between the ":" and
the "." I think.
> + static const char selection_prefix[] = "D-BUS_SESSION_SELECTION_";
> + static const char address_prefix[] = "D-BUS_SESSION_ADDRESS";
> + static const char pid_prefix[] = "D-BUS_SESSION_PID";
Hyphens are rarely used in X atoms, also a "_" prefix is normal, so
something like _DBUS_SESSION_SELECTION, _DBUS_SESSION_PID
Why do all three of these need to be set? I would think we only need the
address?
> + /* 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);
Rather than creating all these atoms with the hostname munged in, since
we are already creating a window to own the selection, we could just
have the hostname in the selection name, then set the pid and address on
the selection owner window. That's a pretty normal X thing to do.
> + 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*)data;
I think XGetWindowProperty has surprising behavior on 64-bit but I don't
remember offhand what it is. It's possible that "data" there is always a
long even though it's format "32" - I'd have to look at some other code
and see.
I would not in any case cast to pid_t since that pointer is going to be
to maybe int or long, but not to pid_t. The cast to pid_t would need to
be *after* dereferencing the pointer if the compiler is going to do the
right thing. (Assuming pid_t is anything other than int ever, which I
doubt, but if going to the trouble to use all the libc _t types, may as
well do it right ;-)
> + /* Now grab the selection */
> + XSetSelectionOwner (xdisplay, selection_atom, wid, CurrentTime);
CurrentTime is one big race condition usually but should be OK since the
server is grabbed.
Normally when using selections for something like this, one also handles
losing the selection. So e.g. if we lost the selection we'd kill the
bus. This is how "--replace" works in window managers; twm and metacity
both have example code I know.
Probably not worth the time to code it.
Havoc
More information about the dbus
mailing list