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