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