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