From df01c98cc7e83f3336e501fcf2eeee52c95464fb Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 4 May 2003 08:54:24 +0000 Subject: 2003-05-04 Havoc Pennington * tools/dbus-launch.c: implement * bus/main.c (main), bus/bus.c (bus_context_new): implement --print-pid and --fork --- ChangeLog | 7 + bus/bus.c | 40 ++- bus/bus.h | 2 + bus/dbus-daemon-1.1.in | 16 +- bus/main.c | 76 +++++- bus/test.c | 2 +- configure.in | 12 +- tools/Makefile.am | 3 +- tools/dbus-launch.1 | 13 +- tools/dbus-launch.c | 672 ++++++++++++++++++++++++++++++++++++++++++++++++- 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 + + * 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 * 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 "" 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 -#include #include #include #include @@ -30,10 +29,53 @@ #include #include #include +#include +#include #ifdef DBUS_BUILD_X11 #include #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; } -- cgit