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 #if defined(__APPLE__)    49 # include <crt_externs.h>    50 # define environ (*_NSGetEnviron ())    51 #elif !HAVE_DECL_ENVIRON    52 extern char **environ;
    85   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    94       to_read = 
sizeof (int) * n_ints_in_buf - bytes;
   102                     ((
char*)buf) + bytes,
   105       if (chunk < 0 && errno == EINTR)
   112                           "Failed to read from child pipe (%s)",
   113                           _dbus_strerror (errno));
   127   *n_ints_read = (int)(bytes / 
sizeof(
int));
   140   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   149       to_read = 
sizeof (pid_t) - bytes;
   157                     ((
char*)buf) + bytes,
   159       if (chunk < 0 && errno == EINTR)
   166                           "Failed to read from child pipe (%s)",
   167                           _dbus_strerror (errno));
   262   DBusBabysitterFinishedFunc finished_cb;
   273 _dbus_babysitter_new (
void)
   281   sitter->refcount = 1;
   312   sitter->refcount += 1;
   334   sitter->refcount -= 1;
   335   if (sitter->refcount == 0)
   344       close_socket_to_babysitter (sitter);
   346       close_error_pipe_from_child (sitter);
   357           ret = waitpid (sitter->
sitter_pid, &status, WNOHANG);
   369                   ret = waitpid (sitter->
sitter_pid, &status, 0);
   371               while (_DBUS_UNLIKELY (ret < 0 && errno == EINTR));
   377                 _dbus_warn (
"Babysitter process not available to be reaped; should not happen");
   379                 _dbus_warn (
"Unexpected error %d in waitpid() for babysitter: %s",
   380                             errno, _dbus_strerror (errno));
   384               _dbus_verbose (
"Reaped %ld, waiting for babysitter %ld\n",
   387               if (WIFEXITED (sitter->
status))
   388                 _dbus_verbose (
"Babysitter exited with status %d\n",
   389                                WEXITSTATUS (sitter->
status));
   390               else if (WIFSIGNALED (sitter->
status))
   391                 _dbus_verbose (
"Babysitter received signal %d\n",
   392                                WTERMSIG (sitter->
status));
   394                 _dbus_verbose (
"Babysitter exited abnormally\n");
   418   r = read_ints (fd, &what, 1, &got, &error);
   443         case CHILD_FORK_FAILED:
   444         case CHILD_EXEC_FAILED:
   448             r = read_ints (fd, &arg, 1, &got, &error);
   467                 if (what == CHILD_EXITED)
   486                     sitter->have_child_status = 
TRUE;
   488                     _dbus_verbose (
"recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
   489                                    WIFEXITED (sitter->
status), WIFSIGNALED (sitter->
status),
   490                                    WEXITSTATUS (sitter->
status), WTERMSIG (sitter->
status));
   492                 else if (what == CHILD_FORK_FAILED)
   496                     _dbus_verbose (
"recorded fork errnum %d\n", sitter->
errnum);
   498                 else if (what == CHILD_EXEC_FAILED)
   502                     _dbus_verbose (
"recorded exec errnum %d\n", sitter->
errnum);
   511             r = read_pid (fd, &pid, &error);
   530             _dbus_verbose (
"recorded grandchild pid %d\n", sitter->
grandchild_pid);
   534           _dbus_warn (
"Unknown message received from babysitter process");
   545   _dbus_verbose (
"Closing babysitter\n");
   566   _dbus_verbose (
"Closing child error\n");
   594       _dbus_verbose (
"Reading data from babysitter\n");
   596         close_socket_to_babysitter (sitter);
   600       close_socket_to_babysitter (sitter);
   610       _dbus_verbose (
"Reading data from child error\n");
   612         close_error_pipe_from_child (sitter);
   616       close_error_pipe_from_child (sitter);
   629   descriptors_ready = 
FALSE;
   657       while (ret < 0 && errno == EINTR);
   659       if (ret == 0 && block)
   665           while (ret < 0 && errno == EINTR);
   670           descriptors_ready = 
TRUE;
   676                 handle_error_pipe (sitter, fds[i].revents);
   678                 handle_babysitter_socket (sitter, fds[i].revents);
   683   return descriptors_ready;
   690 #define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter.fd >= 0 || (sitter)->error_pipe_from_child >= 0)   704     babysitter_iteration (sitter, 
TRUE);
   706   _dbus_verbose (
"Got child PID %ld for killing\n",
   726          babysitter_iteration (sitter, 
FALSE))
   752   if (!sitter->have_child_status ||
   753       !(WIFEXITED (sitter->
status)))
   756   *status = WEXITSTATUS (sitter->
status);
   783                       "Failed to execute program %s: %s",
   789                       "Failed to fork a new process %s: %s",
   792   else if (sitter->have_child_status)
   794       if (WIFEXITED (sitter->
status))
   796                         "Process %s exited with status %d",
   798       else if (WIFSIGNALED (sitter->
status))
   800                         "Process %s received signal %d",
   804                         "Process %s exited abnormally",
   810                       "Process %s exited, reason unknown",
   845               unsigned int     condition,
   863     handle_error_pipe (sitter, revents);
   865     handle_babysitter_socket (sitter, revents);
   868          babysitter_iteration (sitter, 
FALSE))
   877       sitter->finished_cb != 
