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 DBusBabysitterFinishedFunc finished_cb;
00209 void *finished_data;
00210
00211 int errnum;
00212 int status;
00213 unsigned int have_child_status : 1;
00214 unsigned int have_fork_errnum : 1;
00215 unsigned int have_exec_errnum : 1;
00216 };
00217
00218 static DBusBabysitter*
00219 _dbus_babysitter_new (void)
00220 {
00221 DBusBabysitter *sitter;
00222
00223 sitter = dbus_new0 (DBusBabysitter, 1);
00224 if (sitter == NULL)
00225 return NULL;
00226
00227 sitter->refcount = 1;
00228
00229 sitter->socket_to_babysitter = -1;
00230 sitter->error_pipe_from_child = -1;
00231
00232 sitter->sitter_pid = -1;
00233 sitter->grandchild_pid = -1;
00234
00235 sitter->watches = _dbus_watch_list_new ();
00236 if (sitter->watches == NULL)
00237 goto failed;
00238
00239 return sitter;
00240
00241 failed:
00242 _dbus_babysitter_unref (sitter);
00243 return NULL;
00244 }
00245
00252 DBusBabysitter *
00253 _dbus_babysitter_ref (DBusBabysitter *sitter)
00254 {
00255 _dbus_assert (sitter != NULL);
00256 _dbus_assert (sitter->refcount > 0);
00257
00258 sitter->refcount += 1;
00259
00260 return sitter;
00261 }
00262
00263 static void close_socket_to_babysitter (DBusBabysitter *sitter);
00264 static void close_error_pipe_from_child (DBusBabysitter *sitter);
00265
00274 void
00275 _dbus_babysitter_unref (DBusBabysitter *sitter)
00276 {
00277 _dbus_assert (sitter != NULL);
00278 _dbus_assert (sitter->refcount > 0);
00279
00280 sitter->refcount -= 1;
00281 if (sitter->refcount == 0)
00282 {
00283
00284
00285
00286
00287
00288
00289
00290 close_socket_to_babysitter (sitter);
00291
00292 close_error_pipe_from_child (sitter);
00293
00294 if (sitter->sitter_pid > 0)
00295 {
00296 int status;
00297 int ret;
00298
00299
00300
00301
00302
00303 ret = waitpid (sitter->sitter_pid, &status, WNOHANG);
00304
00305
00306
00307
00308 if (ret == 0)
00309 kill (sitter->sitter_pid, SIGKILL);
00310
00311 again:
00312 if (ret == 0)
00313 ret = waitpid (sitter->sitter_pid, &status, 0);
00314
00315 if (ret < 0)
00316 {
00317 if (errno == EINTR)
00318 goto again;
00319 else if (errno == ECHILD)
00320 _dbus_warn ("Babysitter process not available to be reaped; should not happen\n");
00321 else
00322 _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s\n",
00323 errno, _dbus_strerror (errno));
00324 }
00325 else
00326 {
00327 _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n",
00328 (long) ret, (long) sitter->sitter_pid);
00329
00330 if (WIFEXITED (sitter->status))
00331 _dbus_verbose ("Babysitter exited with status %d\n",
00332 WEXITSTATUS (sitter->status));
00333 else if (WIFSIGNALED (sitter->status))
00334 _dbus_verbose ("Babysitter received signal %d\n",
00335 WTERMSIG (sitter->status));
00336 else
00337 _dbus_verbose ("Babysitter exited abnormally\n");
00338 }
00339
00340 sitter->sitter_pid = -1;
00341 }
00342
00343 if (sitter->watches)
00344 _dbus_watch_list_free (sitter->watches);
00345
00346 dbus_free (sitter->executable);
00347
00348 dbus_free (sitter);
00349 }
00350 }
00351
00352 static ReadStatus
00353 read_data (DBusBabysitter *sitter,
00354 int fd)
00355 {
00356 int what;
00357 int got;
00358 DBusError error = DBUS_ERROR_INIT;
00359 ReadStatus r;
00360
00361 r = read_ints (fd, &what, 1, &got, &error);
00362
00363 switch (r)
00364 {
00365 case READ_STATUS_ERROR:
00366 _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message);
00367 dbus_error_free (&error);
00368 return r;
00369
00370 case READ_STATUS_EOF:
00371 return r;
00372
00373 case READ_STATUS_OK:
00374 break;
00375 }
00376
00377 if (got == 1)
00378 {
00379 switch (what)
00380 {
00381 case CHILD_EXITED:
00382 case CHILD_FORK_FAILED:
00383 case CHILD_EXEC_FAILED:
00384 {
00385 int arg;
00386
00387 r = read_ints (fd, &arg, 1, &got, &error);
00388
00389 switch (r)
00390 {
00391 case READ_STATUS_ERROR:
00392 _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message);
00393 dbus_error_free (&error);
00394 return r;
00395 case READ_STATUS_EOF:
00396 return r;
00397 case READ_STATUS_OK:
00398 break;
00399 }
00400
00401 if (got == 1)
00402 {
00403 if (what == CHILD_EXITED)
00404 {
00405 sitter->have_child_status = TRUE;
00406 sitter->status = arg;
00407 sitter->errnum = 0;
00408 _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
00409 WIFEXITED (sitter->status), WIFSIGNALED (sitter->status),
00410 WEXITSTATUS (sitter->status), WTERMSIG (sitter->status));
00411 }
00412 else if (what == CHILD_FORK_FAILED)
00413 {
00414 sitter->have_fork_errnum = TRUE;
00415 sitter->errnum = arg;
00416 _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum);
00417 }
00418 else if (what == CHILD_EXEC_FAILED)
00419 {
00420 sitter->have_exec_errnum = TRUE;
00421 sitter->errnum = arg;
00422 _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum);
00423 }
00424 }
00425 }
00426 break;
00427 case CHILD_PID:
00428 {
00429 pid_t pid = -1;
00430
00431 r = read_pid (fd, &pid, &error);
00432
00433 switch (r)
00434 {
00435 case READ_STATUS_ERROR:
00436 _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message);
00437 dbus_error_free (&error);
00438 return r;
00439 case READ_STATUS_EOF:
00440 return r;
00441 case READ_STATUS_OK:
00442 break;
00443 }
00444
00445 sitter->grandchild_pid = pid;
00446
00447 _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid);
00448 }
00449 break;
00450 default:
00451 _dbus_warn ("Unknown message received from babysitter process\n");
00452 break;
00453 }
00454 }
00455
00456 return r;
00457 }
00458
00459 static void
00460 close_socket_to_babysitter (DBusBabysitter *sitter)
00461 {
00462 _dbus_verbose ("Closing babysitter\n");
00463
00464 if (sitter->sitter_watch != NULL)
00465 {
00466 _dbus_assert (sitter->watches != NULL);
00467 _dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch);
00468 _dbus_watch_invalidate (sitter->sitter_watch);
00469 _dbus_watch_unref (sitter->sitter_watch);
00470 sitter->sitter_watch = NULL;
00471 }
00472
00473 if (sitter->socket_to_babysitter >= 0)
00474 {
00475 _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00476 sitter->socket_to_babysitter = -1;
00477 }
00478 }
00479
00480 static void
00481 close_error_pipe_from_child (DBusBabysitter *sitter)
00482 {
00483 _dbus_verbose ("Closing child error\n");
00484
00485 if (sitter->error_watch != NULL)
00486 {
00487 _dbus_assert (sitter->watches != NULL);
00488 _dbus_watch_list_remove_watch (sitter->watches, sitter->error_watch);
00489 _dbus_watch_invalidate (sitter->error_watch);
00490 _dbus_watch_unref (sitter->error_watch);
00491 sitter->error_watch = NULL;
00492 }
00493
00494 if (sitter->error_pipe_from_child >= 0)
00495 {
00496 _dbus_close_socket (sitter->error_pipe_from_child, NULL);
00497 sitter->error_pipe_from_child = -1;
00498 }
00499 }
00500
00501 static void
00502 handle_babysitter_socket (DBusBabysitter *sitter,
00503 int revents)
00504 {
00505
00506
00507
00508
00509 if (revents & _DBUS_POLLIN)
00510 {
00511 _dbus_verbose ("Reading data from babysitter\n");
00512 if (read_data (sitter, sitter->socket_to_babysitter) != READ_STATUS_OK)
00513 close_socket_to_babysitter (sitter);
00514 }
00515 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00516 {
00517 close_socket_to_babysitter (sitter);
00518 }
00519 }
00520
00521 static void
00522 handle_error_pipe (DBusBabysitter *sitter,
00523 int revents)
00524 {
00525 if (revents & _DBUS_POLLIN)
00526 {
00527 _dbus_verbose ("Reading data from child error\n");
00528 if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK)
00529 close_error_pipe_from_child (sitter);
00530 }
00531 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00532 {
00533 close_error_pipe_from_child (sitter);
00534 }
00535 }
00536
00537
00538 static dbus_bool_t
00539 babysitter_iteration (DBusBabysitter *sitter,
00540 dbus_bool_t block)
00541 {
00542 DBusPollFD fds[2];
00543 int i;
00544 dbus_bool_t descriptors_ready;
00545
00546 descriptors_ready = FALSE;
00547
00548 i = 0;
00549
00550 if (sitter->error_pipe_from_child >= 0)
00551 {
00552 fds[i].fd = sitter->error_pipe_from_child;
00553 fds[i].events = _DBUS_POLLIN;
00554 fds[i].revents = 0;
00555 ++i;
00556 }
00557
00558 if (sitter->socket_to_babysitter >= 0)
00559 {
00560 fds[i].fd = sitter->socket_to_babysitter;
00561 fds[i].events = _DBUS_POLLIN;
00562 fds[i].revents = 0;
00563 ++i;
00564 }
00565
00566 if (i > 0)
00567 {
00568 int ret;
00569
00570 do
00571 {
00572 ret = _dbus_poll (fds, i, 0);
00573 }
00574 while (ret < 0 && errno == EINTR);
00575
00576 if (ret == 0 && block)
00577 {
00578 do
00579 {
00580 ret = _dbus_poll (fds, i, -1);
00581 }
00582 while (ret < 0 && errno == EINTR);
00583 }
00584
00585 if (ret > 0)
00586 {
00587 descriptors_ready = TRUE;
00588
00589 while (i > 0)
00590 {
00591 --i;
00592 if (fds[i].fd == sitter->error_pipe_from_child)
00593 handle_error_pipe (sitter, fds[i].revents);
00594 else if (fds[i].fd == sitter->socket_to_babysitter)
00595 handle_babysitter_socket (sitter, fds[i].revents);
00596 }
00597 }
00598 }
00599
00600 return descriptors_ready;
00601 }
00602
00607 #define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter >= 0 || (sitter)->error_pipe_from_child >= 0)
00608
00615 void
00616 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
00617 {
00618
00619 while (LIVE_CHILDREN (sitter) &&
00620 sitter->grandchild_pid == -1)
00621 babysitter_iteration (sitter, TRUE);
00622
00623 _dbus_verbose ("Got child PID %ld for killing\n",
00624 (long) sitter->grandchild_pid);
00625
00626 if (sitter->grandchild_pid == -1)
00627 return;
00628
00629 kill (sitter->grandchild_pid, SIGKILL);
00630 }
00631
00637 dbus_bool_t
00638 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
00639 {
00640
00641
00642 while (LIVE_CHILDREN (sitter) &&
00643 babysitter_iteration (sitter, FALSE))
00644 ;
00645
00646
00647 return sitter->socket_to_babysitter < 0;
00648 }
00649
00662 dbus_bool_t
00663 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
00664 int *status)
00665 {
00666 if (!_dbus_babysitter_get_child_exited (sitter))
00667 _dbus_assert_not_reached ("Child has not exited");
00668
00669 if (!sitter->have_child_status ||
00670 !(WIFEXITED (sitter->status)))
00671 return FALSE;
00672
00673 *status = WEXITSTATUS (sitter->status);
00674 return TRUE;
00675 }
00676
00686 void
00687 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
00688 DBusError *error)
00689 {
00690 if (!_dbus_babysitter_get_child_exited (sitter))
00691 return;
00692
00693
00694
00695
00696
00697 if (sitter->have_exec_errnum)
00698 {
00699 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00700 "Failed to execute program %s: %s",
00701 sitter->executable, _dbus_strerror (sitter->errnum));
00702 }
00703 else if (sitter->have_fork_errnum)
00704 {
00705 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00706 "Failed to fork a new process %s: %s",
00707 sitter->executable, _dbus_strerror (sitter->errnum));
00708 }
00709 else if (sitter->have_child_status)
00710 {
00711 if (WIFEXITED (sitter->status))
00712 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00713 "Process %s exited with status %d",
00714 sitter->executable, WEXITSTATUS (sitter->status));
00715 else if (WIFSIGNALED (sitter->status))
00716 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,
00717 "Process %s received signal %d",
00718 sitter->executable, WTERMSIG (sitter->status));
00719 else
00720 dbus_set_error (error, DBUS_ERROR_FAILED,
00721 "Process %s exited abnormally",
00722 sitter->executable);
00723 }
00724 else
00725 {
00726 dbus_set_error (error, DBUS_ERROR_FAILED,
00727 "Process %s exited, reason unknown",
00728 sitter->executable);
00729 }
00730 }
00731
00744 dbus_bool_t
00745 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter,
00746 DBusAddWatchFunction add_function,
00747 DBusRemoveWatchFunction remove_function,
00748 DBusWatchToggledFunction toggled_function,
00749 void *data,
00750 DBusFreeFunction free_data_function)
00751 {
00752 return _dbus_watch_list_set_functions (sitter->watches,
00753 add_function,
00754 remove_function,
00755 toggled_function,
00756 data,
00757 free_data_function);
00758 }
00759
00760 static dbus_bool_t
00761 handle_watch (DBusWatch *watch,
00762 unsigned int condition,
00763 void *data)
00764 {
00765 DBusBabysitter *sitter = _dbus_babysitter_ref (data);
00766 int revents;
00767 int fd;
00768
00769 revents = 0;
00770 if (condition & DBUS_WATCH_READABLE)
00771 revents |= _DBUS_POLLIN;
00772 if (condition & DBUS_WATCH_ERROR)
00773 revents |= _DBUS_POLLERR;
00774 if (condition & DBUS_WATCH_HANGUP)
00775 revents |= _DBUS_POLLHUP;
00776
00777 fd = dbus_watch_get_socket (watch);
00778
00779 if (fd == sitter->error_pipe_from_child)
00780 handle_error_pipe (sitter, revents);
00781 else if (fd == sitter->socket_to_babysitter)
00782 handle_babysitter_socket (sitter, revents);
00783
00784 while (LIVE_CHILDREN (sitter) &&
00785 babysitter_iteration (sitter, FALSE))
00786 ;
00787
00788
00789
00790 _dbus_assert (sitter->socket_to_babysitter != -1 || sitter->sitter_watch == NULL);
00791 _dbus_assert (sitter->error_pipe_from_child != -1 || sitter->error_watch == NULL);
00792
00793 if (_dbus_babysitter_get_child_exited (sitter) &&
00794 sitter->finished_cb != NULL)
00795 {
00796 sitter->finished_cb (sitter, sitter->finished_data);
00797 sitter->finished_cb = NULL;
00798 }
00799
00800 _dbus_babysitter_unref (sitter);
00801 return TRUE;
00802 }
00803
00805 #define READ_END 0
00806
00807 #define WRITE_END 1
00808
00809
00810
00811
00812
00813
00814 static int
00815 close_and_invalidate (int *fd)
00816 {
00817 int ret;
00818
00819 if (*fd < 0)
00820 return -1;
00821 else
00822 {
00823 ret = _dbus_close_socket (*fd, NULL);
00824 *fd = -1;
00825 }
00826
00827 return ret;
00828 }
00829
00830 static dbus_bool_t
00831 make_pipe (int p[2],
00832 DBusError *error)
00833 {
00834 int retval;
00835
00836 #ifdef HAVE_PIPE2
00837 dbus_bool_t cloexec_done;
00838
00839 retval = pipe2 (p, O_CLOEXEC);
00840 cloexec_done = retval >= 0;
00841
00842
00843
00844 if (retval < 0 && errno == ENOSYS)
00845 #endif
00846 {
00847 retval = pipe(p);
00848 }
00849
00850 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00851
00852 if (retval < 0)
00853 {
00854 dbus_set_error (error,
00855 DBUS_ERROR_SPAWN_FAILED,
00856 "Failed to create pipe for communicating with child process (%s)",
00857 _dbus_strerror (errno));
00858 return FALSE;
00859 }
00860
00861 #ifdef HAVE_PIPE2
00862 if (!cloexec_done)
00863 #endif
00864 {
00865 _dbus_fd_set_close_on_exec (p[0]);
00866 _dbus_fd_set_close_on_exec (p[1]);
00867 }
00868
00869 return TRUE;
00870 }
00871
00872 static void
00873 do_write (int fd, const void *buf, size_t count)
00874 {
00875 size_t bytes_written;
00876 int ret;
00877
00878 bytes_written = 0;
00879
00880 again:
00881
00882 ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
00883
00884 if (ret < 0)
00885 {
00886 if (errno == EINTR)
00887 goto again;
00888 else
00889 {
00890 _dbus_warn ("Failed to write data to pipe!\n");
00891 exit (1);
00892 }
00893 }
00894 else
00895 bytes_written += ret;
00896
00897 if (bytes_written < count)
00898 goto again;
00899 }
00900
00901 static void
00902 write_err_and_exit (int fd, int msg)
00903 {
00904 int en = errno;
00905
00906 do_write (fd, &msg, sizeof (msg));
00907 do_write (fd, &en, sizeof (en));
00908
00909 exit (1);
00910 }
00911
00912 static void
00913 write_pid (int fd, pid_t pid)
00914 {
00915 int msg = CHILD_PID;
00916
00917 do_write (fd, &msg, sizeof (msg));
00918 do_write (fd, &pid, sizeof (pid));
00919 }
00920
00921 static void
00922 write_status_and_exit (int fd, int status)
00923 {
00924 int msg = CHILD_EXITED;
00925
00926 do_write (fd, &msg, sizeof (msg));
00927 do_write (fd, &status, sizeof (status));
00928
00929 exit (0);
00930 }
00931
00932 static void
00933 do_exec (int child_err_report_fd,
00934 char **argv,
00935 char **envp,
00936 DBusSpawnChildSetupFunc child_setup,
00937 void *user_data)
00938 {
00939 #ifdef DBUS_BUILD_TESTS
00940 int i, max_open;
00941 #endif
00942
00943 _dbus_verbose_reset ();
00944 _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n",
00945 _dbus_getpid ());
00946
00947 if (child_setup)
00948 (* child_setup) (user_data);
00949
00950 #ifdef DBUS_BUILD_TESTS
00951 max_open = sysconf (_SC_OPEN_MAX);
00952
00953 for (i = 3; i < max_open; i++)
00954 {
00955 int retval;
00956
00957 if (i == child_err_report_fd)
00958 continue;
00959
00960 retval = fcntl (i, F_GETFD);
00961
00962 if (retval != -1 && !(retval & FD_CLOEXEC))
00963 _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
00964 }
00965 #endif
00966
00967 if (envp == NULL)
00968 {
00969 _dbus_assert (environ != NULL);
00970
00971 envp = environ;
00972 }
00973
00974 execve (argv[0], argv, envp);
00975
00976
00977 write_err_and_exit (child_err_report_fd,
00978 CHILD_EXEC_FAILED);
00979 }
00980
00981 static void
00982 check_babysit_events (pid_t grandchild_pid,
00983 int parent_pipe,
00984 int revents)
00985 {
00986 pid_t ret;
00987 int status;
00988
00989 do
00990 {
00991 ret = waitpid (grandchild_pid, &status, WNOHANG);
00992
00993
00994
00995 }
00996 while (ret < 0 && errno == EINTR);
00997
00998 if (ret == 0)
00999 {
01000 _dbus_verbose ("no child exited\n");
01001
01002 ;
01003 }
01004 else if (ret < 0)
01005 {
01006
01007 _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n",
01008 _dbus_strerror (errno));
01009 exit (1);
01010 }
01011 else if (ret == grandchild_pid)
01012 {
01013
01014 _dbus_verbose ("reaped child pid %ld\n", (long) ret);
01015
01016 write_status_and_exit (parent_pipe, status);
01017 }
01018 else
01019 {
01020 _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n",
01021 (int) ret);
01022 exit (1);
01023 }
01024
01025 if (revents & _DBUS_POLLIN)
01026 {
01027 _dbus_verbose ("babysitter got POLLIN from parent pipe\n");
01028 }
01029
01030 if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
01031 {
01032
01033 _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n");
01034 exit (0);
01035 }
01036 }
01037
01038 static int babysit_sigchld_pipe = -1;
01039
01040 static void
01041 babysit_signal_handler (int signo)
01042 {
01043 char b = '\0';
01044 again:
01045 if (write (babysit_sigchld_pipe, &b, 1) <= 0)
01046 if (errno == EINTR)
01047 goto again;
01048 }
01049
01050 static void
01051 babysit (pid_t grandchild_pid,
01052 int parent_pipe)
01053 {
01054 int sigchld_pipe[2];
01055
01056
01057
01058
01059 _dbus_verbose_reset ();
01060
01061
01062
01063
01064
01065
01066 if (pipe (sigchld_pipe) < 0)
01067 {
01068 _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n");
01069 exit (1);
01070 }
01071
01072 babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
01073
01074 _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
01075
01076 write_pid (parent_pipe, grandchild_pid);
01077
01078 check_babysit_events (grandchild_pid, parent_pipe, 0);
01079
01080 while (TRUE)
01081 {
01082 DBusPollFD pfds[2];
01083
01084 pfds[0].fd = parent_pipe;
01085 pfds[0].events = _DBUS_POLLIN;
01086 pfds[0].revents = 0;
01087
01088 pfds[1].fd = sigchld_pipe[READ_END];
01089 pfds[1].events = _DBUS_POLLIN;
01090 pfds[1].revents = 0;
01091
01092 if (_dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1) < 0 && errno != EINTR)
01093 {
01094 _dbus_warn ("_dbus_poll() error: %s\n", strerror (errno));
01095 exit (1);
01096 }
01097
01098 if (pfds[0].revents != 0)
01099 {
01100 check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
01101 }
01102 else if (pfds[1].revents & _DBUS_POLLIN)
01103 {
01104 char b;
01105 if (read (sigchld_pipe[READ_END], &b, 1) == -1)
01106 {
01107
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
01193
01194 _dbus_watch_invalidate (sitter->error_watch);
01195 _dbus_watch_unref (sitter->error_watch);
01196 sitter->error_watch = NULL;
01197
01198 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01199 goto cleanup_and_fail;
01200 }
01201
01202 sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
01203 DBUS_WATCH_READABLE,
01204 TRUE, handle_watch, sitter, NULL);
01205 if (sitter->sitter_watch == NULL)
01206 {
01207 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01208 goto cleanup_and_fail;
01209 }
01210
01211 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
01212 {
01213
01214
01215 _dbus_watch_invalidate (sitter->sitter_watch);
01216 _dbus_watch_unref (sitter->sitter_watch);
01217 sitter->sitter_watch = NULL;
01218
01219 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01220 goto cleanup_and_fail;
01221 }
01222
01223 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01224
01225 pid = fork ();
01226
01227 if (pid < 0)
01228 {
01229 dbus_set_error (error,
01230 DBUS_ERROR_SPAWN_FORK_FAILED,
01231 "Failed to fork (%s)",
01232 _dbus_strerror (errno));
01233 goto cleanup_and_fail;
01234 }
01235 else if (pid == 0)
01236 {
01237
01238 int grandchild_pid;
01239
01240
01241
01242
01243 signal (SIGPIPE, SIG_DFL);
01244
01245
01246 close_and_invalidate (&child_err_report_pipe[READ_END]);
01247 close_and_invalidate (&babysitter_pipe[0]);
01248
01249
01250 grandchild_pid = fork ();
01251
01252 if (grandchild_pid < 0)
01253 {
01254 write_err_and_exit (babysitter_pipe[1],
01255 CHILD_FORK_FAILED);
01256 _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
01257 }
01258 else if (grandchild_pid == 0)
01259 {
01260 do_exec (child_err_report_pipe[WRITE_END],
01261 argv,
01262 env,
01263 child_setup, user_data);
01264 _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
01265 }
01266 else
01267 {
01268 babysit (grandchild_pid, babysitter_pipe[1]);
01269 _dbus_assert_not_reached ("Got to code after babysit()");
01270 }
01271 }
01272 else
01273 {
01274
01275 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01276 close_and_invalidate (&babysitter_pipe[1]);
01277
01278 sitter->socket_to_babysitter = babysitter_pipe[0];
01279 babysitter_pipe[0] = -1;
01280
01281 sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
01282 child_err_report_pipe[READ_END] = -1;
01283
01284 sitter->sitter_pid = pid;
01285
01286 if (sitter_p != NULL)
01287 *sitter_p = sitter;
01288 else
01289 _dbus_babysitter_unref (sitter);
01290
01291 dbus_free_string_array (env);
01292
01293 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01294
01295 return TRUE;
01296 }
01297
01298 cleanup_and_fail:
01299
01300 _DBUS_ASSERT_ERROR_IS_SET (error);
01301
01302 close_and_invalidate (&child_err_report_pipe[READ_END]);
01303 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01304 close_and_invalidate (&babysitter_pipe[0]);
01305 close_and_invalidate (&babysitter_pipe[1]);
01306
01307 if (sitter != NULL)
01308 _dbus_babysitter_unref (sitter);
01309
01310 return FALSE;
01311 }
01312
01313 void
01314 _dbus_babysitter_set_result_function (DBusBabysitter *sitter,
01315 DBusBabysitterFinishedFunc finished,
01316 void *user_data)
01317 {
01318 sitter->finished_cb = finished;
01319 sitter->finished_data = user_data;
01320 }
01321
01324 #ifdef DBUS_BUILD_TESTS
01325
01326 static char *
01327 get_test_exec (const char *exe,
01328 DBusString *scratch_space)
01329 {
01330 const char *dbus_test_exec;
01331
01332 dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC");
01333
01334 if (dbus_test_exec == NULL)
01335 dbus_test_exec = DBUS_TEST_EXEC;
01336
01337 if (!_dbus_string_init (scratch_space))
01338 return NULL;
01339
01340 if (!_dbus_string_append_printf (scratch_space, "%s/%s%s",
01341 dbus_test_exec, exe, DBUS_EXEEXT))
01342 {
01343 _dbus_string_free (scratch_space);
01344 return NULL;
01345 }
01346
01347 return _dbus_string_get_data (scratch_space);
01348 }
01349
01350 static void
01351 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
01352 {
01353 while (LIVE_CHILDREN (sitter))
01354 babysitter_iteration (sitter, TRUE);
01355 }
01356
01357 static dbus_bool_t
01358 check_spawn_nonexistent (void *data)
01359 {
01360 char *argv[4] = { NULL, NULL, NULL, NULL };
01361 DBusBabysitter *sitter = NULL;
01362 DBusError error = DBUS_ERROR_INIT;
01363
01364
01365
01366 argv[0] = "/this/does/not/exist/32542sdgafgafdg";
01367 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01368 NULL, NULL, NULL,
01369 &error))
01370 {
01371 _dbus_babysitter_block_for_child_exit (sitter);
01372 _dbus_babysitter_set_child_exit_error (sitter, &error);
01373 }
01374
01375 if (sitter)
01376 _dbus_babysitter_unref (sitter);
01377
01378 if (!dbus_error_is_set (&error))
01379 {
01380 _dbus_warn ("Did not get an error launching nonexistent executable\n");
01381 return FALSE;
01382 }
01383
01384 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01385 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
01386 {
01387 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
01388 error.name, error.message);
01389 dbus_error_free (&error);
01390 return FALSE;
01391 }
01392
01393 dbus_error_free (&error);
01394
01395 return TRUE;
01396 }
01397
01398 static dbus_bool_t
01399 check_spawn_segfault (void *data)
01400 {
01401 char *argv[4] = { NULL, NULL, NULL, NULL };
01402 DBusBabysitter *sitter = NULL;
01403 DBusError error = DBUS_ERROR_INIT;
01404 DBusString argv0;
01405
01406
01407
01408 argv[0] = get_test_exec ("test-segfault", &argv0);
01409
01410 if (argv[0] == NULL)
01411 {
01412
01413 return TRUE;
01414 }
01415
01416 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01417 NULL, NULL, NULL,
01418 &error))
01419 {
01420 _dbus_babysitter_block_for_child_exit (sitter);
01421 _dbus_babysitter_set_child_exit_error (sitter, &error);
01422 }
01423
01424 _dbus_string_free (&argv0);
01425
01426 if (sitter)
01427 _dbus_babysitter_unref (sitter);
01428
01429 if (!dbus_error_is_set (&error))
01430 {
01431 _dbus_warn ("Did not get an error launching segfaulting binary\n");
01432 return FALSE;
01433 }
01434
01435 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01436 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01437 {
01438 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
01439 error.name, error.message);
01440 dbus_error_free (&error);
01441 return FALSE;
01442 }
01443
01444 dbus_error_free (&error);
01445
01446 return TRUE;
01447 }
01448
01449 static dbus_bool_t
01450 check_spawn_exit (void *data)
01451 {
01452 char *argv[4] = { NULL, NULL, NULL, NULL };
01453 DBusBabysitter *sitter = NULL;
01454 DBusError error = DBUS_ERROR_INIT;
01455 DBusString argv0;
01456
01457
01458
01459 argv[0] = get_test_exec ("test-exit", &argv0);
01460
01461 if (argv[0] == NULL)
01462 {
01463
01464 return TRUE;
01465 }
01466
01467 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01468 NULL, NULL, NULL,
01469 &error))
01470 {
01471 _dbus_babysitter_block_for_child_exit (sitter);
01472 _dbus_babysitter_set_child_exit_error (sitter, &error);
01473 }
01474
01475 _dbus_string_free (&argv0);
01476
01477 if (sitter)
01478 _dbus_babysitter_unref (sitter);
01479
01480 if (!dbus_error_is_set (&error))
01481 {
01482 _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
01483 return FALSE;
01484 }
01485
01486 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01487 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
01488 {
01489 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
01490 error.name, error.message);
01491 dbus_error_free (&error);
01492 return FALSE;
01493 }
01494
01495 dbus_error_free (&error);
01496
01497 return TRUE;
01498 }
01499
01500 static dbus_bool_t
01501 check_spawn_and_kill (void *data)
01502 {
01503 char *argv[4] = { NULL, NULL, NULL, NULL };
01504 DBusBabysitter *sitter = NULL;
01505 DBusError error = DBUS_ERROR_INIT;
01506 DBusString argv0;
01507
01508
01509
01510 argv[0] = get_test_exec ("test-sleep-forever", &argv0);
01511
01512 if (argv[0] == NULL)
01513 {
01514
01515 return TRUE;
01516 }
01517
01518 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01519 NULL, NULL, NULL,
01520 &error))
01521 {
01522 _dbus_babysitter_kill_child (sitter);
01523
01524 _dbus_babysitter_block_for_child_exit (sitter);
01525
01526 _dbus_babysitter_set_child_exit_error (sitter, &error);
01527 }
01528
01529 _dbus_string_free (&argv0);
01530
01531 if (sitter)
01532 _dbus_babysitter_unref (sitter);
01533
01534 if (!dbus_error_is_set (&error))
01535 {
01536 _dbus_warn ("Did not get an error after killing spawned binary\n");
01537 return FALSE;
01538 }
01539
01540 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01541 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01542 {
01543 _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
01544 error.name, error.message);
01545 dbus_error_free (&error);
01546 return FALSE;
01547 }
01548
01549 dbus_error_free (&error);
01550
01551 return TRUE;
01552 }
01553
01554 dbus_bool_t
01555 _dbus_spawn_test (const char *test_data_dir)
01556 {
01557 if (!_dbus_test_oom_handling ("spawn_nonexistent",
01558 check_spawn_nonexistent,
01559 NULL))
01560 return FALSE;
01561
01562 if (!_dbus_test_oom_handling ("spawn_segfault",
01563 check_spawn_segfault,
01564 NULL))
01565 return FALSE;
01566
01567 if (!_dbus_test_oom_handling ("spawn_exit",
01568 check_spawn_exit,
01569 NULL))
01570 return FALSE;
01571
01572 if (!_dbus_test_oom_handling ("spawn_and_kill",
01573 check_spawn_and_kill,
01574 NULL))
01575 return FALSE;
01576
01577 return TRUE;
01578 }
01579 #endif