summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-05-04 08:54:24 +0000
committerHavoc Pennington <hp@redhat.com>2003-05-04 08:54:24 +0000
commitdf01c98cc7e83f3336e501fcf2eeee52c95464fb (patch)
treee92ccc82056908b25eb9cab6e9ad763b8febd9dc
parentc0158234d046381a6bc8c004c82577576977d0d7 (diff)
2003-05-04 Havoc Pennington <hp@pobox.com>
* tools/dbus-launch.c: implement * bus/main.c (main), bus/bus.c (bus_context_new): implement --print-pid and --fork
-rw-r--r--ChangeLog7
-rw-r--r--bus/bus.c40
-rw-r--r--bus/bus.h2
-rw-r--r--bus/dbus-daemon-1.1.in16
-rw-r--r--bus/main.c76
-rw-r--r--bus/test.c2
-rw-r--r--configure.in12
-rw-r--r--tools/Makefile.am3
-rw-r--r--tools/dbus-launch.113
-rw-r--r--tools/dbus-launch.c672
10 files changed, 824 insertions, 19 deletions
diff --git a/ChangeLog b/ChangeLog
index ac827951..a3b0ce6a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2003-05-04 Havoc Pennington <hp@pobox.com>
+
+ * tools/dbus-launch.c: implement
+
+ * bus/main.c (main), bus/bus.c (bus_context_new):
+ implement --print-pid and --fork
+
2003-05-03 Havoc Pennington <hp@redhat.com>
* dbus/dbus-address.c (dbus_parse_address): fix bug when a key in
diff --git a/bus/bus.c b/bus/bus.c
index cabc0b18..85d737da 100644
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -280,7 +280,9 @@ setup_server (BusContext *context,
BusContext*
bus_context_new (const DBusString *config_file,
+ dbus_bool_t force_fork,
int print_addr_fd,
+ int print_pid_fd,
DBusError *error)
{
BusContext *context;
@@ -540,7 +542,7 @@ bus_context_new (const DBusString *config_file,
_dbus_assert (context->policy != NULL);
/* Now become a daemon if appropriate */
- if (bus_config_parser_get_fork (parser))
+ if (force_fork || bus_config_parser_get_fork (parser))
{
DBusString u;
@@ -567,6 +569,42 @@ bus_context_new (const DBusString *config_file,
/* keep around the pid filename so we can delete it later */
context->pidfile = _dbus_strdup (pidfile);
+ /* Write PID if requested */
+ if (print_pid_fd >= 0)
+ {
+ DBusString pid;
+ int bytes;
+
+ if (!_dbus_string_init (&pid))
+ {
+ BUS_SET_OOM (error);
+ goto failed;
+ }
+
+ if (!_dbus_string_append_int (&pid, _dbus_getpid ()) ||
+ !_dbus_string_append (&pid, "\n"))
+ {
+ _dbus_string_free (&pid);
+ BUS_SET_OOM (error);
+ goto failed;
+ }
+
+ bytes = _dbus_string_get_length (&pid);
+ if (_dbus_write (print_pid_fd, &pid, 0, bytes) != bytes)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Printing message bus PID: %s\n",
+ _dbus_strerror (errno));
+ _dbus_string_free (&pid);
+ goto failed;
+ }
+
+ if (print_pid_fd > 2)
+ _dbus_close (print_pid_fd, NULL);
+
+ _dbus_string_free (&pid);
+ }
+
/* Here we change our credentials if required,
* as soon as we've set up our sockets and pidfile
*/
diff --git a/bus/bus.h b/bus/bus.h
index 747e009f..8f32d7a9 100644
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -57,7 +57,9 @@ typedef struct
} BusLimits;
BusContext* bus_context_new (const DBusString *config_file,
+ dbus_bool_t force_fork,
int print_addr_fd,
+ int print_pid_fd,
DBusError *error);
void bus_context_shutdown (BusContext *context);
void bus_context_ref (BusContext *context);
diff --git a/bus/dbus-daemon-1.1.in b/bus/dbus-daemon-1.1.in
index 3339aebc..73a88c90 100644
--- a/bus/dbus-daemon-1.1.in
+++ b/bus/dbus-daemon-1.1.in
@@ -9,7 +9,7 @@ dbus-daemon-1 \- Message bus daemon
.PP
.B dbus-daemon-1
dbus-daemon-1 [\-\-version] [\-\-session] [\-\-system] [\-\-config-file=FILE]
-[\-\-print-address[=DESCRIPTOR]]
+[\-\-print-address[=DESCRIPTOR]] [\-\-print-pid[=DESCRIPTOR]] [\-\-fork]
.SH DESCRIPTION
@@ -62,11 +62,22 @@ The following options are supported:
.I "--config-file=FILE"
Use the given configuration file.
.TP
+.I "--fork"
+Force the message bus to fork and become a daemon, even if
+the configuration file does not specify that it should.
+In most contexts the configuration file already gets this
+right, though.
+.TP
.I "--print-address[=DESCRIPTOR]"
Print the address of the message bus to standard output, or
to the given file descriptor. This is used by programs that
launch the message bus.
.TP
+.I "--print-pid[=DESCRIPTOR]"
+Print the process ID of the message bus to standard output, or
+to the given file descriptor. This is used by programs that
+launch the message bus.
+.TP
.I "--session"
Use the standard configuration file for the per-login-session message
bus.
@@ -185,7 +196,8 @@ privileges for writing.
.PP
If present, the bus daemon becomes a real daemon (forks
-into the background, etc.).
+into the background, etc.). This is generally used
+rather than the \-\-fork command line option.
.TP
.I "<listen>"
diff --git a/bus/main.c b/bus/main.c
index de78368b..8c605be3 100644
--- a/bus/main.c
+++ b/bus/main.c
@@ -47,7 +47,7 @@ signal_handler (int sig)
static void
usage (void)
{
- fprintf (stderr, "dbus-daemon-1 [--version] [--session] [--system] [--config-file=FILE] [--print-address[=DESCRIPTOR]]\n");
+ fprintf (stderr, "dbus-daemon-1 [--version] [--session] [--system] [--config-file=FILE] [--print-address[=DESCRIPTOR]] [--print-pid[=DESCRIPTOR]] [--fork]\n");
exit (1);
}
@@ -86,24 +86,45 @@ check_two_addr_descriptors (const DBusString *addr_fd,
}
}
+static void
+check_two_pid_descriptors (const DBusString *pid_fd,
+ const char *extra_arg)
+{
+ if (_dbus_string_get_length (pid_fd) > 0)
+ {
+ fprintf (stderr, "--%s specified but printing pid to %s already requested\n",
+ extra_arg, _dbus_string_get_const_data (pid_fd));
+ exit (1);
+ }
+}
+
int
main (int argc, char **argv)
{
DBusError error;
DBusString config_file;
DBusString addr_fd;
+ DBusString pid_fd;
const char *prev_arg;
int print_addr_fd;
+ int print_pid_fd;
int i;
dbus_bool_t print_address;
+ dbus_bool_t print_pid;
+ dbus_bool_t force_fork;
if (!_dbus_string_init (&config_file))
return 1;
if (!_dbus_string_init (&addr_fd))
return 1;
+
+ if (!_dbus_string_init (&pid_fd))
+ return 1;
print_address = FALSE;
+ print_pid = FALSE;
+ force_fork = FALSE;
prev_arg = NULL;
i = 1;
@@ -117,6 +138,8 @@ main (int argc, char **argv)
usage ();
else if (strcmp (arg, "--version") == 0)
version ();
+ else if (strcmp (arg, "--fork") == 0)
+ force_fork = TRUE;
else if (strcmp (arg, "--system") == 0)
{
check_two_config_files (&config_file, "system");
@@ -179,6 +202,32 @@ main (int argc, char **argv)
}
else if (strcmp (arg, "--print-address") == 0)
print_address = TRUE; /* and we'll get the next arg if appropriate */
+ else if (strstr (arg, "--print-pid=") == arg)
+ {
+ const char *desc;
+
+ check_two_pid_descriptors (&pid_fd, "print-pid");
+
+ desc = strchr (arg, '=');
+ ++desc;
+
+ if (!_dbus_string_append (&pid_fd, desc))
+ exit (1);
+
+ print_pid = TRUE;
+ }
+ else if (prev_arg &&
+ strcmp (prev_arg, "--print-pid") == 0)
+ {
+ check_two_pid_descriptors (&pid_fd, "print-pid");
+
+ if (!_dbus_string_append (&pid_fd, arg))
+ exit (1);
+
+ print_pid = TRUE;
+ }
+ else if (strcmp (arg, "--print-pid") == 0)
+ print_pid = TRUE; /* and we'll get the next arg if appropriate */
else
usage ();
@@ -213,9 +262,32 @@ main (int argc, char **argv)
print_addr_fd = val;
}
}
+
+ print_pid_fd = -1;
+ if (print_pid)
+ {
+ print_pid_fd = 1; /* stdout */
+ if (_dbus_string_get_length (&pid_fd) > 0)
+ {
+ long val;
+ int end;
+ if (!_dbus_string_parse_int (&pid_fd, 0, &val, &end) ||
+ end != _dbus_string_get_length (&pid_fd) ||
+ val < 0 || val > _DBUS_INT_MAX)
+ {
+ fprintf (stderr, "Invalid file descriptor: \"%s\"\n",
+ _dbus_string_get_const_data (&pid_fd));
+ exit (1);
+ }
+
+ print_pid_fd = val;
+ }
+ }
dbus_error_init (&error);
- context = bus_context_new (&config_file, print_addr_fd, &error);
+ context = bus_context_new (&config_file, force_fork,
+ print_addr_fd, print_pid_fd,
+ &error);
_dbus_string_free (&config_file);
if (context == NULL)
{
diff --git a/bus/test.c b/bus/test.c
index 012d1d0e..f8d4c5f3 100644
--- a/bus/test.c
+++ b/bus/test.c
@@ -377,7 +377,7 @@ bus_context_new_test (const DBusString *test_data_dir,
}
dbus_error_init (&error);
- context = bus_context_new (&config_file, -1, &error);
+ context = bus_context_new (&config_file, FALSE, -1, -1, &error);
if (context == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (&error);
diff --git a/configure.in b/configure.in
index b36aeba9..18cb519e 100644
--- a/configure.in
+++ b/configure.in
@@ -440,10 +440,6 @@ AC_SUBST(DBUS_QT_LIBS)
### X11 detection
AC_PATH_XTRA
-DBUS_X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
-DBUS_X_CFLAGS="$X_CFLAGS"
-AC_SUBST(DBUS_X_CFLAGS)
-AC_SUBST(DBUS_X_LIBS)
## for now enable_x11 just tracks have_x11,
## there's no --enable-x11
@@ -457,8 +453,16 @@ fi
if test x$enable_x11 = xyes ; then
AC_DEFINE(DBUS_BUILD_X11,1,[Build X11-dependent code])
+ DBUS_X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
+ DBUS_X_CFLAGS="$X_CFLAGS"
+else
+ DBUS_X_LIBS=
+ DBUS_X_CFLAGS=
fi
+AC_SUBST(DBUS_X_CFLAGS)
+AC_SUBST(DBUS_X_LIBS)
+
### Documentation
AC_PATH_PROG(DOXYGEN, doxygen, no)
diff --git a/tools/Makefile.am b/tools/Makefile.am
index c33caae7..60b9ddab 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -19,7 +19,8 @@ dbus_launch_SOURCES= \
dbus_send_LDADD= $(top_builddir)/dbus/libdbus-1.la
dbus_monitor_LDADD= $(top_builddir)/glib/libdbus-glib-1.la
-dbus_launch_LDADD= $(top_builddir)/dbus/libdbus-1.la
+## dbus-launch doesn't link to anything
+dbus_launch_LDADD= $(DBUS_X_LIBS)
man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1
EXTRA_DIST = $(man_MANS)
diff --git a/tools/dbus-launch.1 b/tools/dbus-launch.1
index 9342423d..c0fb03f6 100644
--- a/tools/dbus-launch.1
+++ b/tools/dbus-launch.1
@@ -24,14 +24,19 @@ about D-BUS. See also the man page for \fIdbus-daemon-1\fP.
.PP
Here is an example of how to use \fIdbus-launch\fP with an
-sh-compatible shell:
+sh-compatible shell to start the per-session bus daemon:
.nf
- VARIABLES=`dbus-launch`
- eval $VARIABLES
- echo "D-BUS per-session daemon address is: $DBUS_SESSION_BUS_ADDRESS"
+ ## test for an existing bus daemon, just to be safe
+ if test -z "$DBUS_SESSION_BUS_ADDRESS" ; then
+ ## if not found, launch a new one
+ eval `dbus-launch --exit-with-session`
+ echo "D-BUS per-session daemon address is: $DBUS_SESSION_BUS_ADDRESS"
+ export DBUS_SESSION_BUS_ADDRESS
+ fi
.fi
+You might run something like that in your login scripts.
.SH OPTIONS
The following options are supported:
diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c
index b21c7e9d..f0b9e589 100644
--- a/tools/dbus-launch.c
+++ b/tools/dbus-launch.c
@@ -21,7 +21,6 @@
*
*/
#include <config.h>
-#include <dbus/dbus.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
@@ -30,10 +29,53 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <signal.h>
+#include <stdarg.h>
#ifdef DBUS_BUILD_X11
#include <X11/Xlib.h>
#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
+verbose (const char *format,
+ ...)
+{
+ va_list args;
+ static int verbose = TRUE;
+ static int verbose_initted = FALSE;
+
+ /* things are written a bit oddly here so that
+ * in the non-verbose case we just have the one
+ * conditional and return immediately.
+ */
+ if (!verbose)
+ return;
+
+ if (!verbose_initted)
+ {
+ verbose = getenv ("DBUS_VERBOSE") != NULL;
+ verbose_initted = TRUE;
+ if (!verbose)
+ return;
+ }
+
+ fprintf (stderr, "%lu: ", (unsigned long) getpid ());
+
+ va_start (args, format);
+ vfprintf (stderr, format, args);
+ va_end (args);
+}
+
static void
usage (void)
{
@@ -52,13 +94,462 @@ version (void)
exit (0);
}
+typedef enum
+{
+ READ_STATUS_OK, /**< Read succeeded */
+ READ_STATUS_ERROR, /**< Some kind of error */
+ READ_STATUS_EOF /**< EOF returned */
+} ReadStatus;
+
+static ReadStatus
+read_line (int fd,
+ char *buf,
+ size_t maxlen)
+{
+ size_t bytes = 0;
+ ReadStatus retval;
+
+ memset (buf, '\0', maxlen);
+ maxlen -= 1; /* ensure nul term */
+
+ retval = READ_STATUS_OK;
+
+ while (TRUE)
+ {
+ size_t chunk;
+ size_t to_read;
+
+ again:
+ to_read = maxlen - bytes;
+
+ if (to_read == 0)
+ break;
+
+ chunk = read (fd,
+ buf + bytes,
+ to_read);
+ if (chunk < 0 && errno == EINTR)
+ goto again;
+
+ if (chunk < 0)
+ {
+ retval = READ_STATUS_ERROR;
+ break;
+ }
+ else if (chunk == 0)
+ {
+ retval = READ_STATUS_EOF;
+ break; /* EOF */
+ }
+ else /* chunk > 0 */
+ bytes += chunk;
+ }
+
+ if (retval == READ_STATUS_EOF &&
+ bytes > 0)
+ retval = READ_STATUS_OK;
+
+ /* whack newline */
+ if (retval != READ_STATUS_ERROR &&
+ bytes > 0 &&
+ buf[bytes-1] == '\n')
+ buf[bytes-1] = '\0';
+
+ return retval;
+}
+
+static ReadStatus
+read_pid (int fd,
+ pid_t *buf)
+{
+ size_t bytes = 0;
+ ReadStatus retval;
+
+ retval = READ_STATUS_OK;
+
+ while (TRUE)
+ {
+ size_t chunk;
+ size_t to_read;
+
+ again:
+ to_read = sizeof (pid_t) - bytes;
+
+ if (to_read == 0)
+ break;
+
+ chunk = read (fd,
+ ((char*)buf) + bytes,
+ to_read);
+ if (chunk < 0 && errno == EINTR)
+ goto again;
+
+ if (chunk < 0)
+ {
+ retval = READ_STATUS_ERROR;
+ break;
+ }
+ else if (chunk == 0)
+ {
+ retval = READ_STATUS_EOF;
+ break; /* EOF */
+ }
+ else /* chunk > 0 */
+ bytes += chunk;
+ }
+
+ return retval;
+}
+
+static void
+do_write (int fd, const void *buf, size_t count)
+{
+ size_t bytes_written;
+ int ret;
+
+ bytes_written = 0;
+
+ again:
+
+ ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
+
+ if (ret < 0)
+ {
+ if (errno == EINTR)
+ goto again;
+ else
+ {
+ fprintf (stderr, "Failed to write data to pipe!\n");
+ exit (1); /* give up, we suck */
+ }
+ }
+ else
+ bytes_written += ret;
+
+ if (bytes_written < count)
+ goto again;
+}
+
+static void
+write_pid (int fd,
+ pid_t pid)
+{
+ do_write (fd, &pid, sizeof (pid));
+}
+
+static int
+do_waitpid (pid_t pid)
+{
+ int ret;
+
+ again:
+ ret = waitpid (pid, NULL, 0);
+
+ if (ret < 0 &&
+ errno == EINTR)
+ goto again;
+
+ return ret;
+}
+
+static pid_t bus_pid_to_kill = -1;
+
+static void
+kill_bus_and_exit (void)
+{
+ verbose ("Killing message bus and exiting babysitter\n");
+
+ /* in case these point to any NFS mounts, get rid of them immediately */
+ close (0);
+ close (1);
+ close (2);
+
+ kill (bus_pid_to_kill, SIGTERM);
+ sleep (3);
+ kill (bus_pid_to_kill, SIGKILL);
+
+ exit (0);
+}
+
+#ifdef DBUS_BUILD_X11
+static int
+x_io_error_handler (Display *xdisplay)
+{
+ verbose ("X IO error\n");
+ kill_bus_and_exit ();
+}
+#endif
+
+static int got_sighup = FALSE;
+
+static void
+signal_handler (int sig)
+{
+ switch (sig)
+ {
+ case SIGHUP:
+ got_sighup = TRUE;
+ break;
+ }
+}
+
+static void
+kill_bus_when_session_ends (void)
+{
+ int tty_fd;
+ int x_fd;
+ fd_set read_set;
+ fd_set err_set;
+ int ret;
+ struct sigaction act;
+ sigset_t empty_mask;
+#ifdef DBUS_BUILD_X11
+ Display *xdisplay;
+#endif
+
+ /* install SIGHUP handler */
+ got_sighup = FALSE;
+ sigemptyset (&empty_mask);
+ act.sa_handler = signal_handler;
+ act.sa_mask = empty_mask;
+ act.sa_flags = 0;
+ sigaction (SIGHUP, &act, 0);
+
+#ifdef DBUS_BUILD_X11
+ xdisplay = XOpenDisplay (NULL);
+ 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
+
+ if (isatty (0))
+ tty_fd = 0;
+ else
+ tty_fd = -1;
+
+ if (tty_fd >= 0)
+ verbose ("stdin isatty(), monitoring it\n");
+ else
+ verbose ("stdin was not a TTY, not monitoring it\n");
+
+ if (tty_fd < 0 && x_fd < 0)
+ {
+ fprintf (stderr, "No terminal on standard input and no X display; cannot attach message bus to session lifetime\n");
+ exit (1);
+ }
+
+ while (TRUE)
+ {
+ FD_ZERO (&read_set);
+ FD_ZERO (&err_set);
+
+ if (tty_fd >= 0)
+ {
+ FD_SET (tty_fd, &read_set);
+ FD_SET (tty_fd, &err_set);
+ }
+
+ if (x_fd >= 0)
+ {
+ FD_SET (x_fd, &read_set);
+ FD_SET (x_fd, &err_set);
+ }
+
+ ret = select (MAX (tty_fd, x_fd) + 1,
+ &read_set, NULL, &err_set, NULL);
+
+ if (got_sighup)
+ {
+ verbose ("Got SIGHUP, exiting\n");
+ kill_bus_and_exit ();
+ }
+
+#ifdef DBUS_BUILD_X11
+ /* Dump events on the floor, and let
+ * IO error handler run if we lose
+ * the X connection
+ */
+ if (x_fd >= 0)
+ 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);
+ }
+ }
+#endif
+
+ if (tty_fd >= 0)
+ {
+ if (FD_ISSET (tty_fd, &read_set))
+ {
+ int bytes_read;
+ char discard[512];
+
+ verbose ("TTY ready for reading\n");
+
+ bytes_read = read (tty_fd, discard, sizeof (discard));
+
+ verbose ("Read %d bytes from TTY errno = %d\n",
+ bytes_read, errno);
+
+ if (bytes_read == 0)
+ kill_bus_and_exit (); /* EOF */
+ else if (bytes_read < 0 && errno != EINTR)
+ {
+ /* This shouldn't happen I don't think; to avoid
+ * spinning on the fd forever we exit.
+ */
+ fprintf (stderr, "dbus-launch: error reading from stdin: %s\n",
+ strerror (errno));
+ kill_bus_and_exit ();
+ }
+ }
+ else if (FD_ISSET (tty_fd, &err_set))
+ {
+ verbose ("TTY has error condition\n");
+
+ kill_bus_and_exit ();
+ }
+ }
+ }
+}
+
+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 ret;
+#define MAX_PID_LEN 64
+ char buf[MAX_PID_LEN];
+ long val;
+ char *end;
+
+ /* We chdir ("/") since we are persistent and daemon-like, and fork
+ * again so dbus-launch can reap the parent. However, we don't
+ * setsid() or close fd 0,1,2 because the idea is to remain attached
+ * to the tty and the X server in order to kill the message bus
+ * when the session ends.
+ */
+
+ if (chdir ("/") < 0)
+ {
+ fprintf (stderr, "Could not change to root directory: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+
+ ret = fork ();
+
+ if (ret < 0)
+ {
+ fprintf (stderr, "fork() failed in babysitter: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+
+ if (ret > 0)
+ {
+ /* Parent reaps pre-fork part of bus daemon, then exits and is
+ * reaped so the babysitter isn't a zombie
+ */
+
+ verbose ("=== Babysitter's intermediate parent continues again\n");
+
+ if (do_waitpid (child_pid) < 0)
+ {
+ /* shouldn't happen */
+ fprintf (stderr, "Failed waitpid() waiting for bus daemon's parent\n");
+ exit (1);
+ }
+
+ verbose ("Babysitter's intermediate parent exiting\n");
+
+ exit (0);
+ }
+
+ /* 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))
+ {
+ 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_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;
+ * we connect to X display and tty and wait to
+ * kill bus if requested.
+ */
+
+ kill_bus_when_session_ends ();
+ }
+
+ verbose ("Babysitter exiting\n");
+
+ exit (0);
+}
+
+#define READ_END 0
+#define WRITE_END 1
+
int
main (int argc, char **argv)
{
const char *prev_arg;
- dbus_bool_t exit_with_session;
+ int exit_with_session;
int i;
-
+ int ret;
+ int bus_pid_to_launcher_pipe[2];
+ int bus_pid_to_babysitter_pipe[2];
+ int bus_address_to_launcher_pipe[2];
+
exit_with_session = FALSE;
prev_arg = NULL;
@@ -82,8 +573,181 @@ main (int argc, char **argv)
++i;
}
+
+ verbose ("--exit-with-session provided\n");
+
+ if (pipe (bus_pid_to_launcher_pipe) < 0 ||
+ pipe (bus_address_to_launcher_pipe) < 0)
+ {
+ fprintf (stderr,
+ "Failed to create pipe: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+
+ bus_pid_to_babysitter_pipe[READ_END] = -1;
+ bus_pid_to_babysitter_pipe[WRITE_END] = -1;
-
+ ret = fork ();
+ if (ret < 0)
+ {
+ fprintf (stderr, "Failed to fork: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+
+ if (ret == 0)
+ {
+ /* Child */
+#define MAX_FD_LEN 64
+ char write_pid_fd_as_string[MAX_FD_LEN];
+ 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)
+ {
+ fprintf (stderr, "Failed to fork: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+
+ if (ret > 0)
+ {
+ /* In babysitter */
+ verbose ("=== Babysitter's intermediate parent continues\n");
+
+ close (bus_pid_to_launcher_pipe[READ_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]);
+
+ /* babysit() will fork *again*
+ * and will also reap the pre-forked bus
+ * daemon
+ */
+ babysit (exit_with_session, ret,
+ bus_pid_to_babysitter_pipe[READ_END],
+ bus_pid_to_launcher_pipe[WRITE_END]);
+ exit (0);
+ }
+
+ verbose ("=== Bus exec process created\n");
+
+ /* Now we are the bus process (well, almost;
+ * dbus-daemon-1 itself forks again)
+ */
+ 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]);
+
+ sprintf (write_pid_fd_as_string,
+ "%d", bus_pid_to_babysitter_pipe[WRITE_END]);
+
+ sprintf (write_address_fd_as_string,
+ "%d", bus_address_to_launcher_pipe[WRITE_END]);
+
+ verbose ("Calling exec()\n");
+
+ execlp ("dbus-daemon-1",
+ "dbus-daemon-1",
+ "--fork",
+ "--session",
+ "--print-pid", write_pid_fd_as_string,
+ "--print-address", write_address_fd_as_string,
+ NULL);
+
+ fprintf (stderr,
+ "Failed to execute message bus daemon: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+ else
+ {
+ /* Parent */
+#define MAX_ADDR_LEN 512
+ pid_t bus_pid;
+ char bus_address[MAX_ADDR_LEN];
+
+ verbose ("=== Parent dbus-launch continues\n");
+
+ close (bus_pid_to_launcher_pipe[WRITE_END]);
+ close (bus_address_to_launcher_pipe[WRITE_END]);
+
+ verbose ("Waiting for babysitter's intermediate parent\n");
+
+ /* Immediately reap parent of babysitter
+ * (which was created just for us to reap)
+ */
+ if (do_waitpid (ret) < 0)
+ {
+ fprintf (stderr, "Failed to waitpid() for babysitter intermediate process: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+
+ verbose ("Reading address from bus\n");
+
+ /* Read the pipe data, print, and exit */
+ switch (read_line (bus_address_to_launcher_pipe[READ_END],
+ bus_address, MAX_ADDR_LEN))
+ {
+ 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;
+ }
+
+ 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;
+ }
+
+ close (bus_pid_to_launcher_pipe[READ_END]);
+
+ printf ("DBUS_SESSION_BUS_ADDRESS='%s'\n",
+ bus_address);
+
+ printf ("DBUS_SESSION_BUS_PID=%ld\n",
+ (long) bus_pid);
+
+ verbose ("dbus-launch exiting\n");
+
+ exit (0);
+ }
return 0;
}