NULL)
   879       sitter->finished_cb (sitter, sitter->finished_data);
   880       sitter->finished_cb = 
NULL;
   903 close_and_invalidate (
int *fd)
   927   retval = pipe2 (p, O_CLOEXEC);
   928   cloexec_done = retval >= 0;
   932   if (retval < 0 && errno == ENOSYS)
   938   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   944                       "Failed to create pipe for communicating with child process (%s)",
   945                       _dbus_strerror (errno));
   961 do_write (
int fd, 
const void *buf, 
size_t count)
   963   size_t bytes_written;
   970   ret = write (fd, ((
const char*)buf) + bytes_written, count - bytes_written);
   983     bytes_written += ret;
   985   if (bytes_written < count)
   989 static void write_err_and_exit (
int fd, 
int msg) _DBUS_GNUC_NORETURN;
   992 write_err_and_exit (
int fd, 
int msg)
   996   do_write (fd, &msg, 
sizeof (msg));
   997   do_write (fd, &en, 
sizeof (en));
  1003 write_pid (
int fd, pid_t pid)
  1005   int msg = CHILD_PID;
  1007   do_write (fd, &msg, 
sizeof (msg));
  1008   do_write (fd, &pid, 
sizeof (pid));
  1011 static void write_status_and_exit (
int fd, 
int status) _DBUS_GNUC_NORETURN;
  1014 write_status_and_exit (
int fd, 
int status)
  1016   int msg = CHILD_EXITED;
  1018   do_write (fd, &msg, 
sizeof (msg));
  1019   do_write (fd, &status, 
sizeof (status));
  1024 static void do_exec (
int                       child_err_report_fd,
  1027                      DBusSpawnChildSetupFunc   child_setup,
  1028                      void                     *user_data) _DBUS_GNUC_NORETURN;
  1031 do_exec (
int                       child_err_report_fd,
  1034          DBusSpawnChildSetupFunc   child_setup,
  1037 #ifdef DBUS_ENABLE_EMBEDDED_TESTS  1041   _dbus_verbose_reset ();
  1046     (* child_setup) (user_data);
  1048 #ifdef DBUS_ENABLE_EMBEDDED_TESTS  1049   max_open = sysconf (_SC_OPEN_MAX);
  1051   for (i = 3; i < max_open; i++)
  1055       if (i == child_err_report_fd)
  1058       retval = fcntl (i, F_GETFD);
  1060       if (retval != -1 && !(retval & FD_CLOEXEC))
  1061         _dbus_warn (
"Fd %d did not have the close-on-exec flag set!", i);
  1072   execve (argv[0], argv, envp);
  1075   write_err_and_exit (child_err_report_fd,
  1080 check_babysit_events (pid_t grandchild_pid,
  1089       ret = waitpid (grandchild_pid, &status, WNOHANG);
  1094   while (ret < 0 && errno == EINTR);
  1098       _dbus_verbose (
"no child exited\n");
  1105       _dbus_warn (
"unexpected waitpid() failure in check_babysit_events(): %s",
  1106                   _dbus_strerror (errno));
  1109   else if (ret == grandchild_pid)
  1112       _dbus_verbose (
"reaped child pid %ld\n", (
long) ret);
  1114       write_status_and_exit (parent_pipe, status);
  1118       _dbus_warn (
"waitpid() reaped pid %d that we've never heard of",
  1125       _dbus_verbose (
"babysitter got POLLIN from parent pipe\n");
  1131       _dbus_verbose (
"babysitter got POLLERR or POLLHUP from parent\n");
  1136 static int babysit_sigchld_pipe = -1;
  1139 babysit_signal_handler (
int signo)
  1143   int saved_errno = errno;
  1147   if (write (babysit_sigchld_pipe, &b, 1) <= 0) 
  1151   errno = saved_errno;
  1154 static void babysit (pid_t grandchild_pid,
  1155                      int   parent_pipe) _DBUS_GNUC_NORETURN;
  1158 babysit (pid_t grandchild_pid,
  1161   int sigchld_pipe[2];
  1166   _dbus_verbose_reset ();
  1173   if (pipe (sigchld_pipe) < 0)
  1175       _dbus_warn (
"Not enough file descriptors to create pipe in babysitter process");
  1179   babysit_sigchld_pipe = sigchld_pipe[
WRITE_END];
  1183   write_pid (parent_pipe, grandchild_pid);
  1185   check_babysit_events (grandchild_pid, parent_pipe, 0);
  1191       pfds[0].
fd = parent_pipe;
  1201           _dbus_warn (
"_dbus_poll() error: %s", strerror (errno));
  1205       if (pfds[0].revents != 0)
  1207           check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
  1212           if (read (sigchld_pipe[
READ_END], &b, 1) == -1)
  1217           check_babysit_events (grandchild_pid, parent_pipe, 0);
  1250                                    const char               *log_name,
  1253                                    DBusSpawnFlags            flags,
  1254                                    DBusSpawnChildSetupFunc   child_setup,
  1259   int child_err_report_pipe[2] = { -1, -1 };
  1260   DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT };
  1267   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  1270   if (sitter_p != 
NULL)
  1275   sitter = _dbus_babysitter_new ();
  1286       goto cleanup_and_fail;
  1295       goto cleanup_and_fail;
  1298   if (!make_pipe (child_err_report_pipe, error))
  1299     goto cleanup_and_fail;
  1302     goto cleanup_and_fail;
  1315       goto cleanup_and_fail;
  1327       goto cleanup_and_fail;
  1336       goto cleanup_and_fail;
  1348       goto cleanup_and_fail;
  1351   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  1354   if (flags & DBUS_SPAWN_REDIRECT_OUTPUT)
  1360       fd_out = sd_journal_stream_fd (sitter->
log_name, LOG_INFO, 
FALSE);
  1361       fd_err = sd_journal_stream_fd (sitter->
log_name, LOG_WARNING, 
FALSE);
  1371                       "Failed to fork (%s)",
  1372                       _dbus_strerror (errno));
  1373       goto cleanup_and_fail;
  1383       signal (SIGPIPE, SIG_DFL);
  1386       close_and_invalidate (&child_err_report_pipe[
READ_END]);
  1387       close_and_invalidate (&babysitter_pipe[0].fd);
  1390       grandchild_pid = fork ();
  1392       if (grandchild_pid < 0)
  1394           write_err_and_exit (babysitter_pipe[1].fd,
  1398       else if (grandchild_pid == 0)
  1404           fd = open (
"/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
  1409               fd = open (
"/proc/self/oom_score_adj", O_WRONLY);
  1415               if (write (fd, 
"0", 
sizeof (
char)) < 0)
  1416                 _dbus_warn (
"writing oom_score_adj error: %s", strerror (errno));
  1422           signal (SIGPIPE, SIG_IGN);
  1424           close_and_invalidate (&babysitter_pipe[1].fd);
  1428             dup2 (fd_out, STDOUT_FILENO);
  1430             dup2 (fd_err, STDERR_FILENO);
  1431           close_and_invalidate (&fd_out);
  1432           close_and_invalidate (&fd_err);
  1434           do_exec (child_err_report_pipe[
WRITE_END],
  1437                    child_setup, user_data);
  1442           close_and_invalidate (&child_err_report_pipe[
WRITE_END]);
  1444           close_and_invalidate (&fd_out);
  1445           close_and_invalidate (&fd_err);
  1447           babysit (grandchild_pid, babysitter_pipe[1].fd);
  1454       close_and_invalidate (&child_err_report_pipe[
WRITE_END]);
  1455       close_and_invalidate (&babysitter_pipe[1].fd);
  1457       close_and_invalidate (&fd_out);
  1458       close_and_invalidate (&fd_err);
  1462       babysitter_pipe[0].fd = -1;
  1465       child_err_report_pipe[
READ_END] = -1;
  1469       if (sitter_p != 
NULL)
  1476       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  1483   _DBUS_ASSERT_ERROR_IS_SET (error);
  1485   close_and_invalidate (&child_err_report_pipe[
READ_END]);
  1486   close_and_invalidate (&child_err_report_pipe[
WRITE_END]);
  1487   close_and_invalidate (&babysitter_pipe[0].fd);
  1488   close_and_invalidate (&babysitter_pipe[1].fd);
  1490   close_and_invalidate (&fd_out);
  1491   close_and_invalidate (&fd_err);
  1502                                        DBusBabysitterFinishedFunc  finished,
  1505   sitter->finished_cb = finished;
  1506   sitter->finished_data = user_data;
  1515     babysitter_iteration (sitter, 
TRUE);
 const char * message
public error message field 
#define DBUS_ERROR_SPAWN_FAILED
While starting a new process, something went wrong. 
DBusWatch * _dbus_watch_new(DBusPollable fd, unsigned int flags, dbus_bool_t enabled, DBusWatchHandler handler, void *data, DBusFreeFunction free_data_function)
Creates a new DBusWatch. 
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. 
dbus_bool_t _dbus_socketpair(DBusSocket *fd1, DBusSocket *fd2, dbus_bool_t blocking, DBusError *error)
Creates pair of connect sockets (as in socketpair()). 
#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. 
#define DBUS_ERROR_INIT
Expands to a suitable initializer for a DBusError on the stack. 
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...
void _dbus_watch_list_free(DBusWatchList *watch_list)
Frees a DBusWatchList. 
dbus_pid_t _dbus_getpid(void)
Gets our process ID. 
#define _DBUS_POLLIN
There is data to read. 
DBusWatchList * _dbus_watch_list_new(void)
Creates a new watch list. 
short events
Events to poll for. 
dbus_bool_t _dbus_close_socket(DBusSocket fd, DBusError *error)
Closes a socket. 
dbus_bool_t _dbus_babysitter_get_child_exited(DBusBabysitter *sitter)
Checks whether the child has exited, without blocking. 
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. 
void _dbus_set_signal_handler(int sig, DBusSignalHandler handler)
Installs a UNIX signal handler. 
DBusWatchList * watches
Watches. 
#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() 
void _dbus_warn(const char *format,...)
Prints a warning message to stderr. 
pid_t sitter_pid
PID Of the babysitter. 
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)
Spawns a new process. 
void _dbus_watch_invalidate(DBusWatch *watch)
Clears the file descriptor from a now-invalid watch object so that no one tries to use it...
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. 
unsigned int have_child_status
True if child status has been reaped. 
As in POLLERR (can't watch for this, but can be present in current state passed to dbus_watch_handle(...
#define TRUE
Expands to "1". 
DBusPollable fd
File descriptor. 
#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. 
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...
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_fd_set_close_on_exec(int fd)
Sets the file descriptor to be close on exec. 
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...
void _dbus_babysitter_unref(DBusBabysitter *sitter)
Decrement the reference count on the babysitter object. 
#define DBUS_ERROR_SPAWN_FORK_FAILED
While starting a new process, the fork() call failed. 
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 
void _dbus_watch_unref(DBusWatch *watch)
Decrements the reference count of a DBusWatch object and finalizes the object if the count reaches ze...
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation. 
dbus_bool_t _dbus_close(int fd, DBusError *error)
Closes a file descriptor. 
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() 
DBusSocket socket_to_babysitter
Connection to the babysitter process. 
#define WRITE_END
Helps remember which end of the pipe is which. 
char * _dbus_strdup(const char *str)
Duplicates a string. 
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...
int _dbus_poll(DBusPollFD *fds, int n_fds, int timeout_milliseconds)
Wrapper for poll(). 
short revents
Events that occurred. 
#define _DBUS_POLLERR
Error condition. 
DBusBabysitter * _dbus_babysitter_ref(DBusBabysitter *sitter)
Increment the reference count on the babysitter object.