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