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