27 #include "dbus-spawn.h"
28 #include "dbus-sysdeps-unix.h"
29 #include "dbus-internals.h"
30 #include "dbus-test.h"
31 #include "dbus-protocol.h"
45 #include <systemd/sd-journal.h>
48 extern char **environ;
80 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
89 to_read =
sizeof (int) * n_ints_in_buf - bytes;
100 if (chunk < 0 && errno == EINTR)
107 "Failed to read from child pipe (%s)",
108 _dbus_strerror (errno));
122 *n_ints_read = (int)(bytes /
sizeof(
int));
135 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
144 to_read =
sizeof (pid_t) - bytes;
152 ((
char*)buf) + bytes,
154 if (chunk < 0 && errno == EINTR)
161 "Failed to read from child pipe (%s)",
162 _dbus_strerror (errno));
257 DBusBabysitterFinishedFunc finished_cb;
262 unsigned int have_child_status : 1;
268 _dbus_babysitter_new (
void)
339 close_socket_to_babysitter (sitter);
341 close_error_pipe_from_child (sitter);
352 ret = waitpid (sitter->
sitter_pid, &status, WNOHANG);
364 ret = waitpid (sitter->
sitter_pid, &status, 0);
366 while (_DBUS_UNLIKELY (ret < 0 && errno == EINTR));
372 _dbus_warn (
"Babysitter process not available to be reaped; should not happen\n");
374 _dbus_warn (
"Unexpected error %d in waitpid() for babysitter: %s\n",
375 errno, _dbus_strerror (errno));
379 _dbus_verbose (
"Reaped %ld, waiting for babysitter %ld\n",
382 if (WIFEXITED (sitter->
status))
383 _dbus_verbose (
"Babysitter exited with status %d\n",
384 WEXITSTATUS (sitter->
status));
385 else if (WIFSIGNALED (sitter->
status))
386 _dbus_verbose (
"Babysitter received signal %d\n",
387 WTERMSIG (sitter->
status));
389 _dbus_verbose (
"Babysitter exited abnormally\n");
413 r = read_ints (fd, &what, 1, &got, &error);
434 case CHILD_FORK_FAILED:
435 case CHILD_EXEC_FAILED:
439 r = read_ints (fd, &arg, 1, &got, &error);
455 if (what == CHILD_EXITED)
457 sitter->have_child_status =
TRUE;
460 _dbus_verbose (
"recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
461 WIFEXITED (sitter->
status), WIFSIGNALED (sitter->
status),
462 WEXITSTATUS (sitter->
status), WTERMSIG (sitter->
status));
464 else if (what == CHILD_FORK_FAILED)
468 _dbus_verbose (
"recorded fork errnum %d\n", sitter->
errnum);
470 else if (what == CHILD_EXEC_FAILED)
474 _dbus_verbose (
"recorded exec errnum %d\n", sitter->
errnum);
483 r = read_pid (fd, &pid, &error);
499 _dbus_verbose (
"recorded grandchild pid %d\n", sitter->
grandchild_pid);
503 _dbus_warn (
"Unknown message received from babysitter process\n");
514 _dbus_verbose (
"Closing babysitter\n");
535 _dbus_verbose (
"Closing child error\n");
563 _dbus_verbose (
"Reading data from babysitter\n");
565 close_socket_to_babysitter (sitter);
569 close_socket_to_babysitter (sitter);
577 if (revents & _DBUS_POLLIN)
579 _dbus_verbose (
"Reading data from child error\n");
581 close_error_pipe_from_child (sitter);
585 close_error_pipe_from_child (sitter);
598 descriptors_ready =
FALSE;
626 while (ret < 0 && errno == EINTR);
628 if (ret == 0 && block)
634 while (ret < 0 && errno == EINTR);
639 descriptors_ready =
TRUE;
645 handle_error_pipe (sitter, fds[i].revents);
647 handle_babysitter_socket (sitter, fds[i].revents);
652 return descriptors_ready;
659 #define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter >= 0 || (sitter)->error_pipe_from_child >= 0)
673 babysitter_iteration (sitter,
TRUE);
675 _dbus_verbose (
"Got child PID %ld for killing\n",
695 babysitter_iteration (sitter,
FALSE))
721 if (!sitter->have_child_status ||
722 !(WIFEXITED (sitter->
status)))
725 *status = WEXITSTATUS (sitter->
status);
752 "Failed to execute program %s: %s",
758 "Failed to fork a new process %s: %s",
761 else if (sitter->have_child_status)
763 if (WIFEXITED (sitter->
status))
765 "Process %s exited with status %d",
767 else if (WIFSIGNALED (sitter->
status))
769 "Process %s received signal %d",
773 "Process %s exited abnormally",
779 "Process %s exited, reason unknown",
814 unsigned int condition,
832 handle_error_pipe (sitter, revents);
834 handle_babysitter_socket (sitter, revents);
837 babysitter_iteration (sitter,
FALSE))
846 sitter->finished_cb !=
NULL)
848 sitter->finished_cb (sitter, sitter->finished_data);
849 sitter->finished_cb =
NULL;
872 close_and_invalidate (
int *fd)
896 retval = pipe2 (p, O_CLOEXEC);
897 cloexec_done = retval >= 0;
901 if (retval < 0 && errno == ENOSYS)
907 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
913 "Failed to create pipe for communicating with child process (%s)",
914 _dbus_strerror (errno));
930 do_write (
int fd,
const void *buf,
size_t count)
932 size_t bytes_written;
939 ret = write (fd, ((
const char*)buf) + bytes_written, count - bytes_written);
947 _dbus_warn (
"Failed to write data to pipe!\n");
952 bytes_written += ret;
954 if (bytes_written < count)
959 write_err_and_exit (
int fd,
int msg)
963 do_write (fd, &msg,
sizeof (msg));
964 do_write (fd, &en,
sizeof (en));
970 write_pid (
int fd, pid_t pid)
974 do_write (fd, &msg,
sizeof (msg));
975 do_write (fd, &pid,
sizeof (pid));
979 write_status_and_exit (
int fd,
int status)
981 int msg = CHILD_EXITED;
983 do_write (fd, &msg,
sizeof (msg));
984 do_write (fd, &status,
sizeof (status));
990 do_exec (
int child_err_report_fd,
993 DBusSpawnChildSetupFunc child_setup,
996 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1000 _dbus_verbose_reset ();
1005 (* child_setup) (user_data);
1007 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1008 max_open = sysconf (_SC_OPEN_MAX);
1010 for (i = 3; i < max_open; i++)
1014 if (i == child_err_report_fd)
1017 retval = fcntl (i, F_GETFD);
1019 if (retval != -1 && !(retval & FD_CLOEXEC))
1020 _dbus_warn (
"Fd %d did not have the close-on-exec flag set!\n", i);
1031 execve (argv[0], argv, envp);
1034 write_err_and_exit (child_err_report_fd,
1039 check_babysit_events (pid_t grandchild_pid,
1048 ret = waitpid (grandchild_pid, &status, WNOHANG);
1053 while (ret < 0 && errno == EINTR);
1057 _dbus_verbose (
"no child exited\n");
1064 _dbus_warn (
"unexpected waitpid() failure in check_babysit_events(): %s\n",
1065 _dbus_strerror (errno));
1068 else if (ret == grandchild_pid)
1071 _dbus_verbose (
"reaped child pid %ld\n", (
long) ret);
1073 write_status_and_exit (parent_pipe, status);
1077 _dbus_warn (
"waitpid() reaped pid %d that we've never heard of\n",
1082 if (revents & _DBUS_POLLIN)
1084 _dbus_verbose (
"babysitter got POLLIN from parent pipe\n");
1090 _dbus_verbose (
"babysitter got POLLERR or POLLHUP from parent\n");
1095 static int babysit_sigchld_pipe = -1;
1098 babysit_signal_handler (
int signo)
1102 if (write (babysit_sigchld_pipe, &b, 1) <= 0)
1108 babysit (pid_t grandchild_pid,
1111 int sigchld_pipe[2];
1116 _dbus_verbose_reset ();
1123 if (pipe (sigchld_pipe) < 0)
1125 _dbus_warn (
"Not enough file descriptors to create pipe in babysitter process\n");
1129 babysit_sigchld_pipe = sigchld_pipe[
WRITE_END];
1133 write_pid (parent_pipe, grandchild_pid);
1135 check_babysit_events (grandchild_pid, parent_pipe, 0);
1141 pfds[0].
fd = parent_pipe;
1151 _dbus_warn (
"_dbus_poll() error: %s\n", strerror (errno));
1155 if (pfds[0].revents != 0)
1157 check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
1159 else if (pfds[1].revents & _DBUS_POLLIN)
1162 if (read (sigchld_pipe[
READ_END], &b, 1) == -1)
1167 check_babysit_events (grandchild_pid, parent_pipe, 0);
1195 const char *log_name,
1198 DBusSpawnChildSetupFunc child_setup,
1203 int child_err_report_pipe[2] = { -1, -1 };
1204 int babysitter_pipe[2] = { -1, -1 };
1211 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1214 if (sitter_p !=
NULL)
1219 sitter = _dbus_babysitter_new ();
1230 goto cleanup_and_fail;
1239 goto cleanup_and_fail;
1242 if (!make_pipe (child_err_report_pipe, error))
1243 goto cleanup_and_fail;
1246 goto cleanup_and_fail;
1254 DBUS_WATCH_READABLE,
1259 goto cleanup_and_fail;
1271 goto cleanup_and_fail;
1275 DBUS_WATCH_READABLE,
1280 goto cleanup_and_fail;
1292 goto cleanup_and_fail;
1295 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1302 fd_out = sd_journal_stream_fd (sitter->
log_name, LOG_INFO,
FALSE);
1303 fd_err = sd_journal_stream_fd (sitter->
log_name, LOG_WARNING,
FALSE);
1312 "Failed to fork (%s)",
1313 _dbus_strerror (errno));
1314 goto cleanup_and_fail;
1324 signal (SIGPIPE, SIG_DFL);
1327 close_and_invalidate (&child_err_report_pipe[READ_END]);
1328 close_and_invalidate (&babysitter_pipe[0]);
1331 grandchild_pid = fork ();
1333 if (grandchild_pid < 0)
1335 write_err_and_exit (babysitter_pipe[1],
1339 else if (grandchild_pid == 0)
1343 signal (SIGPIPE, SIG_IGN);
1345 close_and_invalidate (&babysitter_pipe[1]);
1349 dup2 (fd_out, STDOUT_FILENO);
1351 dup2 (fd_err, STDERR_FILENO);
1352 close_and_invalidate (&fd_out);
1353 close_and_invalidate (&fd_err);
1355 do_exec (child_err_report_pipe[
WRITE_END],
1358 child_setup, user_data);
1363 close_and_invalidate (&child_err_report_pipe[
WRITE_END]);
1365 close_and_invalidate (&fd_out);
1366 close_and_invalidate (&fd_err);
1368 babysit (grandchild_pid, babysitter_pipe[1]);
1375 close_and_invalidate (&child_err_report_pipe[
WRITE_END]);
1376 close_and_invalidate (&babysitter_pipe[1]);
1378 close_and_invalidate (&fd_out);
1379 close_and_invalidate (&fd_err);
1383 babysitter_pipe[0] = -1;
1386 child_err_report_pipe[
READ_END] = -1;
1390 if (sitter_p !=
NULL)
1397 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1404 _DBUS_ASSERT_ERROR_IS_SET (error);
1406 close_and_invalidate (&child_err_report_pipe[READ_END]);
1407 close_and_invalidate (&child_err_report_pipe[
WRITE_END]);
1408 close_and_invalidate (&babysitter_pipe[0]);
1409 close_and_invalidate (&babysitter_pipe[1]);
1411 close_and_invalidate (&fd_out);
1412 close_and_invalidate (&fd_err);
1423 DBusBabysitterFinishedFunc finished,
1426 sitter->finished_cb = finished;
1427 sitter->finished_data = user_data;
1432 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
1435 get_test_exec (
const char *exe,
1438 const char *dbus_test_exec;
1442 if (dbus_test_exec ==
NULL)
1443 dbus_test_exec = DBUS_TEST_EXEC;
1449 dbus_test_exec, exe, DBUS_EXEEXT))
1455 return _dbus_string_get_data (scratch_space);
1462 babysitter_iteration (sitter,
TRUE);
1466 check_spawn_nonexistent (
void *data)
1474 argv[0] =
"/this/does/not/exist/32542sdgafgafdg";
1479 _dbus_babysitter_block_for_child_exit (sitter);
1488 _dbus_warn (
"Did not get an error launching nonexistent executable\n");
1495 _dbus_warn (
"Not expecting error when launching nonexistent executable: %s: %s\n",
1507 check_spawn_segfault (
void *data)
1516 argv[0] = get_test_exec (
"test-segfault", &argv0);
1518 if (argv[0] ==
NULL)
1528 _dbus_babysitter_block_for_child_exit (sitter);
1539 _dbus_warn (
"Did not get an error launching segfaulting binary\n");
1546 _dbus_warn (
"Not expecting error when launching segfaulting executable: %s: %s\n",
1558 check_spawn_exit (
void *data)
1567 argv[0] = get_test_exec (
"test-exit", &argv0);
1569 if (argv[0] ==
NULL)
1579 _dbus_babysitter_block_for_child_exit (sitter);
1590 _dbus_warn (
"Did not get an error launching binary that exited with failure code\n");
1597 _dbus_warn (
"Not expecting error when launching exiting executable: %s: %s\n",
1609 check_spawn_and_kill (
void *data)
1618 argv[0] = get_test_exec (
"test-sleep-forever", &argv0);
1620 if (argv[0] ==
NULL)
1632 _dbus_babysitter_block_for_child_exit (sitter);
1644 _dbus_warn (
"Did not get an error after killing spawned binary\n");
1651 _dbus_warn (
"Not expecting error when killing executable: %s: %s\n",
1663 _dbus_spawn_test (
const char *test_data_dir)
1665 if (!_dbus_test_oom_handling (
"spawn_nonexistent",
1666 check_spawn_nonexistent,
1670 if (!_dbus_test_oom_handling (
"spawn_segfault",
1671 check_spawn_segfault,
1675 if (!_dbus_test_oom_handling (
"spawn_exit",
1680 if (!_dbus_test_oom_handling (
"spawn_and_kill",
1681 check_spawn_and_kill,
dbus_bool_t dbus_error_has_name(const DBusError *error, const char *name)
Checks whether the error is set and has the given name.
const char * message
public error message field
#define DBUS_ERROR_SPAWN_FAILED
While starting a new process, something went wrong.
Implementation of DBusWatch.
#define NULL
A null pointer, defined appropriately for C or C++.
#define DBUS_ERROR_SPAWN_EXEC_FAILED
While starting a new process, the exec() call failed.
void(* DBusFreeFunction)(void *memory)
The type of a function which frees a block of memory.
#define LIVE_CHILDREN(sitter)
Macro returns TRUE if the babysitter still has live sockets open to the babysitter child or the grand...
#define _DBUS_POLLHUP
Hung up.
unsigned int have_exec_errnum
True if we have an error code from exec()
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
DBusWatch * error_watch
Error pipe watch.
DBusWatchList * _dbus_watch_list_new(void)
Creates a new watch list.
void _dbus_watch_invalidate(DBusWatch *watch)
Clears the file descriptor from a now-invalid watch object so that no one tries to use it...
#define DBUS_PID_FORMAT
an appropriate printf format for dbus_pid_t
void(* DBusWatchToggledFunction)(DBusWatch *watch, void *data)
Called when dbus_watch_get_enabled() may return a different value than it did before.
#define DBUS_ERROR_SPAWN_CHILD_EXITED
While starting a new process, the child exited with a status code.
int status
Exit status code.
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
int socket_to_babysitter
Connection to the babysitter process.
dbus_bool_t _dbus_full_duplex_pipe(int *fd1, int *fd2, dbus_bool_t blocking, DBusError *error)
Creates a full-duplex pipe (as in socketpair()).
#define DBUS_ERROR_INIT
Expands to a suitable initializer for a DBusError on the stack.
dbus_bool_t _dbus_watch_list_add_watch(DBusWatchList *watch_list, DBusWatch *watch)
Adds a new watch to the watch list, invoking the application DBusAddWatchFunction if appropriate...
void dbus_error_free(DBusError *error)
Frees an error that's been set (or just initialized), then reinitializes the error as in dbus_error_i...
A portable struct pollfd wrapper.
#define _DBUS_POLLIN
There is data to read.
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
dbus_pid_t _dbus_getpid(void)
Gets our process ID.
short events
Events to poll for.
dbus_bool_t _dbus_babysitter_get_child_exited(DBusBabysitter *sitter)
Checks whether the child has exited, without blocking.
const char * _dbus_getenv(const char *varname)
Wrapper for getenv().
DBusWatchList * watches
Watches.
void _dbus_fd_set_close_on_exec(intptr_t fd)
Sets the file descriptor to be close on exec.
#define DBUS_ERROR_SPAWN_CHILD_SIGNALED
While starting a new process, the child exited on a signal.
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
DBusWatch * sitter_watch
Sitter pipe watch.
DBUS_EXPORT int dbus_watch_get_socket(DBusWatch *watch)
Returns a socket to be watched, on UNIX this will return -1 if our transport is not socket-based so d...
dbus_bool_t _dbus_babysitter_get_child_exit_status(DBusBabysitter *sitter, int *status)
Gets the exit status of the child.
void _dbus_babysitter_kill_child(DBusBabysitter *sitter)
Blocks until the babysitter process gives us the PID of the spawned grandchild, then kills the spawne...
Babysitter implementation details.
ReadStatus
Enumeration for status of a read()
int _dbus_poll(DBusPollFD *fds, int n_fds, int timeout_milliseconds)
Wrapper for poll().
dbus_bool_t _dbus_spawn_async_with_babysitter(DBusBabysitter **sitter_p, const char *log_name, char **argv, char **env, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error)
Spawns a new process.
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
pid_t sitter_pid
PID Of the babysitter.
dbus_bool_t _dbus_string_append_printf(DBusString *str, const char *format,...)
Appends a printf-style formatted string to the DBusString.
dbus_bool_t _dbus_babysitter_set_watch_functions(DBusBabysitter *sitter, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function)
Sets watch functions to notify us when the babysitter object needs to read/write file descriptors...
Object representing an exception.
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
pid_t grandchild_pid
PID of the grandchild.
#define _DBUS_N_ELEMENTS(array)
Computes the number of elements in a fixed-size array using sizeof().
int refcount
Reference count.
As in POLLERR (can't watch for this, but can be present in current state passed to dbus_watch_handle(...
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
#define TRUE
Expands to "1".
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
As in POLLHUP (can't watch for it, but can be present in current state passed to dbus_watch_handle())...
#define DBUS_ERROR_FAILED
A generic error; "something went wrong" - see the error message for more.
const char * name
public error name field
dbus_bool_t(* DBusAddWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus needs a new watch to be monitored by the main loop.
#define READ_END
Helps remember which end of the pipe is which.
void(* DBusRemoveWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus no longer needs a watch to be monitored by the main loop.
DBusWatchList implementation details.
void _dbus_babysitter_unref(DBusBabysitter *sitter)
Decrement the reference count on the babysitter object.
dbus_bool_t _dbus_watch_list_set_functions(DBusWatchList *watch_list, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function)
Sets the watch functions.
#define DBUS_ERROR_SPAWN_FORK_FAILED
While starting a new process, the fork() call failed.
void _dbus_set_signal_handler(int sig, DBusSignalHandler handler)
Installs a UNIX signal handler.
DBusWatch * _dbus_watch_new(int fd, unsigned int flags, dbus_bool_t enabled, DBusWatchHandler handler, void *data, DBusFreeFunction free_data_function)
Creates a new DBusWatch.
void dbus_free_string_array(char **str_array)
Frees a NULL-terminated array of strings.
char * log_name
the name under which to log messages about this process being spawned
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
unsigned int have_fork_errnum
True if we have an error code from fork()
#define FALSE
Expands to "0".
int error_pipe_from_child
Connection to the process that does the exec()
void _dbus_watch_unref(DBusWatch *watch)
Decrements the reference count of a DBusWatch object and finalizes the object if the count reaches ze...
#define WRITE_END
Helps remember which end of the pipe is which.
void _dbus_watch_list_free(DBusWatchList *watch_list)
Frees a DBusWatchList.
char * _dbus_strdup(const char *str)
Duplicates a string.
dbus_bool_t _dbus_close_socket(int fd, DBusError *error)
Closes a socket.
void _dbus_babysitter_set_child_exit_error(DBusBabysitter *sitter, DBusError *error)
Sets the DBusError with an explanation of why the spawned child process exited (on a signal...
short revents
Events that occurred.
dbus_bool_t dbus_error_is_set(const DBusError *error)
Checks whether an error occurred (the error is set).
void _dbus_watch_list_remove_watch(DBusWatchList *watch_list, DBusWatch *watch)
Removes a watch from the watch list, invoking the application's DBusRemoveWatchFunction if appropriat...
#define _DBUS_POLLERR
Error condition.
DBusBabysitter * _dbus_babysitter_ref(DBusBabysitter *sitter)
Increment the reference count on the babysitter object.