*
* 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 <config.h>
#include "dbus-launch.h"
#include <stdlib.h>
#include <ctype.h>
extern Display *xdisplay;
#endif
+/* PROCESSES
+ *
+ * If you are in a shell and run "dbus-launch myapp", here is what happens:
+ *
+ * shell [*]
+ * \- main() --exec--> myapp[*]
+ * \- "intermediate parent"
+ * \- bus-runner --exec--> dbus-daemon --fork
+ * \- babysitter[*] \- final dbus-daemon[*]
+ *
+ * Processes marked [*] survive the initial flurry of activity.
+ *
+ * If you run "dbus-launch --sh-syntax" then the diagram is the same, except
+ * that main() prints variables and exits 0 instead of exec'ing myapp.
+ *
+ * PIPES
+ *
+ * dbus-daemon --print-pid -> bus_pid_to_launcher_pipe -> main
+ * dbus-daemon --print-address -> bus_address_to_launcher_pipe -> main
+ * main -> bus_pid_to_babysitter_pipe -> babysitter
+ *
+ * The intermediate parent looks pretty useless at first glance. Its purpose
+ * is to avoid the bus-runner becoming a zombie: when the intermediate parent
+ * terminates, the bus-runner and babysitter are reparented to init, which
+ * reaps them if they have finished. We can't rely on main() to reap arbitrary
+ * children because it might exec myapp, after which it can't be relied on to
+ * reap its children. We *can* rely on main() to reap the intermediate parent,
+ * because that happens before it execs myapp.
+ *
+ * It's unclear why dbus-daemon needs to fork, but we explicitly tell it to
+ * for some reason, then wait for it. If we left it undefined, a forking
+ * dbus-daemon would get the parent process reparented to init and reaped
+ * when the intermediate parent terminated, and a non-forking dbus-daemon
+ * would get reparented to init and carry on there.
+ *
+ * myapp is exec'd by the process that initially ran main() so that it's
+ * the shell's child, so the shell knows how to do job control and stuff.
+ * This is desirable for the "dbus-launch an application" use-case, less so
+ * for the "dbus-launch a test suite in an isolated session" use-case.
+ */
+
static char* machine_uuid = NULL;
const char*
machine_uuid = xstrdup (uuid_arg);
}
+#ifdef DBUS_BUILD_X11
#define UUID_MAXLEN 40
/* Read the machine uuid from file if needed. Returns TRUE if machine_uuid is
* set after this function */
fclose(f);
return ret;
}
-
+#endif /* DBUS_BUILD_X11 */
void
verbose (const char *format,
...)
{
+#ifdef DBUS_ENABLE_VERBOSE_MODE
va_list args;
static int verbose = TRUE;
static int verbose_initted = FALSE;
va_start (args, format);
vfprintf (stderr, format, args);
va_end (args);
+#endif /* DBUS_ENABLE_VERBOSE_MODE */
}
static void
usage (int ecode)
{
- fprintf (stderr, "dbus-launch [--version] [--help] [--sh-syntax] [--csh-syntax] [--auto-syntax] [--exit-with-session]\n");
+ fprintf (stderr, "dbus-launch [--version] [--help] [--sh-syntax]"
+ " [--csh-syntax] [--auto-syntax] [--binary-syntax] [--close-stderr]"
+ " [--exit-with-session] [--autolaunch=MACHINEID]"
+ " [--config-file=FILENAME] [PROGRAM] [ARGS...]\n");
exit (ecode);
}
static pid_t bus_pid_to_kill = -1;
static void
-kill_bus()
+kill_bus(void)
{
verbose ("Killing message bus and exiting babysitter\n");
kill (bus_pid_to_kill, SIGTERM);
{
if (binary_syntax)
{
- write (1, bus_address, strlen (bus_address) + 1);
- write (1, &bus_pid, sizeof bus_pid);
- write (1, &bus_wid, sizeof bus_wid);
+ do_write (1, bus_address, strlen (bus_address) + 1);
+ do_write (1, &bus_pid, sizeof bus_pid);
+ do_write (1, &bus_wid, sizeof bus_wid);
return;
}
else if (c_shell_syntax)
#ifdef SIGHUP
case SIGHUP:
#endif
+ case SIGINT:
case SIGTERM:
got_sighup = TRUE;
break;
act.sa_flags = 0;
sigaction (SIGHUP, &act, NULL);
sigaction (SIGTERM, &act, NULL);
+ sigaction (SIGINT, &act, NULL);
#ifdef DBUS_BUILD_X11
x11_init();
else
tty_fd = -1;
- if (tty_fd >= 0)
- verbose ("stdin isatty(), monitoring it\n");
+ if (x_fd >= 0)
+ {
+ verbose ("session lifetime is defined by X, not monitoring stdin\n");
+ tty_fd = -1;
+ }
+ else if (tty_fd >= 0)
+ {
+ verbose ("stdin isatty(), monitoring it\n");
+ }
else
- verbose ("stdin was not a TTY, not monitoring it\n");
-
+ {
+ 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");
s = getenv ("DBUS_DEBUG_OUTPUT");
if (s == NULL || *s == '\0')
dup2 (dev_null_fd, 2);
+ close (dev_null_fd);
}
else
{
int binary_syntax,
int argc, char **argv, int remaining_args)
{
+ char *envvar = NULL;
+ char **args = NULL;
+
if (runprog)
{
- char *envvar;
- char **args;
int i;
envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") +
if (envvar == NULL || args == NULL)
goto oom;
- args[0] = xstrdup (runprog);
+ args[0] = xstrdup (runprog);
if (!args[0])
goto oom;
- for (i = 1; i <= (argc-remaining_args); i++)
- {
- size_t len = strlen (argv[remaining_args+i-1])+1;
- args[i] = malloc (len);
- if (!args[i])
- goto oom;
- strncpy (args[i], argv[remaining_args+i-1], len);
- }
- args[i] = NULL;
+ for (i = 1; i <= (argc-remaining_args); i++)
+ {
+ size_t len = strlen (argv[remaining_args+i-1])+1;
+ args[i] = malloc (len);
+ if (!args[i])
+ goto oom;
+ strncpy (args[i], argv[remaining_args+i-1], len);
+ }
+ args[i] = NULL;
- strcpy (envvar, "DBUS_SESSION_BUS_ADDRESS=");
- strcat (envvar, bus_address);
- putenv (envvar);
+ strcpy (envvar, "DBUS_SESSION_BUS_ADDRESS=");
+ strcat (envvar, bus_address);
+ putenv (envvar);
- execvp (runprog, args);
- fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno));
- exit (1);
+ execvp (runprog, args);
+ fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno));
+ exit (1);
}
else
{
print_variables (bus_address, bus_pid, bus_wid, c_shell_syntax,
- bourne_shell_syntax, binary_syntax);
+ bourne_shell_syntax, binary_syntax);
}
verbose ("dbus-launch exiting\n");
close (2);
exit (0);
oom:
+ if (envvar)
+ free (envvar);
+
+ if (args)
+ free (args);
+
fprintf (stderr, "Out of memory!");
exit (1);
}
int autolaunch = FALSE;
int requires_arg = FALSE;
int close_stderr = FALSE;
+ int kdbus = FALSE;
int i;
int ret;
int bus_pid_to_launcher_pipe[2];
exit_with_session = TRUE;
else if (strcmp (arg, "--close-stderr") == 0)
close_stderr = TRUE;
+ else if (strcmp (arg, "--kdbus") == 0)
+ kdbus = TRUE;
else if (strstr (arg, "--autolaunch=") == arg)
{
const char *s;
fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n"
"Cannot continue.\n");
exit (1);
-#else
+#else /* DBUS_BUILD_X11 */
+#ifndef DBUS_ENABLE_X11_AUTOLAUNCH
+ fprintf (stderr, "X11 autolaunch support disabled at compile time.\n");
+ exit (1);
+#else /* DBUS_ENABLE_X11_AUTOLAUNCH */
char *address;
pid_t pid;
long wid;
bourne_shell_syntax, binary_syntax, argc, argv, remaining_args);
exit (0);
}
+#endif /* DBUS_ENABLE_X11_AUTOLAUNCH */
}
- else if (read_machine_uuid_if_needed())
+ else if (read_machine_uuid_if_needed())
{
x11_init();
-#endif
+#endif /* DBUS_BUILD_X11 */
}
verbose ("Calling exec()\n");
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
/* exec from testdir */
if (getenv("DBUS_USE_TEST_BINARY") != NULL)
{
"Failed to execute test message bus daemon %s: %s. Will try again with the system path.\n",
TEST_BUS_BINARY, strerror (errno));
}
- #endif /* DBUS_BUILD_TESTS */
+ #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
- execl (DBUS_DAEMONDIR"/dbus-daemon",
+ if (kdbus)
+ {
+ execl (DBUS_DAEMONDIR"/dbus-daemon",
DBUS_DAEMONDIR"/dbus-daemon",
"--fork",
"--print-pid", write_pid_fd_as_string,
"--print-address", write_address_fd_as_string,
+ "--address=kdbus:",
config_file ? "--config-file" : "--session",
config_file, /* has to be last in this varargs list */
NULL);
+ }
+ else
+ {
+ execl (DBUS_DAEMONDIR"/dbus-daemon",
+ DBUS_DAEMONDIR"/dbus-daemon",
+ "--fork",
+ "--print-pid", write_pid_fd_as_string,
+ "--print-address", write_address_fd_as_string,
+ config_file ? "--config-file" : "--session",
+ config_file, /* has to be last in this varargs list */
+ NULL);
+ }
+
fprintf (stderr,
"Failed to execute message bus daemon %s: %s. Will try again without full path.\n",
* file and the dbus-daemon will not be in the install location during
* build time.
*/
- execlp ("dbus-daemon",
+ if (kdbus)
+ {
+ execlp ("dbus-daemon",
+ "dbus-daemon",
+ "--fork",
+ "--print-pid", write_pid_fd_as_string,
+ "--print-address", write_address_fd_as_string,
+ "--address=kdbus:",
+ config_file ? "--config-file" : "--session",
+ config_file, /* has to be last in this varargs list */
+ NULL);
+ }
+ else
+ {
+ execlp ("dbus-daemon",
"dbus-daemon",
"--fork",
"--print-pid", write_pid_fd_as_string,
config_file ? "--config-file" : "--session",
config_file, /* has to be last in this varargs list */
NULL);
+ }
fprintf (stderr,
"Failed to execute message bus daemon: %s\n",
char *end;
long wid = 0;
long val;
- int ret2;
verbose ("=== Parent dbus-launch continues\n");
close (bus_pid_to_launcher_pipe[READ_END]);
-#ifdef DBUS_BUILD_X11
+#ifdef DBUS_ENABLE_X11_AUTOLAUNCH
if (xdisplay != NULL)
{
+ int ret2;
+
verbose("Saving x11 address\n");
ret2 = x11_save_address (bus_address, bus_pid, &wid);
/* Only get an existing dbus session when autolaunching */