/** * Spawns a new process. * * On Unix platforms, the child_setup function is passed the given * user_data and is run in the child after fork() but before calling exec(). * This can be used to change uid, resource limits and so on. * On Windows, this functionality does not fit the multi-processing model * (Windows does the equivalent of fork() and exec() in a single API call), * and the child_setup function and its user_data are ignored. * * Also creates a "babysitter" which tracks the status of the * child process, advising the parent if the child exits. * If the spawn fails, no babysitter is created. * If sitter_p is #NULL, no babysitter is kept. * * @param sitter_p return location for babysitter or #NULL * @param log_name the name under which to log messages about this process being spawned * @param argv the executable and arguments * @param env the environment, or #NULL to copy the parent's * @param child_setup function to call in child pre-exec() * @param user_data user data for setup function * @param error error object to be filled in if function fails * @returns #TRUE on success, #FALSE if error is filled in */ dbus_bool_t _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, const char *log_name, char * const *argv, char **env, DBusSpawnFlags flags, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error) { DBusBabysitter *sitter; int child_err_report_pipe[2] = { -1, -1 }; DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT }; pid_t pid; #ifdef HAVE_SYSTEMD int fd_out = -1; int fd_err = -1; #endif _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (argv[0] != NULL); if (sitter_p != NULL) *sitter_p = NULL; sitter = NULL; sitter = _dbus_babysitter_new (); if (sitter == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } sitter->log_name = _dbus_strdup (log_name); if (sitter->log_name == NULL && log_name != NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (sitter->log_name == NULL) sitter->log_name = _dbus_strdup (argv[0]); if (sitter->log_name == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!make_pipe (child_err_report_pipe, error)) goto cleanup_and_fail; if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error)) goto cleanup_and_fail; /* Setting up the babysitter is only useful in the parent, * but we don't want to run out of memory and fail * after we've already forked, since then we'd leak * child processes everywhere. */ sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END], DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); if (sitter->error_watch == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch)) { /* we need to free it early so the destructor won't try to remove it * without it having been added, which DBusLoop doesn't allow */ _dbus_watch_invalidate (sitter->error_watch); _dbus_watch_unref (sitter->error_watch); sitter->error_watch = NULL; dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0].fd, DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); if (sitter->sitter_watch == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) { /* we need to free it early so the destructor won't try to remove it * without it having been added, which DBusLoop doesn't allow */ _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); #ifdef HAVE_SYSTEMD if (flags & DBUS_SPAWN_REDIRECT_OUTPUT) { /* This may fail, but it's not critical. * In particular, if we were compiled with journald support but are now * running on a non-systemd system, this is going to fail, so we * have to cope gracefully. */ fd_out = sd_journal_stream_fd (sitter->log_name, LOG_INFO, FALSE); fd_err = sd_journal_stream_fd (sitter->log_name, LOG_WARNING, FALSE); } #endif pid = fork (); if (pid < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FORK_FAILED, "Failed to fork (%s)", _dbus_strerror (errno)); goto cleanup_and_fail; } else if (pid == 0) { /* Immediate child, this is the babysitter process. */ int grandchild_pid; /* Be sure we crash if the parent exits * and we write to the err_report_pipe */ signal (SIGPIPE, SIG_DFL); /* Close the parent's end of the pipes. */ close_and_invalidate (&child_err_report_pipe[READ_END]); close_and_invalidate (&babysitter_pipe[0].fd); /* Create the child that will exec () */ grandchild_pid = fork (); if (grandchild_pid < 0) { write_err_and_exit (babysitter_pipe[1].fd, CHILD_FORK_FAILED); _dbus_assert_not_reached ("Got to code after write_err_and_exit()"); } else if (grandchild_pid == 0) { #ifdef __linux__ int fd = -1; #ifdef O_CLOEXEC fd = open ("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC); #endif if (fd < 0) { fd = open ("/proc/self/oom_score_adj", O_WRONLY); _dbus_fd_set_close_on_exec (fd); } if (fd >= 0) { if (write (fd, "0", sizeof (char)) < 0) _dbus_warn ("writing oom_score_adj error: %s", strerror (errno)); _dbus_close (fd, NULL); } #endif /* Go back to ignoring SIGPIPE, since it's evil */ signal (SIGPIPE, SIG_IGN); close_and_invalidate (&babysitter_pipe[1].fd); #ifdef HAVE_SYSTEMD /* log to systemd journal if possible */ if (fd_out >= 0) dup2 (fd_out, STDOUT_FILENO); if (fd_err >= 0) dup2 (fd_err, STDERR_FILENO); close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif do_exec (child_err_report_pipe[WRITE_END], argv, env, child_setup, user_data); _dbus_assert_not_reached ("Got to code after exec() - should have exited on error"); } else { close_and_invalidate (&child_err_report_pipe[WRITE_END]); #ifdef HAVE_SYSTEMD close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif babysit (grandchild_pid, babysitter_pipe[1].fd); _dbus_assert_not_reached ("Got to code after babysit()"); } } else { /* Close the uncared-about ends of the pipes */ close_and_invalidate (&child_err_report_pipe[WRITE_END]); close_and_invalidate (&babysitter_pipe[1].fd); #ifdef HAVE_SYSTEMD close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif sitter->socket_to_babysitter = babysitter_pipe[0]; babysitter_pipe[0].fd = -1; sitter->error_pipe_from_child = child_err_report_pipe[READ_END]; child_err_report_pipe[READ_END] = -1; sitter->sitter_pid = pid; if (sitter_p != NULL) *sitter_p = sitter; else _dbus_babysitter_unref (sitter); dbus_free_string_array (env); _DBUS_ASSERT_ERROR_IS_CLEAR (error); return TRUE; } cleanup_and_fail: _DBUS_ASSERT_ERROR_IS_SET (error); close_and_invalidate (&child_err_report_pipe[READ_END]); close_and_invalidate (&child_err_report_pipe[WRITE_END]); close_and_invalidate (&babysitter_pipe[0].fd); close_and_invalidate (&babysitter_pipe[1].fd); #ifdef HAVE_SYSTEMD close_and_invalidate (&fd_out); close_and_invalidate (&fd_err); #endif if (sitter != NULL) _dbus_babysitter_unref (sitter); return FALSE; }
int main (int argc, char **argv) { const char *prev_arg; const char *shname; const char *runprog = NULL; int remaining_args = 0; int exit_with_session; int exit_with_x11 = FALSE; int binary_syntax = FALSE; int c_shell_syntax = FALSE; int bourne_shell_syntax = FALSE; int auto_shell_syntax = FALSE; int autolaunch = FALSE; int requires_arg = FALSE; int close_stderr = FALSE; 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]; char *config_file; dbus_bool_t user_bus_supported = FALSE; DBusString user_bus; const char *error_str; exit_with_session = FALSE; config_file = NULL; /* Ensure that the first three fds are open, to ensure that when we * create other file descriptors (for example for epoll, inotify or * a socket), they never get assigned as fd 0, 1 or 2. If they were, * which could happen if our caller had (incorrectly) closed those * standard fds, then we'd start dbus-daemon with those fds closed, * which is unexpected and could cause it to misbehave. */ if (!_dbus_ensure_standard_fds (0, &error_str)) { fprintf (stderr, "dbus-launch: fatal error setting up standard fds: %s: %s\n", error_str, _dbus_strerror (errno)); return 1; } prev_arg = NULL; i = 1; while (i < argc) { const char *arg = argv[i]; if (strcmp (arg, "--help") == 0 || strcmp (arg, "-h") == 0 || strcmp (arg, "-?") == 0) usage (0); else if (strcmp (arg, "--auto-syntax") == 0) auto_shell_syntax = TRUE; else if (strcmp (arg, "-c") == 0 || strcmp (arg, "--csh-syntax") == 0) c_shell_syntax = TRUE; else if (strcmp (arg, "-s") == 0 || strcmp (arg, "--sh-syntax") == 0) bourne_shell_syntax = TRUE; else if (strcmp (arg, "--binary-syntax") == 0) binary_syntax = TRUE; else if (strcmp (arg, "--version") == 0) version (); else if (strcmp (arg, "--exit-with-session") == 0) exit_with_session = TRUE; else if (strcmp (arg, "--exit-with-x11") == 0) exit_with_x11 = TRUE; else if (strcmp (arg, "--close-stderr") == 0) close_stderr = TRUE; else if (strstr (arg, "--autolaunch=") == arg) { const char *s; if (autolaunch) { fprintf (stderr, "--autolaunch given twice\n"); exit (1); } autolaunch = TRUE; s = strchr (arg, '='); ++s; save_machine_uuid (s); } else if (prev_arg && strcmp (prev_arg, "--autolaunch") == 0) { if (autolaunch) { fprintf (stderr, "--autolaunch given twice\n"); exit (1); } autolaunch = TRUE; save_machine_uuid (arg); requires_arg = FALSE; } else if (strcmp (arg, "--autolaunch") == 0) requires_arg = TRUE; else if (strstr (arg, "--config-file=") == arg) { const char *file; if (config_file != NULL) { fprintf (stderr, "--config-file given twice\n"); exit (1); } file = strchr (arg, '='); ++file; config_file = xstrdup (file); } else if (prev_arg && strcmp (prev_arg, "--config-file") == 0) { if (config_file != NULL) { fprintf (stderr, "--config-file given twice\n"); exit (1); } config_file = xstrdup (arg); requires_arg = FALSE; } else if (strcmp (arg, "--config-file") == 0) requires_arg = TRUE; else if (arg[0] == '-') { if (strcmp (arg, "--") != 0) { fprintf (stderr, "Option `%s' is unknown.\n", arg); exit (1); } else { runprog = argv[i+1]; remaining_args = i+2; break; } } else { runprog = arg; remaining_args = i+1; break; } prev_arg = arg; ++i; } if (requires_arg) { fprintf (stderr, "Option `%s' requires an argument.\n", prev_arg); exit (1); } if (auto_shell_syntax) { if ((shname = getenv ("SHELL")) != NULL) { if (!strncmp (shname + strlen (shname) - 3, "csh", 3)) c_shell_syntax = TRUE; else bourne_shell_syntax = TRUE; } else bourne_shell_syntax = TRUE; } if (exit_with_session) verbose ("--exit-with-session enabled\n"); if (exit_with_x11) verbose ("--exit-with-x11 enabled\n"); if (autolaunch) { #ifndef DBUS_BUILD_X11 fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n" "Cannot continue.\n"); exit (1); #else /* DBUS_BUILD_X11 */ fprintf (stderr, "X11 autolaunch support disabled at compile time.\n"); exit (1); #endif /* DBUS_BUILD_X11 */ } else if (exit_with_x11) { #ifndef DBUS_BUILD_X11 fprintf (stderr, "Session lifetime based on X11 requested, but X11 support not compiled in.\n"); exit (1); #else /* DBUS_BUILD_X11 */ if (!read_machine_uuid_if_needed()) { fprintf (stderr, "Session lifetime based on X11 requested, but machine UUID unavailable.\n"); exit (1); } if (!x11_init ()) { fprintf (stderr, "Session lifetime based on X11 requested, but X11 initialization failed.\n"); exit (1); } #endif /* DBUS_BUILD_X11 */ } #ifdef DBUS_BUILD_X11 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) { 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) { /* Child */ #define MAX_FD_LEN 64 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 (); verbose ("=== Babysitter's intermediate parent created\n"); /* Fork once more to create babysitter */ 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_pid_to_launcher_pipe[WRITE_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 || exit_with_x11, ret, bus_pid_to_babysitter_pipe[READ_END]); exit (0); } verbose ("=== Bus exec process created\n"); /* Now we are the bus process (well, almost; * dbus-daemon 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_babysitter_pipe[WRITE_END]); /* If we have a user bus and want to use it, do so instead of * exec'ing a new dbus-daemon. */ if (autolaunch && user_bus_supported) { do_write (bus_pid_to_launcher_pipe[WRITE_END], "0\n", 2); close (bus_pid_to_launcher_pipe[WRITE_END]); do_write (bus_address_to_launcher_pipe[WRITE_END], _dbus_string_get_const_data (&user_bus), _dbus_string_get_length (&user_bus)); do_write (bus_address_to_launcher_pipe[WRITE_END], "\n", 1); close (bus_address_to_launcher_pipe[WRITE_END]); exit (0); } sprintf (write_pid_fd_as_string, "%d", bus_pid_to_launcher_pipe[WRITE_END]); sprintf (write_address_fd_as_string, "%d", bus_address_to_launcher_pipe[WRITE_END]); verbose ("Calling exec()\n"); #ifdef DBUS_ENABLE_EMBEDDED_TESTS { /* exec from testdir */ const char *test_daemon = getenv ("DBUS_TEST_DAEMON"); if (test_daemon != NULL) { if (config_file == NULL && getenv ("DBUS_TEST_DATA") != NULL) { config_file = concat2 (getenv ("DBUS_TEST_DATA"), "/valid-config-files/session.conf"); if (config_file == NULL) { fprintf (stderr, "Out of memory\n"); exit (1); } } execl (test_daemon, test_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 test message bus daemon %s: %s.\n", test_daemon, strerror (errno)); exit (1); } } #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ 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", DBUS_DAEMONDIR"/dbus-daemon", strerror (errno)); /* * If it failed, try running without full PATH. Note this is needed * because the build process builds the run-with-tmp-session-bus.conf * file and the dbus-daemon will not be in the install location during * build time. */ 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", strerror (errno)); exit (1); } else { /* Parent */ #define MAX_PID_LEN 64 pid_t bus_pid; char bus_address[MAX_ADDR_LEN]; char buf[MAX_PID_LEN]; char *end; long wid = 0; long val; verbose ("=== Parent dbus-launch continues\n"); close (bus_pid_to_launcher_pipe[WRITE_END]); close (bus_address_to_launcher_pipe[WRITE_END]); close (bus_pid_to_babysitter_pipe[READ_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 daemon\n"); /* Now read data */ switch (read_line (bus_pid_to_launcher_pipe[READ_END], 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 = val; /* Have to initialize bus_pid_to_kill ASAP, so that the X error callback can kill it if an error happens. */ bus_pid_to_kill = bus_pid; close (bus_pid_to_launcher_pipe[READ_END]); #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 */ if (autolaunch) { if (ret2 == 0) { char *address = NULL; /* another window got added. Return its address */ 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); } } } #endif /* Forward the pid to the babysitter */ write_pid (bus_pid_to_babysitter_pipe[WRITE_END], bus_pid); close (bus_pid_to_babysitter_pipe[WRITE_END]); pass_info (runprog, bus_address, bus_pid, wid, c_shell_syntax, bourne_shell_syntax, binary_syntax, argc, argv, remaining_args); } return 0; }
/** * Spawns a new process. The executable name and argv[0] * are the same, both are provided in argv[0]. The child_setup * function is passed the given user_data and is run in the child * just before calling exec(). * * Also creates a "babysitter" which tracks the status of the * child process, advising the parent if the child exits. * If the spawn fails, no babysitter is created. * If sitter_p is #NULL, no babysitter is kept. * * @param sitter_p return location for babysitter or #NULL * @param argv the executable and arguments * @param env the environment (not used on unix yet) * @param child_setup function to call in child pre-exec() * @param user_data user data for setup function * @param error error object to be filled in if function fails * @returns #TRUE on success, #FALSE if error is filled in */ dbus_bool_t _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, char **argv, char **env, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error) { DBusBabysitter *sitter; int child_err_report_pipe[2] = { -1, -1 }; int babysitter_pipe[2] = { -1, -1 }; pid_t pid; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (sitter_p != NULL) *sitter_p = NULL; sitter = NULL; sitter = _dbus_babysitter_new (); if (sitter == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } sitter->executable = _dbus_strdup (argv[0]); if (sitter->executable == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!make_pipe (child_err_report_pipe, error)) goto cleanup_and_fail; if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error)) goto cleanup_and_fail; /* Setting up the babysitter is only useful in the parent, * but we don't want to run out of memory and fail * after we've already forked, since then we'd leak * child processes everywhere. */ sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END], DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); if (sitter->error_watch == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch)) { /* we need to free it early so the destructor won't try to remove it * without it having been added, which DBusLoop doesn't allow */ _dbus_watch_invalidate (sitter->error_watch); _dbus_watch_unref (sitter->error_watch); sitter->error_watch = NULL; dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0], DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); if (sitter->sitter_watch == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) { /* we need to free it early so the destructor won't try to remove it * without it having been added, which DBusLoop doesn't allow */ _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); pid = fork (); if (pid < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FORK_FAILED, "Failed to fork (%s)", _dbus_strerror (errno)); goto cleanup_and_fail; } else if (pid == 0) { /* Immediate child, this is the babysitter process. */ int grandchild_pid; /* Be sure we crash if the parent exits * and we write to the err_report_pipe */ signal (SIGPIPE, SIG_DFL); /* Close the parent's end of the pipes. */ close_and_invalidate (&child_err_report_pipe[READ_END]); close_and_invalidate (&babysitter_pipe[0]); /* Create the child that will exec () */ grandchild_pid = fork (); if (grandchild_pid < 0) { write_err_and_exit (babysitter_pipe[1], CHILD_FORK_FAILED); _dbus_assert_not_reached ("Got to code after write_err_and_exit()"); } else if (grandchild_pid == 0) { do_exec (child_err_report_pipe[WRITE_END], argv, env, child_setup, user_data); _dbus_assert_not_reached ("Got to code after exec() - should have exited on error"); } else { babysit (grandchild_pid, babysitter_pipe[1]); _dbus_assert_not_reached ("Got to code after babysit()"); } } else { /* Close the uncared-about ends of the pipes */ close_and_invalidate (&child_err_report_pipe[WRITE_END]); close_and_invalidate (&babysitter_pipe[1]); sitter->socket_to_babysitter = babysitter_pipe[0]; babysitter_pipe[0] = -1; sitter->error_pipe_from_child = child_err_report_pipe[READ_END]; child_err_report_pipe[READ_END] = -1; sitter->sitter_pid = pid; if (sitter_p != NULL) *sitter_p = sitter; else _dbus_babysitter_unref (sitter); dbus_free_string_array (env); _DBUS_ASSERT_ERROR_IS_CLEAR (error); return TRUE; } cleanup_and_fail: _DBUS_ASSERT_ERROR_IS_SET (error); close_and_invalidate (&child_err_report_pipe[READ_END]); close_and_invalidate (&child_err_report_pipe[WRITE_END]); close_and_invalidate (&babysitter_pipe[0]); close_and_invalidate (&babysitter_pipe[1]); if (sitter != NULL) _dbus_babysitter_unref (sitter); return FALSE; }
int main (int argc, char **argv) { const char *prev_arg; const char *shname; const char *runprog = NULL; int remaining_args = 0; int exit_with_session; int c_shell_syntax = FALSE; int bourne_shell_syntax = FALSE; int auto_shell_syntax = FALSE; 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]; char *config_file; exit_with_session = FALSE; config_file = NULL; prev_arg = NULL; i = 1; while (i < argc) { const char *arg = argv[i]; if (strcmp (arg, "--help") == 0 || strcmp (arg, "-h") == 0 || strcmp (arg, "-?") == 0) usage (0); else if (strcmp (arg, "--auto-syntax") == 0) auto_shell_syntax = TRUE; else if (strcmp (arg, "-c") == 0 || strcmp (arg, "--csh-syntax") == 0) c_shell_syntax = TRUE; else if (strcmp (arg, "-s") == 0 || strcmp (arg, "--sh-syntax") == 0) bourne_shell_syntax = TRUE; else if (strcmp (arg, "--version") == 0) version (); else if (strcmp (arg, "--exit-with-session") == 0) exit_with_session = TRUE; else if (strstr (arg, "--config-file=") == arg) { const char *file; if (config_file != NULL) { fprintf (stderr, "--config-file given twice\n"); exit (1); } file = strchr (arg, '='); ++file; config_file = xstrdup (file); } else if (prev_arg && strcmp (prev_arg, "--config-file") == 0) { if (config_file != NULL) { fprintf (stderr, "--config-file given twice\n"); exit (1); } config_file = xstrdup (arg); } else if (strcmp (arg, "--config-file") == 0) ; /* wait for next arg */ else { runprog = arg; remaining_args = i+1; break; } prev_arg = arg; ++i; } if (exit_with_session) verbose ("--exit-with-session enabled\n"); if (auto_shell_syntax) { if ((shname = getenv ("SHELL")) != NULL) { if (!strncmp (shname + strlen (shname) - 3, "csh", 3)) c_shell_syntax = TRUE; else bourne_shell_syntax = TRUE; } else bourne_shell_syntax = TRUE; } 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 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", "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", 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]); 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 { if (c_shell_syntax) printf ("setenv DBUS_SESSION_BUS_ADDRESS '%s'\n", bus_address); else { printf ("DBUS_SESSION_BUS_ADDRESS='%s'\n", bus_address); if (bourne_shell_syntax) printf ("export DBUS_SESSION_BUS_ADDRESS\n"); } if (c_shell_syntax) printf ("set DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid); else printf ("DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid); } verbose ("dbus-launch exiting\n"); fflush (stdout); fflush (stderr); close (1); close (2); exit (0); } return 0; oom: fprintf (stderr, "Out of memory!"); exit (1); }
int main (int argc, char **argv) { const char *prev_arg; const char *shname; const char *runprog = NULL; int remaining_args = 0; int exit_with_session; int binary_syntax = FALSE; int c_shell_syntax = FALSE; int bourne_shell_syntax = FALSE; int auto_shell_syntax = FALSE; int autolaunch = FALSE; int requires_arg = FALSE; int close_stderr = FALSE; 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]; char *config_file; exit_with_session = FALSE; config_file = NULL; prev_arg = NULL; i = 1; while (i < argc) { const char *arg = argv[i]; if (strcmp (arg, "--help") == 0 || strcmp (arg, "-h") == 0 || strcmp (arg, "-?") == 0) usage (0); else if (strcmp (arg, "--auto-syntax") == 0) auto_shell_syntax = TRUE; else if (strcmp (arg, "-c") == 0 || strcmp (arg, "--csh-syntax") == 0) c_shell_syntax = TRUE; else if (strcmp (arg, "-s") == 0 || strcmp (arg, "--sh-syntax") == 0) bourne_shell_syntax = TRUE; else if (strcmp (arg, "--binary-syntax") == 0) binary_syntax = TRUE; else if (strcmp (arg, "--version") == 0) version (); else if (strcmp (arg, "--exit-with-session") == 0) exit_with_session = TRUE; else if (strcmp (arg, "--close-stderr") == 0) close_stderr = TRUE; else if (strstr (arg, "--autolaunch=") == arg) { const char *s; if (autolaunch) { fprintf (stderr, "--autolaunch given twice\n"); exit (1); } autolaunch = TRUE; s = strchr (arg, '='); ++s; save_machine_uuid (s); } else if (prev_arg && strcmp (prev_arg, "--autolaunch") == 0) { if (autolaunch) { fprintf (stderr, "--autolaunch given twice\n"); exit (1); } autolaunch = TRUE; save_machine_uuid (arg); requires_arg = FALSE; } else if (strcmp (arg, "--autolaunch") == 0) requires_arg = TRUE; else if (strstr (arg, "--config-file=") == arg) { const char *file; if (config_file != NULL) { fprintf (stderr, "--config-file given twice\n"); exit (1); } file = strchr (arg, '='); ++file; config_file = xstrdup (file); } else if (prev_arg && strcmp (prev_arg, "--config-file") == 0) { if (config_file != NULL) { fprintf (stderr, "--config-file given twice\n"); exit (1); } config_file = xstrdup (arg); requires_arg = FALSE; } else if (strcmp (arg, "--config-file") == 0) requires_arg = TRUE; else if (arg[0] == '-') { if (strcmp (arg, "--") != 0) { fprintf (stderr, "Option `%s' is unknown.\n", arg); exit (1); } else { runprog = argv[i+1]; remaining_args = i+2; break; } } else { runprog = arg; remaining_args = i+1; break; } prev_arg = arg; ++i; } if (requires_arg) { fprintf (stderr, "Option `%s' requires an argument.\n", prev_arg); exit (1); } if (auto_shell_syntax) { if ((shname = getenv ("SHELL")) != NULL) { if (!strncmp (shname + strlen (shname) - 3, "csh", 3)) c_shell_syntax = TRUE; else bourne_shell_syntax = TRUE; } else bourne_shell_syntax = TRUE; } if (exit_with_session) verbose ("--exit-with-session enabled\n"); if (autolaunch) { #ifndef DBUS_BUILD_X11 fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n" "Cannot continue.\n"); exit (1); #else char *address; pid_t pid; long wid; if (get_machine_uuid () == NULL) { fprintf (stderr, "Machine UUID not provided as arg to --autolaunch\n"); 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) { verbose ("--exit-with-session automatically enabled\n"); exit_with_session = TRUE; } if (!x11_init ()) { fprintf (stderr, "Autolaunch error: X11 initialization failed.\n"); exit (1); } if (!x11_get_address (&address, &pid, &wid)) { fprintf (stderr, "Autolaunch error: X11 communication error.\n"); exit (1); } 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); exit (0); } #endif } if (pipe (bus_pid_to_launcher_pipe) < 0 || pipe (bus_address_to_launcher_pipe) < 0 || 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) { /* Child */ #define MAX_FD_LEN 64 char write_pid_fd_as_string[MAX_FD_LEN]; char write_address_fd_as_string[MAX_FD_LEN]; if (close_stderr) do_close_stderr (); verbose ("=== Babysitter's intermediate parent created\n"); /* Fork once more to create babysitter */ 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_pid_to_launcher_pipe[WRITE_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]); exit (0); } verbose ("=== Bus exec process created\n"); /* Now we are the bus process (well, almost; * dbus-daemon 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_babysitter_pipe[WRITE_END]); sprintf (write_pid_fd_as_string, "%d", bus_pid_to_launcher_pipe[WRITE_END]); sprintf (write_address_fd_as_string, "%d", bus_address_to_launcher_pipe[WRITE_END]); verbose ("Calling exec()\n"); #ifdef DBUS_BUILD_TESTS /* exec from testdir */ if (getenv("DBUS_USE_TEST_BINARY") != NULL) { execl (TEST_BUS_BINARY, TEST_BUS_BINARY, "--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 test message bus daemon %s: %s. Will try again with the system path.\n", TEST_BUS_BINARY, strerror (errno)); } #endif /* DBUS_BUILD_TESTS */ 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", DBUS_DAEMONDIR"/dbus-daemon", strerror (errno)); /* * If it failed, try running without full PATH. Note this is needed * because the build process builds the run-with-tmp-session-bus.conf * file and the dbus-daemon will not be in the install location during * build time. */ 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", strerror (errno)); exit (1); } else { /* Parent */ #define MAX_PID_LEN 64 pid_t bus_pid; char bus_address[MAX_ADDR_LEN]; char buf[MAX_PID_LEN]; char *end; long wid = 0; long val; int ret2; verbose ("=== Parent dbus-launch continues\n"); close (bus_pid_to_launcher_pipe[WRITE_END]); close (bus_address_to_launcher_pipe[WRITE_END]); close (bus_pid_to_babysitter_pipe[READ_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 daemon\n"); /* Now read data */ switch (read_line (bus_pid_to_launcher_pipe[READ_END], 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 = val; 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) { ret2 = x11_save_address (bus_address, bus_pid, &wid); if (ret2 == 0) { /* another window got added. Return its address */ char *address; pid_t pid; long wid; if (x11_get_address (&address, &pid, &wid) && 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); free (address); bus_pid_to_kill = bus_pid; kill_bus_and_exit (0); } /* 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 /* Forward the pid to the babysitter */ 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"); fflush (stdout); fflush (stderr); close (1); close (2); exit (0); } return 0; oom: fprintf (stderr, "Out of memory!"); exit (1); }
EXPORT_C #endif dbus_bool_t _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, char **argv, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error) { #ifndef __SYMBIAN32__ DBusBabysitter *sitter; int child_err_report_pipe[2] = { -1, -1 }; int babysitter_pipe[2] = { -1, -1 }; pid_t pid; #ifndef __SYMBIAN32__ _DBUS_ASSERT_ERROR_IS_CLEAR (error); *sitter_p = NULL; sitter = NULL; sitter = _dbus_babysitter_new (); if (sitter == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } sitter->executable = _dbus_strdup (argv[0]); if (sitter->executable == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!make_pipe (child_err_report_pipe, error)) goto cleanup_and_fail; _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]); _dbus_fd_set_close_on_exec (child_err_report_pipe[WRITE_END]); if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error)) goto cleanup_and_fail; _dbus_fd_set_close_on_exec (babysitter_pipe[0]); _dbus_fd_set_close_on_exec (babysitter_pipe[1]); /* Setting up the babysitter is only useful in the parent, * but we don't want to run out of memory and fail * after we've already forked, since then we'd leak * child processes everywhere. */ sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END], DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); if (sitter->error_watch == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0], DBUS_WATCH_READABLE, TRUE, handle_watch, sitter, NULL); if (sitter->sitter_watch == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto cleanup_and_fail; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); pid = fork (); if (pid < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FORK_FAILED, "Failed to fork (%s)", _dbus_strerror (errno)); goto cleanup_and_fail; } else if (pid == 0) { /* Immediate child, this is the babysitter process. */ int grandchild_pid; /* Be sure we crash if the parent exits * and we write to the err_report_pipe */ #ifndef __SYMBIAN32__ signal (SIGPIPE, SIG_DFL); #endif /* Close the parent's end of the pipes. */ close_and_invalidate (&child_err_report_pipe[READ_END]); close_and_invalidate (&babysitter_pipe[0]); /* Create the child that will exec () */ grandchild_pid = fork (); if (grandchild_pid < 0) { write_err_and_exit (babysitter_pipe[1], CHILD_FORK_FAILED); _dbus_assert_not_reached ("Got to code after write_err_and_exit()"); } else if (grandchild_pid == 0) { do_exec (child_err_report_pipe[WRITE_END], argv, child_setup, user_data); _dbus_assert_not_reached ("Got to code after exec() - should have exited on error"); } else { babysit (grandchild_pid, babysitter_pipe[1]); _dbus_assert_not_reached ("Got to code after babysit()"); } } else { /* Close the uncared-about ends of the pipes */ close_and_invalidate (&child_err_report_pipe[WRITE_END]); close_and_invalidate (&babysitter_pipe[1]); sitter->socket_to_babysitter = babysitter_pipe[0]; babysitter_pipe[0] = -1; sitter->error_pipe_from_child = child_err_report_pipe[READ_END]; child_err_report_pipe[READ_END] = -1; sitter->sitter_pid = pid; if (sitter_p != NULL) *sitter_p = sitter; else _dbus_babysitter_unref (sitter); _DBUS_ASSERT_ERROR_IS_CLEAR (error); return TRUE; } cleanup_and_fail: _DBUS_ASSERT_ERROR_IS_SET (error); close_and_invalidate (&child_err_report_pipe[READ_END]); close_and_invalidate (&child_err_report_pipe[WRITE_END]); close_and_invalidate (&babysitter_pipe[0]); close_and_invalidate (&babysitter_pipe[1]); if (sitter != NULL) _dbus_babysitter_unref (sitter); #endif return FALSE; #else /* FILE* ChildProcessStream; ChildProcessStream =popen(argv[0], "r"); if (ChildProcessStream == NULL) { dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, "Failed to execute service process"); return FALSE; } */ //static pid_t Childpid; //have to make it static for thread fuction to access it pid_t childPid; int retVal; //pthread_t thread; retVal = posix_spawn(&childPid, argv[0], NULL,NULL, NULL, NULL); if (retVal!=0) { dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, "Failed to execute service process"); return FALSE; } /* pthread_create(&thread, NULL, (void*)&thread_fun, &Childpid); //(void) waitpid(Childpid, NULL, 0); //printf("\r\n*** Child process finished ***\r\n"); */ if(!retVal) return TRUE; else return FALSE; #endif }