00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "dbus-spawn.h"
00025 #include "dbus-sysdeps.h"
00026 #include "dbus-internals.h"
00027 #include "dbus-test.h"
00028
00029 #include <unistd.h>
00030 #include <fcntl.h>
00031 #include <signal.h>
00032 #include <sys/wait.h>
00033 #include <errno.h>
00034 #include <stdlib.h>
00035
00041
00042
00043
00044
00045
00049 typedef enum
00050 {
00051 READ_STATUS_OK,
00052 READ_STATUS_ERROR,
00053 READ_STATUS_EOF
00054 } ReadStatus;
00055
00056 static ReadStatus
00057 read_ints (int fd,
00058 int *buf,
00059 int n_ints_in_buf,
00060 int *n_ints_read,
00061 DBusError *error)
00062 {
00063 size_t bytes = 0;
00064 ReadStatus retval;
00065
00066 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00067
00068 retval = READ_STATUS_OK;
00069
00070 while (TRUE)
00071 {
00072 size_t chunk;
00073 size_t to_read;
00074
00075 again:
00076
00077 to_read = sizeof (int) * n_ints_in_buf - bytes;
00078
00079 if (to_read == 0)
00080 break;
00081
00082 chunk = read (fd,
00083 ((char*)buf) + bytes,
00084 to_read);
00085
00086 if (chunk < 0 && errno == EINTR)
00087 goto again;
00088
00089 if (chunk < 0)
00090 {
00091 dbus_set_error (error,
00092 DBUS_ERROR_SPAWN_FAILED,
00093 "Failed to read from child pipe (%s)",
00094 _dbus_strerror (errno));
00095
00096 retval = READ_STATUS_ERROR;
00097 break;
00098 }
00099 else if (chunk == 0)
00100 {
00101 retval = READ_STATUS_EOF;
00102 break;
00103 }
00104 else
00105 bytes += chunk;
00106 }
00107
00108 *n_ints_read = (int)(bytes / sizeof(int));
00109
00110 return retval;
00111 }
00112
00113 static ReadStatus
00114 read_pid (int fd,
00115 pid_t *buf,
00116 DBusError *error)
00117 {
00118 size_t bytes = 0;
00119 ReadStatus retval;
00120
00121 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00122
00123 retval = READ_STATUS_OK;
00124
00125 while (TRUE)
00126 {
00127 size_t chunk;
00128 size_t to_read;
00129
00130 again:
00131 to_read = sizeof (pid_t) - bytes;
00132
00133 if (to_read == 0)
00134 break;
00135
00136 chunk = read (fd,
00137 ((char*)buf) + bytes,
00138 to_read);
00139 if (chunk < 0 && errno == EINTR)
00140 goto again;
00141
00142 if (chunk < 0)
00143 {
00144 dbus_set_error (error,
00145 DBUS_ERROR_SPAWN_FAILED,
00146 "Failed to read from child pipe (%s)",
00147 _dbus_strerror (errno));
00148
00149 retval = READ_STATUS_ERROR;
00150 break;
00151 }
00152 else if (chunk == 0)
00153 {
00154 retval = READ_STATUS_EOF;
00155 break;
00156 }
00157 else
00158 bytes += chunk;
00159 }
00160
00161 return retval;
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171 enum
00172 {
00173 CHILD_EXITED,
00174 CHILD_FORK_FAILED,
00175 CHILD_EXEC_FAILED,
00176 CHILD_PID
00177 };
00178
00182 struct DBusBabysitter
00183 {
00184 int refcount;
00186 char *executable;
00188 int socket_to_babysitter;
00189 int error_pipe_from_child;
00191 pid_t sitter_pid;
00192 pid_t grandchild_pid;
00194 DBusWatchList *watches;
00196 DBusWatch *error_watch;
00197 DBusWatch *sitter_watch;
00199 int errnum;
00200 int status;
00201 unsigned int have_child_status : 1;
00202 unsigned int have_fork_errnum : 1;
00203 unsigned int have_exec_errnum : 1;
00204 };
00205
00206 static DBusBabysitter*
00207 _dbus_babysitter_new (void)
00208 {
00209 DBusBabysitter *sitter;
00210
00211 sitter = dbus_new0 (DBusBabysitter, 1);
00212 if (sitter == NULL)
00213 return NULL;
00214
00215 sitter->refcount = 1;
00216
00217 sitter->socket_to_babysitter = -1;
00218 sitter->error_pipe_from_child = -1;
00219
00220 sitter->sitter_pid = -1;
00221 sitter->grandchild_pid = -1;
00222
00223 sitter->watches = _dbus_watch_list_new ();
00224 if (sitter->watches == NULL)
00225 goto failed;
00226
00227 return sitter;
00228
00229 failed:
00230 _dbus_babysitter_unref (sitter);
00231 return NULL;
00232 }
00233
00239 void
00240 _dbus_babysitter_ref (DBusBabysitter *sitter)
00241 {
00242 _dbus_assert (sitter != NULL);
00243 _dbus_assert (sitter->refcount > 0);
00244
00245 sitter->refcount += 1;
00246 }
00247
00253 void
00254 _dbus_babysitter_unref (DBusBabysitter *sitter)
00255 {
00256 _dbus_assert (sitter != NULL);
00257 _dbus_assert (sitter->refcount > 0);
00258
00259 sitter->refcount -= 1;
00260 if (sitter->refcount == 0)
00261 {
00262 if (sitter->socket_to_babysitter >= 0)
00263 {
00264 close (sitter->socket_to_babysitter);
00265 sitter->socket_to_babysitter = -1;
00266 }
00267
00268 if (sitter->error_pipe_from_child >= 0)
00269 {
00270 close (sitter->error_pipe_from_child);
00271 sitter->error_pipe_from_child = -1;
00272 }
00273
00274 if (sitter->sitter_pid != -1)
00275 {
00276 int status;
00277 int ret;
00278
00279
00280 again:
00281 ret = waitpid (sitter->sitter_pid, &status, 0);
00282 if (ret < 0)
00283 {
00284 if (errno == EINTR)
00285 goto again;
00286 else if (errno == ECHILD)
00287 _dbus_warn ("Babysitter process not available to be reaped; should not happen\n");
00288 else
00289 _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s\n",
00290 errno, _dbus_strerror (errno));
00291 }
00292 else
00293 {
00294 _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n",
00295 (long) ret, (long) sitter->sitter_pid);
00296
00297 if (WIFEXITED (sitter->status))
00298 _dbus_verbose ("Babysitter exited with status %d\n",
00299 WEXITSTATUS (sitter->status));
00300 else if (WIFSIGNALED (sitter->status))
00301 _dbus_verbose ("Babysitter received signal %d\n",
00302 WTERMSIG (sitter->status));
00303 else
00304 _dbus_verbose ("Babysitter exited abnormally\n");
00305 }
00306
00307 sitter->sitter_pid = -1;
00308 }
00309
00310 if (sitter->error_watch)
00311 {
00312 _dbus_watch_invalidate (sitter->error_watch);
00313 _dbus_watch_unref (sitter->error_watch);
00314 sitter->error_watch = NULL;
00315 }
00316
00317 if (sitter->sitter_watch)
00318 {
00319 _dbus_watch_invalidate (sitter->sitter_watch);
00320 _dbus_watch_unref (sitter->sitter_watch);
00321 sitter->sitter_watch = NULL;
00322 }
00323
00324 if (sitter->watches)
00325 _dbus_watch_list_free (sitter->watches);
00326
00327 dbus_free (sitter->executable);
00328
00329 dbus_free (sitter);
00330 }
00331 }
00332
00333 static ReadStatus
00334 read_data (DBusBabysitter *sitter,
00335 int fd)
00336 {
00337 int what;
00338 int got;
00339 DBusError error;
00340 ReadStatus r;
00341
00342 dbus_error_init (&error);
00343
00344 r = read_ints (fd, &what, 1, &got, &error);
00345
00346 switch (r)
00347 {
00348 case READ_STATUS_ERROR:
00349 _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message);
00350 dbus_error_free (&error);
00351 return r;
00352
00353 case READ_STATUS_EOF:
00354 return r;
00355
00356 case READ_STATUS_OK:
00357 break;
00358 }
00359
00360 if (got == 1)
00361 {
00362 switch (what)
00363 {
00364 case CHILD_EXITED:
00365 case CHILD_FORK_FAILED:
00366 case CHILD_EXEC_FAILED:
00367 {
00368 int arg;
00369
00370 r = read_ints (fd, &arg, 1, &got, &error);
00371
00372 switch (r)
00373 {
00374 case READ_STATUS_ERROR:
00375 _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message);
00376 dbus_error_free (&error);
00377 return r;
00378 case READ_STATUS_EOF:
00379 return r;
00380 case READ_STATUS_OK:
00381 break;
00382 }
00383
00384 if (got == 1)
00385 {
00386 if (what == CHILD_EXITED)
00387 {
00388 sitter->have_child_status = TRUE;
00389 sitter->status = arg;
00390 _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
00391 WIFEXITED (sitter->status), WIFSIGNALED (sitter->status),
00392 WEXITSTATUS (sitter->status), WTERMSIG (sitter->status));
00393 }
00394 else if (what == CHILD_FORK_FAILED)
00395 {
00396 sitter->have_fork_errnum = TRUE;
00397 sitter->errnum = arg;
00398 _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum);
00399 }
00400 else if (what == CHILD_EXEC_FAILED)
00401 {
00402 sitter->have_exec_errnum = TRUE;
00403 sitter->errnum = arg;
00404 _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum);
00405 }
00406 }
00407 }
00408 break;
00409 case CHILD_PID:
00410 {
00411 pid_t pid = -1;
00412
00413 r = read_pid (fd, &pid, &error);
00414
00415 switch (r)
00416 {
00417 case READ_STATUS_ERROR:
00418 _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message);
00419 dbus_error_free (&error);
00420 return r;
00421 case READ_STATUS_EOF:
00422 return r;
00423 case READ_STATUS_OK:
00424 break;
00425 }
00426
00427 sitter->grandchild_pid = pid;
00428
00429 _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid);
00430 }
00431 break;
00432 default:
00433 _dbus_warn ("Unknown message received from babysitter process\n");
00434 break;
00435 }
00436 }
00437
00438 return r;
00439 }
00440
00441 static void
00442 close_socket_to_babysitter (DBusBabysitter *sitter)
00443 {
00444 _dbus_verbose ("Closing babysitter\n");
00445 close (sitter->socket_to_babysitter);
00446 sitter->socket_to_babysitter = -1;
00447 }
00448
00449 static void
00450 close_error_pipe_from_child (DBusBabysitter *sitter)
00451 {
00452 _dbus_verbose ("Closing child error\n");
00453 close (sitter->error_pipe_from_child);
00454 sitter->error_pipe_from_child = -1;
00455 }
00456
00457 static void
00458 handle_babysitter_socket (DBusBabysitter *sitter,
00459 int revents)
00460 {
00461
00462
00463
00464
00465 if (revents & _DBUS_POLLIN)
00466 {
00467 _dbus_verbose ("Reading data from babysitter\n");
00468 if (read_data (sitter, sitter->socket_to_babysitter) != READ_STATUS_OK)
00469 close_socket_to_babysitter (sitter);
00470 }
00471 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00472 {
00473 close_socket_to_babysitter (sitter);
00474 }
00475 }
00476
00477 static void
00478 handle_error_pipe (DBusBabysitter *sitter,
00479 int revents)
00480 {
00481 if (revents & _DBUS_POLLIN)
00482 {
00483 _dbus_verbose ("Reading data from child error\n");
00484 if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK)
00485 close_error_pipe_from_child (sitter);
00486 }
00487 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00488 {
00489 close_error_pipe_from_child (sitter);
00490 }
00491 }
00492
00493
00494 static dbus_bool_t
00495 babysitter_iteration (DBusBabysitter *sitter,
00496 dbus_bool_t block)
00497 {
00498 DBusPollFD fds[2];
00499 int i;
00500 dbus_bool_t descriptors_ready;
00501
00502 descriptors_ready = FALSE;
00503
00504 i = 0;
00505
00506 if (sitter->error_pipe_from_child >= 0)
00507 {
00508 fds[i].fd = sitter->error_pipe_from_child;
00509 fds[i].events = _DBUS_POLLIN;
00510 fds[i].revents = 0;
00511 ++i;
00512 }
00513
00514 if (sitter->socket_to_babysitter >= 0)
00515 {
00516 fds[i].fd = sitter->socket_to_babysitter;
00517 fds[i].events = _DBUS_POLLIN;
00518 fds[i].revents = 0;
00519 ++i;
00520 }
00521
00522 if (i > 0)
00523 {
00524 int ret;
00525
00526 ret = _dbus_poll (fds, i, 0);
00527 if (ret == 0 && block)
00528 ret = _dbus_poll (fds, i, -1);
00529
00530 if (ret > 0)
00531 {
00532 descriptors_ready = TRUE;
00533
00534 while (i > 0)
00535 {
00536 --i;
00537 if (fds[i].fd == sitter->error_pipe_from_child)
00538 handle_error_pipe (sitter, fds[i].revents);
00539 else if (fds[i].fd == sitter->socket_to_babysitter)
00540 handle_babysitter_socket (sitter, fds[i].revents);
00541 }
00542 }
00543 }
00544
00545 return descriptors_ready;
00546 }
00547
00552 #define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter >= 0 || (sitter)->error_pipe_from_child >= 0)
00553
00560 void
00561 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
00562 {
00563
00564 while (LIVE_CHILDREN (sitter) &&
00565 sitter->grandchild_pid == -1)
00566 babysitter_iteration (sitter, TRUE);
00567
00568 _dbus_verbose ("Got child PID %ld for killing\n",
00569 (long) sitter->grandchild_pid);
00570
00571 if (sitter->grandchild_pid == -1)
00572 return;
00573
00574 kill (sitter->grandchild_pid, SIGKILL);
00575 }
00576
00582 dbus_bool_t
00583 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
00584 {
00585
00586
00587 while (LIVE_CHILDREN (sitter) &&
00588 babysitter_iteration (sitter, FALSE))
00589 ;
00590
00591
00592 return sitter->socket_to_babysitter < 0;
00593 }
00594
00604 void
00605 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
00606 DBusError *error)
00607 {
00608 if (!_dbus_babysitter_get_child_exited (sitter))
00609 return;
00610
00611
00612
00613
00614
00615 if (sitter->have_exec_errnum)
00616 {
00617 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00618 "Failed to execute program %s: %s",
00619 sitter->executable, _dbus_strerror (sitter->errnum));
00620 }
00621 else if (sitter->have_fork_errnum)
00622 {
00623 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00624 "Failed to fork a new process %s: %s",
00625 sitter->executable, _dbus_strerror (sitter->errnum));
00626 }
00627 else if (sitter->have_child_status)
00628 {
00629 if (WIFEXITED (sitter->status))
00630 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00631 "Process %s exited with status %d",
00632 sitter->executable, WEXITSTATUS (sitter->status));
00633 else if (WIFSIGNALED (sitter->status))
00634 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,
00635 "Process %s received signal %d",
00636 sitter->executable, WTERMSIG (sitter->status));
00637 else
00638 dbus_set_error (error, DBUS_ERROR_FAILED,
00639 "Process %s exited abnormally",
00640 sitter->executable);
00641 }
00642 else
00643 {
00644 dbus_set_error (error, DBUS_ERROR_FAILED,
00645 "Process %s exited, reason unknown",
00646 sitter->executable);
00647 }
00648 }
00649
00662 dbus_bool_t
00663 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter,
00664 DBusAddWatchFunction add_function,
00665 DBusRemoveWatchFunction remove_function,
00666 DBusWatchToggledFunction toggled_function,
00667 void *data,
00668 DBusFreeFunction free_data_function)
00669 {
00670 return _dbus_watch_list_set_functions (sitter->watches,
00671 add_function,
00672 remove_function,
00673 toggled_function,
00674 data,
00675 free_data_function);
00676 }
00677
00678 static dbus_bool_t
00679 handle_watch (DBusWatch *watch,
00680 unsigned int condition,
00681 void *data)
00682 {
00683 DBusBabysitter *sitter = data;
00684 int revents;
00685 int fd;
00686
00687 revents = 0;
00688 if (condition & DBUS_WATCH_READABLE)
00689 revents |= _DBUS_POLLIN;
00690 if (condition & DBUS_WATCH_ERROR)
00691 revents |= _DBUS_POLLERR;
00692 if (condition & DBUS_WATCH_HANGUP)
00693 revents |= _DBUS_POLLHUP;
00694
00695 fd = dbus_watch_get_fd (watch);
00696
00697 if (fd == sitter->error_pipe_from_child)
00698 handle_error_pipe (sitter, revents);
00699 else if (fd == sitter->socket_to_babysitter)
00700 handle_babysitter_socket (sitter, revents);
00701
00702 while (LIVE_CHILDREN (sitter) &&
00703 babysitter_iteration (sitter, FALSE))
00704 ;
00705
00706 return TRUE;
00707 }
00708
00710 #define READ_END 0
00711
00712 #define WRITE_END 1
00713
00714
00715
00716
00717
00718
00719 static int
00720 close_and_invalidate (int *fd)
00721 {
00722 int ret;
00723
00724 if (*fd < 0)
00725 return -1;
00726 else
00727 {
00728 ret = close (*fd);
00729 *fd = -1;
00730 }
00731
00732 return ret;
00733 }
00734
00735 static dbus_bool_t
00736 make_pipe (int p[2],
00737 DBusError *error)
00738 {
00739 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00740
00741 if (pipe (p) < 0)
00742 {
00743 dbus_set_error (error,
00744 DBUS_ERROR_SPAWN_FAILED,
00745 "Failed to create pipe for communicating with child process (%s)",
00746 _dbus_strerror (errno));
00747 return FALSE;
00748 }
00749
00750 return TRUE;
00751 }
00752
00753 static void
00754 do_write (int fd, const void *buf, size_t count)
00755 {
00756 size_t bytes_written;
00757 int ret;
00758
00759 bytes_written = 0;
00760
00761 again:
00762
00763 ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
00764
00765 if (ret < 0)
00766 {
00767 if (errno == EINTR)
00768 goto again;
00769 else
00770 {
00771 _dbus_warn ("Failed to write data to pipe!\n");
00772 exit (1);
00773 }
00774 }
00775 else
00776 bytes_written += ret;
00777
00778 if (bytes_written < count)
00779 goto again;
00780 }
00781
00782 static void
00783 write_err_and_exit (int fd, int msg)
00784 {
00785 int en = errno;
00786
00787 do_write (fd, &msg, sizeof (msg));
00788 do_write (fd, &en, sizeof (en));
00789
00790 exit (1);
00791 }
00792
00793 static void
00794 write_pid (int fd, pid_t pid)
00795 {
00796 int msg = CHILD_PID;
00797
00798 do_write (fd, &msg, sizeof (msg));
00799 do_write (fd, &pid, sizeof (pid));
00800 }
00801
00802 static void
00803 write_status_and_exit (int fd, int status)
00804 {
00805 int msg = CHILD_EXITED;
00806
00807 do_write (fd, &msg, sizeof (msg));
00808 do_write (fd, &status, sizeof (status));
00809
00810 exit (0);
00811 }
00812
00813 static void
00814 do_exec (int child_err_report_fd,
00815 char **argv,
00816 DBusSpawnChildSetupFunc child_setup,
00817 void *user_data)
00818 {
00819 #ifdef DBUS_BUILD_TESTS
00820 int i, max_open;
00821 #endif
00822
00823 _dbus_verbose_reset ();
00824 _dbus_verbose ("Child process has PID %lu\n",
00825 _dbus_getpid ());
00826
00827 if (child_setup)
00828 (* child_setup) (user_data);
00829
00830 #ifdef DBUS_BUILD_TESTS
00831 max_open = sysconf (_SC_OPEN_MAX);
00832
00833 for (i = 3; i < max_open; i++)
00834 {
00835 int retval;
00836
00837 if (i == child_err_report_fd)
00838 continue;
00839
00840 retval = fcntl (i, F_GETFD);
00841
00842 if (retval != -1 && !(retval & FD_CLOEXEC))
00843 _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
00844 }
00845 #endif
00846
00847 execv (argv[0], argv);
00848
00849
00850 write_err_and_exit (child_err_report_fd,
00851 CHILD_EXEC_FAILED);
00852 }
00853
00854 static void
00855 check_babysit_events (pid_t grandchild_pid,
00856 int parent_pipe,
00857 int revents)
00858 {
00859 pid_t ret;
00860 int status;
00861
00862 ret = waitpid (grandchild_pid, &status, WNOHANG);
00863
00864 if (ret == 0)
00865 {
00866 _dbus_verbose ("no child exited\n");
00867
00868 ;
00869 }
00870 else if (ret < 0)
00871 {
00872
00873 _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n",
00874 _dbus_strerror (errno));
00875 exit (1);
00876 }
00877 else if (ret == grandchild_pid)
00878 {
00879
00880 _dbus_verbose ("reaped child pid %ld\n", (long) ret);
00881
00882 write_status_and_exit (parent_pipe, status);
00883 }
00884 else
00885 {
00886 _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n",
00887 (int) ret);
00888 exit (1);
00889 }
00890
00891 if (revents & _DBUS_POLLIN)
00892 {
00893 _dbus_verbose ("babysitter got POLLIN from parent pipe\n");
00894 }
00895
00896 if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00897 {
00898
00899 _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n");
00900 exit (0);
00901 }
00902 }
00903
00904 static int babysit_sigchld_pipe = -1;
00905
00906 static void
00907 babysit_signal_handler (int signo)
00908 {
00909 char b = '\0';
00910 again:
00911 write (babysit_sigchld_pipe, &b, 1);
00912 if (errno == EINTR)
00913 goto again;
00914 }
00915
00916 static void
00917 babysit (pid_t grandchild_pid,
00918 int parent_pipe)
00919 {
00920 int sigchld_pipe[2];
00921
00922
00923
00924
00925 _dbus_verbose_reset ();
00926
00927
00928
00929
00930
00931
00932 if (pipe (sigchld_pipe) < 0)
00933 {
00934 _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n");
00935 exit (1);
00936 }
00937
00938 babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
00939
00940 _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
00941
00942 write_pid (parent_pipe, grandchild_pid);
00943
00944 check_babysit_events (grandchild_pid, parent_pipe, 0);
00945
00946 while (TRUE)
00947 {
00948 DBusPollFD pfds[2];
00949
00950 pfds[0].fd = parent_pipe;
00951 pfds[0].events = _DBUS_POLLIN;
00952 pfds[0].revents = 0;
00953
00954 pfds[1].fd = sigchld_pipe[READ_END];
00955 pfds[1].events = _DBUS_POLLIN;
00956 pfds[1].revents = 0;
00957
00958 _dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1);
00959
00960 if (pfds[0].revents != 0)
00961 {
00962 check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
00963 }
00964 else if (pfds[1].revents & _DBUS_POLLIN)
00965 {
00966 char b;
00967 read (sigchld_pipe[READ_END], &b, 1);
00968
00969 check_babysit_events (grandchild_pid, parent_pipe, 0);
00970 }
00971 }
00972
00973 exit (1);
00974 }
00975
00994 dbus_bool_t
00995 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
00996 char **argv,
00997 DBusSpawnChildSetupFunc child_setup,
00998 void *user_data,
00999 DBusError *error)
01000 {
01001 DBusBabysitter *sitter;
01002 int child_err_report_pipe[2] = { -1, -1 };
01003 int babysitter_pipe[2] = { -1, -1 };
01004 pid_t pid;
01005
01006 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01007
01008 *sitter_p = NULL;
01009 sitter = NULL;
01010
01011 sitter = _dbus_babysitter_new ();
01012 if (sitter == NULL)
01013 {
01014 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01015 return FALSE;
01016 }
01017
01018 sitter->executable = _dbus_strdup (argv[0]);
01019 if (sitter->executable == NULL)
01020 {
01021 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01022 goto cleanup_and_fail;
01023 }
01024
01025 if (!make_pipe (child_err_report_pipe, error))
01026 goto cleanup_and_fail;
01027
01028 _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]);
01029
01030 if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
01031 goto cleanup_and_fail;
01032
01033 _dbus_fd_set_close_on_exec (babysitter_pipe[0]);
01034 _dbus_fd_set_close_on_exec (babysitter_pipe[1]);
01035
01036
01037
01038
01039
01040
01041 sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
01042 DBUS_WATCH_READABLE,
01043 TRUE, handle_watch, sitter, NULL);
01044 if (sitter->error_watch == NULL)
01045 {
01046 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01047 goto cleanup_and_fail;
01048 }
01049
01050 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch))
01051 {
01052 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01053 goto cleanup_and_fail;
01054 }
01055
01056 sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
01057 DBUS_WATCH_READABLE,
01058 TRUE, handle_watch, sitter, NULL);
01059 if (sitter->sitter_watch == NULL)
01060 {
01061 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01062 goto cleanup_and_fail;
01063 }
01064
01065 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
01066 {
01067 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01068 goto cleanup_and_fail;
01069 }
01070
01071 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01072
01073 pid = fork ();
01074
01075 if (pid < 0)
01076 {
01077 dbus_set_error (error,
01078 DBUS_ERROR_SPAWN_FORK_FAILED,
01079 "Failed to fork (%s)",
01080 _dbus_strerror (errno));
01081 goto cleanup_and_fail;
01082 }
01083 else if (pid == 0)
01084 {
01085
01086 int grandchild_pid;
01087
01088
01089
01090
01091 signal (SIGPIPE, SIG_DFL);
01092
01093
01094 close_and_invalidate (&child_err_report_pipe[READ_END]);
01095 close_and_invalidate (&babysitter_pipe[0]);
01096
01097
01098 grandchild_pid = fork ();
01099
01100 if (grandchild_pid < 0)
01101 {
01102 write_err_and_exit (babysitter_pipe[1],
01103 CHILD_FORK_FAILED);
01104 _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
01105 }
01106 else if (grandchild_pid == 0)
01107 {
01108 do_exec (child_err_report_pipe[WRITE_END],
01109 argv,
01110 child_setup, user_data);
01111 _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
01112 }
01113 else
01114 {
01115 babysit (grandchild_pid, babysitter_pipe[1]);
01116 _dbus_assert_not_reached ("Got to code after babysit()");
01117 }
01118 }
01119 else
01120 {
01121
01122 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01123 close_and_invalidate (&babysitter_pipe[1]);
01124
01125 sitter->socket_to_babysitter = babysitter_pipe[0];
01126 babysitter_pipe[0] = -1;
01127
01128 sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
01129 child_err_report_pipe[READ_END] = -1;
01130
01131 sitter->sitter_pid = pid;
01132
01133 if (sitter_p != NULL)
01134 *sitter_p = sitter;
01135 else
01136 _dbus_babysitter_unref (sitter);
01137
01138 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01139
01140 return TRUE;
01141 }
01142
01143 cleanup_and_fail:
01144
01145 _DBUS_ASSERT_ERROR_IS_SET (error);
01146
01147 close_and_invalidate (&child_err_report_pipe[READ_END]);
01148 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01149 close_and_invalidate (&babysitter_pipe[0]);
01150 close_and_invalidate (&babysitter_pipe[1]);
01151
01152 if (sitter != NULL)
01153 _dbus_babysitter_unref (sitter);
01154
01155 return FALSE;
01156 }
01157
01160 #ifdef DBUS_BUILD_TESTS
01161
01162 static void
01163 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
01164 {
01165 while (LIVE_CHILDREN (sitter))
01166 babysitter_iteration (sitter, TRUE);
01167 }
01168
01169 static dbus_bool_t
01170 check_spawn_nonexistent (void *data)
01171 {
01172 char *argv[4] = { NULL, NULL, NULL, NULL };
01173 DBusBabysitter *sitter;
01174 DBusError error;
01175
01176 sitter = NULL;
01177
01178 dbus_error_init (&error);
01179
01180
01181
01182 argv[0] = "/this/does/not/exist/32542sdgafgafdg";
01183 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01184 NULL, NULL,
01185 &error))
01186 {
01187 _dbus_babysitter_block_for_child_exit (sitter);
01188 _dbus_babysitter_set_child_exit_error (sitter, &error);
01189 }
01190
01191 if (sitter)
01192 _dbus_babysitter_unref (sitter);
01193
01194 if (!dbus_error_is_set (&error))
01195 {
01196 _dbus_warn ("Did not get an error launching nonexistent executable\n");
01197 return FALSE;
01198 }
01199
01200 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01201 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
01202 {
01203 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
01204 error.name, error.message);
01205 dbus_error_free (&error);
01206 return FALSE;
01207 }
01208
01209 dbus_error_free (&error);
01210
01211 return TRUE;
01212 }
01213
01214 static dbus_bool_t
01215 check_spawn_segfault (void *data)
01216 {
01217 char *argv[4] = { NULL, NULL, NULL, NULL };
01218 DBusBabysitter *sitter;
01219 DBusError error;
01220
01221 sitter = NULL;
01222
01223 dbus_error_init (&error);
01224
01225
01226
01227 argv[0] = TEST_SEGFAULT_BINARY;
01228 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01229 NULL, NULL,
01230 &error))
01231 {
01232 _dbus_babysitter_block_for_child_exit (sitter);
01233 _dbus_babysitter_set_child_exit_error (sitter, &error);
01234 }
01235
01236 if (sitter)
01237 _dbus_babysitter_unref (sitter);
01238
01239 if (!dbus_error_is_set (&error))
01240 {
01241 _dbus_warn ("Did not get an error launching segfaulting binary\n");
01242 return FALSE;
01243 }
01244
01245 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01246 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01247 {
01248 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
01249 error.name, error.message);
01250 dbus_error_free (&error);
01251 return FALSE;
01252 }
01253
01254 dbus_error_free (&error);
01255
01256 return TRUE;
01257 }
01258
01259 static dbus_bool_t
01260 check_spawn_exit (void *data)
01261 {
01262 char *argv[4] = { NULL, NULL, NULL, NULL };
01263 DBusBabysitter *sitter;
01264 DBusError error;
01265
01266 sitter = NULL;
01267
01268 dbus_error_init (&error);
01269
01270
01271
01272 argv[0] = TEST_EXIT_BINARY;
01273 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01274 NULL, NULL,
01275 &error))
01276 {
01277 _dbus_babysitter_block_for_child_exit (sitter);
01278 _dbus_babysitter_set_child_exit_error (sitter, &error);
01279 }
01280
01281 if (sitter)
01282 _dbus_babysitter_unref (sitter);
01283
01284 if (!dbus_error_is_set (&error))
01285 {
01286 _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
01287 return FALSE;
01288 }
01289
01290 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01291 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
01292 {
01293 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
01294 error.name, error.message);
01295 dbus_error_free (&error);
01296 return FALSE;
01297 }
01298
01299 dbus_error_free (&error);
01300
01301 return TRUE;
01302 }
01303
01304 static dbus_bool_t
01305 check_spawn_and_kill (void *data)
01306 {
01307 char *argv[4] = { NULL, NULL, NULL, NULL };
01308 DBusBabysitter *sitter;
01309 DBusError error;
01310
01311 sitter = NULL;
01312
01313 dbus_error_init (&error);
01314
01315
01316
01317 argv[0] = TEST_SLEEP_FOREVER_BINARY;
01318 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01319 NULL, NULL,
01320 &error))
01321 {
01322 _dbus_babysitter_kill_child (sitter);
01323
01324 _dbus_babysitter_block_for_child_exit (sitter);
01325
01326 _dbus_babysitter_set_child_exit_error (sitter, &error);
01327 }
01328
01329 if (sitter)
01330 _dbus_babysitter_unref (sitter);
01331
01332 if (!dbus_error_is_set (&error))
01333 {
01334 _dbus_warn ("Did not get an error after killing spawned binary\n");
01335 return FALSE;
01336 }
01337
01338 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01339 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01340 {
01341 _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
01342 error.name, error.message);
01343 dbus_error_free (&error);
01344 return FALSE;
01345 }
01346
01347 dbus_error_free (&error);
01348
01349 return TRUE;
01350 }
01351
01352 dbus_bool_t
01353 _dbus_spawn_test (const char *test_data_dir)
01354 {
01355 if (!_dbus_test_oom_handling ("spawn_nonexistent",
01356 check_spawn_nonexistent,
01357 NULL))
01358 return FALSE;
01359
01360 if (!_dbus_test_oom_handling ("spawn_segfault",
01361 check_spawn_segfault,
01362 NULL))
01363 return FALSE;
01364
01365 if (!_dbus_test_oom_handling ("spawn_exit",
01366 check_spawn_exit,
01367 NULL))
01368 return FALSE;
01369
01370 if (!_dbus_test_oom_handling ("spawn_and_kill",
01371 check_spawn_and_kill,
01372 NULL))
01373 return FALSE;
01374
01375 return TRUE;
01376 }
01377 #endif