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 ssize_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 ssize_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 = DBUS_ERROR_INIT;
00370 ReadStatus r;
00371
00372 r = read_ints (fd, &what, 1, &got, &error);
00373
00374 switch (r)
00375 {
00376 case READ_STATUS_ERROR:
00377 _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message);
00378 dbus_error_free (&error);
00379 return r;
00380
00381 case READ_STATUS_EOF:
00382 return r;
00383
00384 case READ_STATUS_OK:
00385 break;
00386 }
00387
00388 if (got == 1)
00389 {
00390 switch (what)
00391 {
00392 case CHILD_EXITED:
00393 case CHILD_FORK_FAILED:
00394 case CHILD_EXEC_FAILED:
00395 {
00396 int arg;
00397
00398 r = read_ints (fd, &arg, 1, &got, &error);
00399
00400 switch (r)
00401 {
00402 case READ_STATUS_ERROR:
00403 _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message);
00404 dbus_error_free (&error);
00405 return r;
00406 case READ_STATUS_EOF:
00407 return r;
00408 case READ_STATUS_OK:
00409 break;
00410 }
00411
00412 if (got == 1)
00413 {
00414 if (what == CHILD_EXITED)
00415 {
00416 sitter->have_child_status = TRUE;
00417 sitter->status = arg;
00418 sitter->errnum = 0;
00419 _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
00420 WIFEXITED (sitter->status), WIFSIGNALED (sitter->status),
00421 WEXITSTATUS (sitter->status), WTERMSIG (sitter->status));
00422 }
00423 else if (what == CHILD_FORK_FAILED)
00424 {
00425 sitter->have_fork_errnum = TRUE;
00426 sitter->errnum = arg;
00427 _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum);
00428 }
00429 else if (what == CHILD_EXEC_FAILED)
00430 {
00431 sitter->have_exec_errnum = TRUE;
00432 sitter->errnum = arg;
00433 _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum);
00434 }
00435 }
00436 }
00437 break;
00438 case CHILD_PID:
00439 {
00440 pid_t pid = -1;
00441
00442 r = read_pid (fd, &pid, &error);
00443
00444 switch (r)
00445 {
00446 case READ_STATUS_ERROR:
00447 _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message);
00448 dbus_error_free (&error);
00449 return r;
00450 case READ_STATUS_EOF:
00451 return r;
00452 case READ_STATUS_OK:
00453 break;
00454 }
00455
00456 sitter->grandchild_pid = pid;
00457
00458 _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid);
00459 }
00460 break;
00461 default:
00462 _dbus_warn ("Unknown message received from babysitter process\n");
00463 break;
00464 }
00465 }
00466
00467 return r;
00468 }
00469
00470 static void
00471 close_socket_to_babysitter (DBusBabysitter *sitter)
00472 {
00473 _dbus_verbose ("Closing babysitter\n");
00474 _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00475 sitter->socket_to_babysitter = -1;
00476 }
00477
00478 static void
00479 close_error_pipe_from_child (DBusBabysitter *sitter)
00480 {
00481 _dbus_verbose ("Closing child error\n");
00482 _dbus_close_socket (sitter->error_pipe_from_child, NULL);
00483 sitter->error_pipe_from_child = -1;
00484 }
00485
00486 static void
00487 handle_babysitter_socket (DBusBabysitter *sitter,
00488 int revents)
00489 {
00490
00491
00492
00493
00494 if (revents & _DBUS_POLLIN)
00495 {
00496 _dbus_verbose ("Reading data from babysitter\n");
00497 if (read_data (sitter, sitter->socket_to_babysitter) != READ_STATUS_OK)
00498 close_socket_to_babysitter (sitter);
00499 }
00500 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00501 {
00502 close_socket_to_babysitter (sitter);
00503 }
00504 }
00505
00506 static void
00507 handle_error_pipe (DBusBabysitter *sitter,
00508 int revents)
00509 {
00510 if (revents & _DBUS_POLLIN)
00511 {
00512 _dbus_verbose ("Reading data from child error\n");
00513 if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK)
00514 close_error_pipe_from_child (sitter);
00515 }
00516 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00517 {
00518 close_error_pipe_from_child (sitter);
00519 }
00520 }
00521
00522
00523 static dbus_bool_t
00524 babysitter_iteration (DBusBabysitter *sitter,
00525 dbus_bool_t block)
00526 {
00527 DBusPollFD fds[2];
00528 int i;
00529 dbus_bool_t descriptors_ready;
00530
00531 descriptors_ready = FALSE;
00532
00533 i = 0;
00534
00535 if (sitter->error_pipe_from_child >= 0)
00536 {
00537 fds[i].fd = sitter->error_pipe_from_child;
00538 fds[i].events = _DBUS_POLLIN;
00539 fds[i].revents = 0;
00540 ++i;
00541 }
00542
00543 if (sitter->socket_to_babysitter >= 0)
00544 {
00545 fds[i].fd = sitter->socket_to_babysitter;
00546 fds[i].events = _DBUS_POLLIN;
00547 fds[i].revents = 0;
00548 ++i;
00549 }
00550
00551 if (i > 0)
00552 {
00553 int ret;
00554
00555 do
00556 {
00557 ret = _dbus_poll (fds, i, 0);
00558 }
00559 while (ret < 0 && errno == EINTR);
00560
00561 if (ret == 0 && block)
00562 {
00563 do
00564 {
00565 ret = _dbus_poll (fds, i, -1);
00566 }
00567 while (ret < 0 && errno == EINTR);
00568 }
00569
00570 if (ret > 0)
00571 {
00572 descriptors_ready = TRUE;
00573
00574 while (i > 0)
00575 {
00576 --i;
00577 if (fds[i].fd == sitter->error_pipe_from_child)
00578 handle_error_pipe (sitter, fds[i].revents);
00579 else if (fds[i].fd == sitter->socket_to_babysitter)
00580 handle_babysitter_socket (sitter, fds[i].revents);
00581 }
00582 }
00583 }
00584
00585 return descriptors_ready;
00586 }
00587
00592 #define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter >= 0 || (sitter)->error_pipe_from_child >= 0)
00593
00600 void
00601 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
00602 {
00603
00604 while (LIVE_CHILDREN (sitter) &&
00605 sitter->grandchild_pid == -1)
00606 babysitter_iteration (sitter, TRUE);
00607
00608 _dbus_verbose ("Got child PID %ld for killing\n",
00609 (long) sitter->grandchild_pid);
00610
00611 if (sitter->grandchild_pid == -1)
00612 return;
00613
00614 kill (sitter->grandchild_pid, SIGKILL);
00615 }
00616
00622 dbus_bool_t
00623 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
00624 {
00625
00626
00627 while (LIVE_CHILDREN (sitter) &&
00628 babysitter_iteration (sitter, FALSE))
00629 ;
00630
00631
00632 return sitter->socket_to_babysitter < 0;
00633 }
00634
00647 dbus_bool_t
00648 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
00649 int *status)
00650 {
00651 if (!_dbus_babysitter_get_child_exited (sitter))
00652 _dbus_assert_not_reached ("Child has not exited");
00653
00654 if (!sitter->have_child_status ||
00655 !(WIFEXITED (sitter->status)))
00656 return FALSE;
00657
00658 *status = WEXITSTATUS (sitter->status);
00659 return TRUE;
00660 }
00661
00671 void
00672 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
00673 DBusError *error)
00674 {
00675 if (!_dbus_babysitter_get_child_exited (sitter))
00676 return;
00677
00678
00679
00680
00681
00682 if (sitter->have_exec_errnum)
00683 {
00684 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00685 "Failed to execute program %s: %s",
00686 sitter->executable, _dbus_strerror (sitter->errnum));
00687 }
00688 else if (sitter->have_fork_errnum)
00689 {
00690 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00691 "Failed to fork a new process %s: %s",
00692 sitter->executable, _dbus_strerror (sitter->errnum));
00693 }
00694 else if (sitter->have_child_status)
00695 {
00696 if (WIFEXITED (sitter->status))
00697 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00698 "Process %s exited with status %d",
00699 sitter->executable, WEXITSTATUS (sitter->status));
00700 else if (WIFSIGNALED (sitter->status))
00701 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,
00702 "Process %s received signal %d",
00703 sitter->executable, WTERMSIG (sitter->status));
00704 else
00705 dbus_set_error (error, DBUS_ERROR_FAILED,
00706 "Process %s exited abnormally",
00707 sitter->executable);
00708 }
00709 else
00710 {
00711 dbus_set_error (error, DBUS_ERROR_FAILED,
00712 "Process %s exited, reason unknown",
00713 sitter->executable);
00714 }
00715 }
00716
00729 dbus_bool_t
00730 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter,
00731 DBusAddWatchFunction add_function,
00732 DBusRemoveWatchFunction remove_function,
00733 DBusWatchToggledFunction toggled_function,
00734 void *data,
00735 DBusFreeFunction free_data_function)
00736 {
00737 return _dbus_watch_list_set_functions (sitter->watches,
00738 add_function,
00739 remove_function,
00740 toggled_function,
00741 data,
00742 free_data_function);
00743 }
00744
00745 static dbus_bool_t
00746 handle_watch (DBusWatch *watch,
00747 unsigned int condition,
00748 void *data)
00749 {
00750 DBusBabysitter *sitter = data;
00751 int revents;
00752 int fd;
00753
00754 revents = 0;
00755 if (condition & DBUS_WATCH_READABLE)
00756 revents |= _DBUS_POLLIN;
00757 if (condition & DBUS_WATCH_ERROR)
00758 revents |= _DBUS_POLLERR;
00759 if (condition & DBUS_WATCH_HANGUP)
00760 revents |= _DBUS_POLLHUP;
00761
00762 fd = dbus_watch_get_socket (watch);
00763
00764 if (fd == sitter->error_pipe_from_child)
00765 handle_error_pipe (sitter, revents);
00766 else if (fd == sitter->socket_to_babysitter)
00767 handle_babysitter_socket (sitter, revents);
00768
00769 while (LIVE_CHILDREN (sitter) &&
00770 babysitter_iteration (sitter, FALSE))
00771 ;
00772
00773 return TRUE;
00774 }
00775
00777 #define READ_END 0
00778
00779 #define WRITE_END 1
00780
00781
00782
00783
00784
00785
00786 static int
00787 close_and_invalidate (int *fd)
00788 {
00789 int ret;
00790
00791 if (*fd < 0)
00792 return -1;
00793 else
00794 {
00795 ret = _dbus_close_socket (*fd, NULL);
00796 *fd = -1;
00797 }
00798
00799 return ret;
00800 }
00801
00802 static dbus_bool_t
00803 make_pipe (int p[2],
00804 DBusError *error)
00805 {
00806 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00807
00808 if (pipe (p) < 0)
00809 {
00810 dbus_set_error (error,
00811 DBUS_ERROR_SPAWN_FAILED,
00812 "Failed to create pipe for communicating with child process (%s)",
00813 _dbus_strerror (errno));
00814 return FALSE;
00815 }
00816
00817 return TRUE;
00818 }
00819
00820 static void
00821 do_write (int fd, const void *buf, size_t count)
00822 {
00823 size_t bytes_written;
00824 int ret;
00825
00826 bytes_written = 0;
00827
00828 again:
00829
00830 ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
00831
00832 if (ret < 0)
00833 {
00834 if (errno == EINTR)
00835 goto again;
00836 else
00837 {
00838 _dbus_warn ("Failed to write data to pipe!\n");
00839 exit (1);
00840 }
00841 }
00842 else
00843 bytes_written += ret;
00844
00845 if (bytes_written < count)
00846 goto again;
00847 }
00848
00849 static void
00850 write_err_and_exit (int fd, int msg)
00851 {
00852 int en = errno;
00853
00854 do_write (fd, &msg, sizeof (msg));
00855 do_write (fd, &en, sizeof (en));
00856
00857 exit (1);
00858 }
00859
00860 static void
00861 write_pid (int fd, pid_t pid)
00862 {
00863 int msg = CHILD_PID;
00864
00865 do_write (fd, &msg, sizeof (msg));
00866 do_write (fd, &pid, sizeof (pid));
00867 }
00868
00869 static void
00870 write_status_and_exit (int fd, int status)
00871 {
00872 int msg = CHILD_EXITED;
00873
00874 do_write (fd, &msg, sizeof (msg));
00875 do_write (fd, &status, sizeof (status));
00876
00877 exit (0);
00878 }
00879
00880 static void
00881 do_exec (int child_err_report_fd,
00882 char **argv,
00883 DBusSpawnChildSetupFunc child_setup,
00884 void *user_data)
00885 {
00886 #ifdef DBUS_BUILD_TESTS
00887 int i, max_open;
00888 #endif
00889
00890 _dbus_verbose_reset ();
00891 _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n",
00892 _dbus_getpid ());
00893
00894 if (child_setup)
00895 (* child_setup) (user_data);
00896
00897 #ifdef DBUS_BUILD_TESTS
00898 max_open = sysconf (_SC_OPEN_MAX);
00899
00900 for (i = 3; i < max_open; i++)
00901 {
00902 int retval;
00903
00904 if (i == child_err_report_fd)
00905 continue;
00906
00907 retval = fcntl (i, F_GETFD);
00908
00909 if (retval != -1 && !(retval & FD_CLOEXEC))
00910 _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
00911 }
00912 #endif
00913
00914 execv (argv[0], argv);
00915
00916
00917 write_err_and_exit (child_err_report_fd,
00918 CHILD_EXEC_FAILED);
00919 }
00920
00921 static void
00922 check_babysit_events (pid_t grandchild_pid,
00923 int parent_pipe,
00924 int revents)
00925 {
00926 pid_t ret;
00927 int status;
00928
00929 do
00930 {
00931 ret = waitpid (grandchild_pid, &status, WNOHANG);
00932
00933
00934
00935 }
00936 while (ret < 0 && errno == EINTR);
00937
00938 if (ret == 0)
00939 {
00940 _dbus_verbose ("no child exited\n");
00941
00942 ;
00943 }
00944 else if (ret < 0)
00945 {
00946
00947 _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n",
00948 _dbus_strerror (errno));
00949 exit (1);
00950 }
00951 else if (ret == grandchild_pid)
00952 {
00953
00954 _dbus_verbose ("reaped child pid %ld\n", (long) ret);
00955
00956 write_status_and_exit (parent_pipe, status);
00957 }
00958 else
00959 {
00960 _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n",
00961 (int) ret);
00962 exit (1);
00963 }
00964
00965 if (revents & _DBUS_POLLIN)
00966 {
00967 _dbus_verbose ("babysitter got POLLIN from parent pipe\n");
00968 }
00969
00970 if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00971 {
00972
00973 _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n");
00974 exit (0);
00975 }
00976 }
00977
00978 static int babysit_sigchld_pipe = -1;
00979
00980 static void
00981 babysit_signal_handler (int signo)
00982 {
00983 char b = '\0';
00984 again:
00985 if (write (babysit_sigchld_pipe, &b, 1) <= 0)
00986 if (errno == EINTR)
00987 goto again;
00988 }
00989
00990 static void
00991 babysit (pid_t grandchild_pid,
00992 int parent_pipe)
00993 {
00994 int sigchld_pipe[2];
00995
00996
00997
00998
00999 _dbus_verbose_reset ();
01000
01001
01002
01003
01004
01005
01006 if (pipe (sigchld_pipe) < 0)
01007 {
01008 _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n");
01009 exit (1);
01010 }
01011
01012 babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
01013
01014 _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
01015
01016 write_pid (parent_pipe, grandchild_pid);
01017
01018 check_babysit_events (grandchild_pid, parent_pipe, 0);
01019
01020 while (TRUE)
01021 {
01022 DBusPollFD pfds[2];
01023
01024 pfds[0].fd = parent_pipe;
01025 pfds[0].events = _DBUS_POLLIN;
01026 pfds[0].revents = 0;
01027
01028 pfds[1].fd = sigchld_pipe[READ_END];
01029 pfds[1].events = _DBUS_POLLIN;
01030 pfds[1].revents = 0;
01031
01032 if (_dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1) < 0 && errno != EINTR)
01033 {
01034 _dbus_warn ("_dbus_poll() error: %s\n", strerror (errno));
01035 exit (1);
01036 }
01037
01038 if (pfds[0].revents != 0)
01039 {
01040 check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
01041 }
01042 else if (pfds[1].revents & _DBUS_POLLIN)
01043 {
01044 char b;
01045 read (sigchld_pipe[READ_END], &b, 1);
01046
01047 check_babysit_events (grandchild_pid, parent_pipe, 0);
01048 }
01049 }
01050
01051 exit (1);
01052 }
01053
01073 dbus_bool_t
01074 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
01075 char **argv,
01076 char **env,
01077 DBusSpawnChildSetupFunc child_setup,
01078 void *user_data,
01079 DBusError *error)
01080 {
01081 DBusBabysitter *sitter;
01082 int child_err_report_pipe[2] = { -1, -1 };
01083 int babysitter_pipe[2] = { -1, -1 };
01084 pid_t pid;
01085
01086 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01087
01088 if (sitter_p != NULL)
01089 *sitter_p = NULL;
01090
01091 sitter = NULL;
01092
01093 sitter = _dbus_babysitter_new ();
01094 if (sitter == NULL)
01095 {
01096 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01097 return FALSE;
01098 }
01099
01100 sitter->executable = _dbus_strdup (argv[0]);
01101 if (sitter->executable == NULL)
01102 {
01103 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01104 goto cleanup_and_fail;
01105 }
01106
01107 if (!make_pipe (child_err_report_pipe, error))
01108 goto cleanup_and_fail;
01109
01110 _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]);
01111 _dbus_fd_set_close_on_exec (child_err_report_pipe[WRITE_END]);
01112
01113 if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
01114 goto cleanup_and_fail;
01115
01116 _dbus_fd_set_close_on_exec (babysitter_pipe[0]);
01117 _dbus_fd_set_close_on_exec (babysitter_pipe[1]);
01118
01119
01120
01121
01122
01123
01124 sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
01125 DBUS_WATCH_READABLE,
01126 TRUE, handle_watch, sitter, NULL);
01127 if (sitter->error_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->error_watch))
01134 {
01135 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01136 goto cleanup_and_fail;
01137 }
01138
01139 sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
01140 DBUS_WATCH_READABLE,
01141 TRUE, handle_watch, sitter, NULL);
01142 if (sitter->sitter_watch == NULL)
01143 {
01144 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01145 goto cleanup_and_fail;
01146 }
01147
01148 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
01149 {
01150 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01151 goto cleanup_and_fail;
01152 }
01153
01154 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01155
01156 pid = fork ();
01157
01158 if (pid < 0)
01159 {
01160 dbus_set_error (error,
01161 DBUS_ERROR_SPAWN_FORK_FAILED,
01162 "Failed to fork (%s)",
01163 _dbus_strerror (errno));
01164 goto cleanup_and_fail;
01165 }
01166 else if (pid == 0)
01167 {
01168
01169 int grandchild_pid;
01170
01171
01172
01173
01174 signal (SIGPIPE, SIG_DFL);
01175
01176
01177 close_and_invalidate (&child_err_report_pipe[READ_END]);
01178 close_and_invalidate (&babysitter_pipe[0]);
01179
01180
01181 grandchild_pid = fork ();
01182
01183 if (grandchild_pid < 0)
01184 {
01185 write_err_and_exit (babysitter_pipe[1],
01186 CHILD_FORK_FAILED);
01187 _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
01188 }
01189 else if (grandchild_pid == 0)
01190 {
01191 do_exec (child_err_report_pipe[WRITE_END],
01192 argv,
01193 child_setup, user_data);
01194 _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
01195 }
01196 else
01197 {
01198 babysit (grandchild_pid, babysitter_pipe[1]);
01199 _dbus_assert_not_reached ("Got to code after babysit()");
01200 }
01201 }
01202 else
01203 {
01204
01205 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01206 close_and_invalidate (&babysitter_pipe[1]);
01207
01208 sitter->socket_to_babysitter = babysitter_pipe[0];
01209 babysitter_pipe[0] = -1;
01210
01211 sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
01212 child_err_report_pipe[READ_END] = -1;
01213
01214 sitter->sitter_pid = pid;
01215
01216 if (sitter_p != NULL)
01217 *sitter_p = sitter;
01218 else
01219 _dbus_babysitter_unref (sitter);
01220
01221 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01222
01223 return TRUE;
01224 }
01225
01226 cleanup_and_fail:
01227
01228 _DBUS_ASSERT_ERROR_IS_SET (error);
01229
01230 close_and_invalidate (&child_err_report_pipe[READ_END]);
01231 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01232 close_and_invalidate (&babysitter_pipe[0]);
01233 close_and_invalidate (&babysitter_pipe[1]);
01234
01235 if (sitter != NULL)
01236 _dbus_babysitter_unref (sitter);
01237
01238 return FALSE;
01239 }
01240
01243 #ifdef DBUS_BUILD_TESTS
01244
01245 static void
01246 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
01247 {
01248 while (LIVE_CHILDREN (sitter))
01249 babysitter_iteration (sitter, TRUE);
01250 }
01251
01252 static dbus_bool_t
01253 check_spawn_nonexistent (void *data)
01254 {
01255 char *argv[4] = { NULL, NULL, NULL, NULL };
01256 DBusBabysitter *sitter = NULL;
01257 DBusError error = DBUS_ERROR_INIT;
01258
01259
01260
01261 argv[0] = "/this/does/not/exist/32542sdgafgafdg";
01262 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01263 NULL, NULL, NULL,
01264 &error))
01265 {
01266 _dbus_babysitter_block_for_child_exit (sitter);
01267 _dbus_babysitter_set_child_exit_error (sitter, &error);
01268 }
01269
01270 if (sitter)
01271 _dbus_babysitter_unref (sitter);
01272
01273 if (!dbus_error_is_set (&error))
01274 {
01275 _dbus_warn ("Did not get an error launching nonexistent executable\n");
01276 return FALSE;
01277 }
01278
01279 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01280 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
01281 {
01282 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
01283 error.name, error.message);
01284 dbus_error_free (&error);
01285 return FALSE;
01286 }
01287
01288 dbus_error_free (&error);
01289
01290 return TRUE;
01291 }
01292
01293 static dbus_bool_t
01294 check_spawn_segfault (void *data)
01295 {
01296 char *argv[4] = { NULL, NULL, NULL, NULL };
01297 DBusBabysitter *sitter = NULL;
01298 DBusError error = DBUS_ERROR_INIT;
01299
01300
01301
01302 argv[0] = TEST_SEGFAULT_BINARY;
01303 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01304 NULL, NULL, NULL,
01305 &error))
01306 {
01307 _dbus_babysitter_block_for_child_exit (sitter);
01308 _dbus_babysitter_set_child_exit_error (sitter, &error);
01309 }
01310
01311 if (sitter)
01312 _dbus_babysitter_unref (sitter);
01313
01314 if (!dbus_error_is_set (&error))
01315 {
01316 _dbus_warn ("Did not get an error launching segfaulting binary\n");
01317 return FALSE;
01318 }
01319
01320 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01321 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01322 {
01323 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
01324 error.name, error.message);
01325 dbus_error_free (&error);
01326 return FALSE;
01327 }
01328
01329 dbus_error_free (&error);
01330
01331 return TRUE;
01332 }
01333
01334 static dbus_bool_t
01335 check_spawn_exit (void *data)
01336 {
01337 char *argv[4] = { NULL, NULL, NULL, NULL };
01338 DBusBabysitter *sitter = NULL;
01339 DBusError error = DBUS_ERROR_INIT;
01340
01341
01342
01343 argv[0] = TEST_EXIT_BINARY;
01344 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01345 NULL, NULL, NULL,
01346 &error))
01347 {
01348 _dbus_babysitter_block_for_child_exit (sitter);
01349 _dbus_babysitter_set_child_exit_error (sitter, &error);
01350 }
01351
01352 if (sitter)
01353 _dbus_babysitter_unref (sitter);
01354
01355 if (!dbus_error_is_set (&error))
01356 {
01357 _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
01358 return FALSE;
01359 }
01360
01361 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01362 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
01363 {
01364 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
01365 error.name, error.message);
01366 dbus_error_free (&error);
01367 return FALSE;
01368 }
01369
01370 dbus_error_free (&error);
01371
01372 return TRUE;
01373 }
01374
01375 static dbus_bool_t
01376 check_spawn_and_kill (void *data)
01377 {
01378 char *argv[4] = { NULL, NULL, NULL, NULL };
01379 DBusBabysitter *sitter = NULL;
01380 DBusError error = DBUS_ERROR_INIT;
01381
01382
01383
01384 argv[0] = TEST_SLEEP_FOREVER_BINARY;
01385 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01386 NULL, NULL, NULL,
01387 &error))
01388 {
01389 _dbus_babysitter_kill_child (sitter);
01390
01391 _dbus_babysitter_block_for_child_exit (sitter);
01392
01393 _dbus_babysitter_set_child_exit_error (sitter, &error);
01394 }
01395
01396 if (sitter)
01397 _dbus_babysitter_unref (sitter);
01398
01399 if (!dbus_error_is_set (&error))
01400 {
01401 _dbus_warn ("Did not get an error after killing spawned binary\n");
01402 return FALSE;
01403 }
01404
01405 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01406 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01407 {
01408 _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
01409 error.name, error.message);
01410 dbus_error_free (&error);
01411 return FALSE;
01412 }
01413
01414 dbus_error_free (&error);
01415
01416 return TRUE;
01417 }
01418
01419 dbus_bool_t
01420 _dbus_spawn_test (const char *test_data_dir)
01421 {
01422 if (!_dbus_test_oom_handling ("spawn_nonexistent",
01423 check_spawn_nonexistent,
01424 NULL))
01425 return FALSE;
01426
01427 if (!_dbus_test_oom_handling ("spawn_segfault",
01428 check_spawn_segfault,
01429 NULL))
01430 return FALSE;
01431
01432 if (!_dbus_test_oom_handling ("spawn_exit",
01433 check_spawn_exit,
01434 NULL))
01435 return FALSE;
01436
01437 if (!_dbus_test_oom_handling ("spawn_and_kill",
01438 check_spawn_and_kill,
01439 NULL))
01440 return FALSE;
01441
01442 return TRUE;
01443 }
01444 #endif