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