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