X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tools%2Fdbus-launch.c;h=2a2abbbf8572c5b0ddd5b586303515b9ff6d096e;hb=16ed767007722d7450e6f5a4e23fff0166f466dc;hp=9f4c94ab3f580a2ebe3a7d29462f2fef802b9b77;hpb=d229e579a314c6b893e0a92730f0bf644b4eabcd;p=platform%2Fupstream%2Fdbus.git diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c index 9f4c94a..2a2abbb 100644 --- a/tools/dbus-launch.c +++ b/tools/dbus-launch.c @@ -18,11 +18,14 @@ * * 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 #include "dbus-launch.h" #include +#include #include #include #include @@ -40,6 +43,47 @@ 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* @@ -61,10 +105,55 @@ save_machine_uuid (const char *uuid_arg) 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 */ +static int +read_machine_uuid_if_needed (void) +{ + FILE *f; + char uuid[UUID_MAXLEN]; + size_t len; + int ret = FALSE; + + if (machine_uuid != NULL) + return TRUE; + + f = fopen (DBUS_MACHINE_UUID_FILE, "r"); + if (f == NULL) + return FALSE; + + if (fgets (uuid, UUID_MAXLEN, f) == NULL) + goto out; + + len = strlen (uuid); + if (len < 32) + goto out; + + /* rstrip the read uuid */ + while (len > 31 && isspace(uuid[len - 1])) + len--; + + if (len != 32) + goto out; + + uuid[len] = '\0'; + machine_uuid = xstrdup (uuid); + verbose ("UID: %s\n", machine_uuid); + ret = TRUE; + +out: + 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; @@ -89,12 +178,16 @@ verbose (const char *format, 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); } @@ -290,19 +383,24 @@ do_waitpid (pid_t pid) static pid_t bus_pid_to_kill = -1; +static void +kill_bus(void) +{ + verbose ("Killing message bus and exiting babysitter\n"); + kill (bus_pid_to_kill, SIGTERM); + sleep (3); + kill (bus_pid_to_kill, SIGKILL); +} + void kill_bus_and_exit (int exitcode) { - 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); + kill_bus(); exit (exitcode); } @@ -314,9 +412,9 @@ print_variables (const char *bus_address, pid_t bus_pid, long bus_wid, { 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) @@ -353,7 +451,10 @@ signal_handler (int sig) { switch (sig) { +#ifdef SIGHUP case SIGHUP: +#endif + case SIGINT: case SIGTERM: got_sighup = TRUE; break; @@ -378,6 +479,7 @@ kill_bus_when_session_ends (void) act.sa_flags = 0; sigaction (SIGHUP, &act, NULL); sigaction (SIGTERM, &act, NULL); + sigaction (SIGINT, &act, NULL); #ifdef DBUS_BUILD_X11 x11_init(); @@ -396,11 +498,20 @@ kill_bus_when_session_ends (void) 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"); @@ -409,6 +520,17 @@ kill_bus_when_session_ends (void) while (TRUE) { +#ifdef DBUS_BUILD_X11 + /* Dump events on the floor, and let + * IO error handler run if we lose + * the X connection. It's important to + * run this before going into select() since + * we might have queued outgoing messages or + * events. + */ + x11_handle_event (); +#endif + FD_ZERO (&read_set); FD_ZERO (&err_set); @@ -423,7 +545,7 @@ kill_bus_when_session_ends (void) FD_SET (x_fd, &read_set); FD_SET (x_fd, &err_set); } - + select (MAX (tty_fd, x_fd) + 1, &read_set, NULL, &err_set, NULL); @@ -434,15 +556,12 @@ kill_bus_when_session_ends (void) } #ifdef DBUS_BUILD_X11 - /* Dump events on the floor, and let - * IO error handler run if we lose - * the X connection + /* Events will be processed before we select again */ 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)); - x11_handle_event (); #endif if (tty_fd >= 0) @@ -520,6 +639,7 @@ babysit (int exit_with_session, s = getenv ("DBUS_DEBUG_OUTPUT"); if (s == NULL || *s == '\0') dup2 (dev_null_fd, 2); + close (dev_null_fd); } else { @@ -621,6 +741,70 @@ do_close_stderr (void) close (fd); } +static void +pass_info (const char *runprog, const char *bus_address, pid_t bus_pid, + long bus_wid, int c_shell_syntax, int bourne_shell_syntax, + int binary_syntax, + int argc, char **argv, int remaining_args) +{ + char *envvar = NULL; + char **args = NULL; + + if (runprog) + { + int i; + + envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") + + strlen (bus_address) + 1); + args = malloc (sizeof (char *) * ((argc-remaining_args)+2)); + + if (envvar == NULL || args == NULL) + goto oom; + + 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; + + 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); + } + else + { + print_variables (bus_address, bus_pid, bus_wid, c_shell_syntax, + bourne_shell_syntax, binary_syntax); + } + verbose ("dbus-launch exiting\n"); + + fflush (stdout); + fflush (stderr); + close (1); + close (2); + exit (0); +oom: + if (envvar) + free (envvar); + + if (args) + free (args); + + fprintf (stderr, "Out of memory!"); + exit (1); +} + #define READ_END 0 #define WRITE_END 1 @@ -639,6 +823,7 @@ main (int argc, char **argv) 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]; @@ -675,6 +860,8 @@ main (int argc, char **argv) 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; @@ -790,7 +977,11 @@ main (int argc, char **argv) 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; @@ -801,16 +992,6 @@ main (int argc, char **argv) exit (1); } - /* FIXME right now autolaunch always does print_variables(), but it should really - * exec the child program instead if a child program was specified. For now - * we just exit if this conflict arises. - */ - if (runprog) - { - fprintf (stderr, "Currently --autolaunch does not support running a program\n"); - exit (1); - } - verbose ("Autolaunch enabled (using X11).\n"); if (!exit_with_session) { @@ -831,15 +1012,21 @@ main (int argc, char **argv) } if (address != NULL) - { + { verbose ("dbus-daemon is already running. Returning existing parameters.\n"); - print_variables (address, pid, wid, c_shell_syntax, - bourne_shell_syntax, binary_syntax); + pass_info (runprog, address, pid, wid, c_shell_syntax, + bourne_shell_syntax, binary_syntax, argc, argv, remaining_args); exit (0); } -#endif +#endif /* DBUS_ENABLE_X11_AUTOLAUNCH */ + } + else if (read_machine_uuid_if_needed()) + { + x11_init(); +#endif /* DBUS_BUILD_X11 */ } + if (pipe (bus_pid_to_launcher_pipe) < 0 || pipe (bus_address_to_launcher_pipe) < 0 || pipe (bus_pid_to_babysitter_pipe) < 0) @@ -865,6 +1052,10 @@ main (int argc, char **argv) char write_pid_fd_as_string[MAX_FD_LEN]; char write_address_fd_as_string[MAX_FD_LEN]; +#ifdef DBUS_BUILD_X11 + xdisplay = NULL; +#endif + if (close_stderr) do_close_stderr (); @@ -918,7 +1109,7 @@ main (int argc, char **argv) verbose ("Calling exec()\n"); -#ifdef DBUS_BUILD_TESTS +#ifdef DBUS_ENABLE_EMBEDDED_TESTS /* exec from testdir */ if (getenv("DBUS_USE_TEST_BINARY") != NULL) { @@ -935,16 +1126,32 @@ main (int argc, char **argv) "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", @@ -956,14 +1163,29 @@ main (int argc, char **argv) * 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, + "--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\n", @@ -980,7 +1202,6 @@ main (int argc, char **argv) char *end; long wid = 0; long val; - int ret2; verbose ("=== Parent dbus-launch continues\n"); @@ -1051,38 +1272,38 @@ main (int argc, char **argv) close (bus_pid_to_launcher_pipe[READ_END]); -#ifdef DBUS_BUILD_X11 - /* FIXME the runprog == NULL is broken - we need to launch the runprog with the existing bus, - * instead of just doing print_variables() if there's an existing bus. - */ - if (xdisplay != NULL && runprog == NULL) +#ifdef DBUS_ENABLE_X11_AUTOLAUNCH + if (xdisplay != NULL) { + int ret2; + + verbose("Saving x11 address\n"); ret2 = x11_save_address (bus_address, bus_pid, &wid); - if (ret2 == 0) + /* Only get an existing dbus session when autolaunching */ + if (autolaunch) { - /* another window got added. Return its address */ - char *address; - pid_t pid; - long wid; - - if (x11_get_address (&address, &pid, &wid) && address != NULL) + if (ret2 == 0) { - verbose ("dbus-daemon is already running. Returning existing parameters.\n"); - print_variables (address, pid, wid, c_shell_syntax, - bourne_shell_syntax, binary_syntax); - free (address); - + char *address = NULL; + /* another window got added. Return its address */ bus_pid_to_kill = bus_pid; - kill_bus_and_exit (0); + if (x11_get_address (&address, &bus_pid, &wid) + && address != NULL) + { + verbose ("dbus-daemon is already running. Returning existing parameters.\n"); + /* Kill the old bus */ + kill_bus(); + pass_info (runprog, address, bus_pid, wid, + c_shell_syntax, bourne_shell_syntax, binary_syntax, + argc, argv, remaining_args); + } + } + if (ret2 < 0) + { + fprintf (stderr, "Error saving bus information.\n"); + bus_pid_to_kill = bus_pid; + kill_bus_and_exit (1); } - - /* if failed, fall through */ - } - if (ret2 <= 0) - { - fprintf (stderr, "Error saving bus information.\n"); - bus_pid_to_kill = bus_pid; - kill_bus_and_exit (1); } } #endif @@ -1091,56 +1312,9 @@ main (int argc, char **argv) write_pid (bus_pid_to_babysitter_pipe[WRITE_END], bus_pid); close (bus_pid_to_babysitter_pipe[WRITE_END]); - if (runprog) - { - char *envvar; - char **args; - - envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") + strlen (bus_address) + 1); - args = malloc (sizeof (char *) * ((argc-remaining_args)+2)); - - if (envvar == NULL || args == NULL) - goto oom; - - 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; - - 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); - } - else - { - print_variables (bus_address, bus_pid, wid, c_shell_syntax, - bourne_shell_syntax, binary_syntax); - } - - verbose ("dbus-launch exiting\n"); + pass_info (runprog, bus_address, bus_pid, wid, c_shell_syntax, + bourne_shell_syntax, binary_syntax, argc, argv, remaining_args); + } - fflush (stdout); - fflush (stderr); - close (1); - close (2); - - exit (0); - } - return 0; - oom: - fprintf (stderr, "Out of memory!"); - exit (1); }