00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "dbus-spawn.h"
00025 #include "dbus-sysdeps-unix.h"
00026 #include "dbus-internals.h"
00027 #include "dbus-test.h"
00028 #include "dbus-protocol.h"
00029
00030 #include <unistd.h>
00031 #include <fcntl.h>
00032 #include <signal.h>
00033 #include <sys/wait.h>
00034 #include <stdlib.h>
00035 #ifdef HAVE_ERRNO_H
00036 #include <errno.h>
00037 #endif
00038 #ifdef _POSIX_PRIORITY_SCHEDULING
00039 #include <sched.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 return TRUE;
00779 }
00780
00782 #define READ_END 0
00783
00784 #define WRITE_END 1
00785
00786
00787
00788
00789
00790
00791 static int
00792 close_and_invalidate (int *fd)
00793 {
00794 int ret;
00795
00796 if (*fd < 0)
00797 return -1;
00798 else
00799 {
00800 ret = _dbus_close_socket (*fd, NULL);
00801 *fd = -1;
00802 }
00803
00804 return ret;
00805 }
00806
00807 static dbus_bool_t
00808 make_pipe (int p[2],
00809 DBusError *error)
00810 {
00811 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00812
00813 if (pipe (p) < 0)
00814 {
00815 dbus_set_error (error,
00816 DBUS_ERROR_SPAWN_FAILED,
00817 "Failed to create pipe for communicating with child process (%s)",
00818 _dbus_strerror (errno));
00819 return FALSE;
00820 }
00821
00822 return TRUE;
00823 }
00824
00825 static void
00826 do_write (int fd, const void *buf, size_t count)
00827 {
00828 size_t bytes_written;
00829 int ret;
00830
00831 bytes_written = 0;
00832
00833 again:
00834
00835 ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
00836
00837 if (ret < 0)
00838 {
00839 if (errno == EINTR)
00840 goto again;
00841 else
00842 {
00843 _dbus_warn ("Failed to write data to pipe!\n");
00844 exit (1);
00845 }
00846 }
00847 else
00848 bytes_written += ret;
00849
00850 if (bytes_written < count)
00851 goto again;
00852 }
00853
00854 static void
00855 write_err_and_exit (int fd, int msg)
00856 {
00857 int en = errno;
00858
00859 do_write (fd, &msg, sizeof (msg));
00860 do_write (fd, &en, sizeof (en));
00861
00862 exit (1);
00863 }
00864
00865 static void
00866 write_pid (int fd, pid_t pid)
00867 {
00868 int msg = CHILD_PID;
00869
00870 do_write (fd, &msg, sizeof (msg));
00871 do_write (fd, &pid, sizeof (pid));
00872 }
00873
00874 static void
00875 write_status_and_exit (int fd, int status)
00876 {
00877 int msg = CHILD_EXITED;
00878
00879 do_write (fd, &msg, sizeof (msg));
00880 do_write (fd, &status, sizeof (status));
00881
00882 exit (0);
00883 }
00884
00885 static void
00886 do_exec (int child_err_report_fd,
00887 char **argv,
00888 char **envp,
00889 DBusSpawnChildSetupFunc child_setup,
00890 void *user_data)
00891 {
00892 #ifdef DBUS_BUILD_TESTS
00893 int i, max_open;
00894 #endif
00895
00896 int oom = open ("/proc/self/oom_adj", O_WRONLY|O_SYNC);
00897 if (oom >= 0)
00898 {
00899 write (oom, "0", sizeof (char));
00900 _dbus_close (oom, NULL);
00901 }
00902
00903 _dbus_verbose_reset ();
00904 _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n",
00905 _dbus_getpid ());
00906
00907 if (child_setup)
00908 (* child_setup) (user_data);
00909
00910 #ifdef DBUS_BUILD_TESTS
00911 max_open = sysconf (_SC_OPEN_MAX);
00912
00913 for (i = 3; i < max_open; i++)
00914 {
00915 int retval;
00916
00917 if (i == child_err_report_fd)
00918 continue;
00919
00920 retval = fcntl (i, F_GETFD);
00921
00922 if (retval != -1 && !(retval & FD_CLOEXEC))
00923 _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
00924 }
00925 #endif
00926
00927 if (envp == NULL)
00928 {
00929 _dbus_assert (environ != NULL);
00930
00931 envp = environ;
00932 }
00933
00934 execve (argv[0], argv, envp);
00935
00936
00937 write_err_and_exit (child_err_report_fd,
00938 CHILD_EXEC_FAILED);
00939 }
00940
00941 static void
00942 check_babysit_events (pid_t grandchild_pid,
00943 int parent_pipe,
00944 int revents)
00945 {
00946 pid_t ret;
00947 int status;
00948
00949 do
00950 {
00951 ret = waitpid (grandchild_pid, &status, WNOHANG);
00952
00953
00954
00955 }
00956 while (ret < 0 && errno == EINTR);
00957
00958 if (ret == 0)
00959 {
00960 _dbus_verbose ("no child exited\n");
00961
00962 ;
00963 }
00964 else if (ret < 0)
00965 {
00966
00967 _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n",
00968 _dbus_strerror (errno));
00969 exit (1);
00970 }
00971 else if (ret == grandchild_pid)
00972 {
00973
00974 _dbus_verbose ("reaped child pid %ld\n", (long) ret);
00975
00976 write_status_and_exit (parent_pipe, status);
00977 }
00978 else
00979 {
00980 _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n",
00981 (int) ret);
00982 exit (1);
00983 }
00984
00985 if (revents & _DBUS_POLLIN)
00986 {
00987 _dbus_verbose ("babysitter got POLLIN from parent pipe\n");
00988 }
00989
00990 if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00991 {
00992
00993 _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n");
00994 exit (0);
00995 }
00996 }
00997
00998 static int babysit_sigchld_pipe = -1;
00999
01000 static void
01001 babysit_signal_handler (int signo)
01002 {
01003 char b = '\0';
01004 again:
01005 if (write (babysit_sigchld_pipe, &b, 1) <= 0)
01006 if (errno == EINTR)
01007 goto again;
01008 }
01009
01010 static void
01011 babysit (pid_t grandchild_pid,
01012 int parent_pipe)
01013 {
01014 int sigchld_pipe[2];
01015
01016
01017
01018
01019 _dbus_verbose_reset ();
01020
01021
01022
01023
01024
01025
01026 if (pipe (sigchld_pipe) < 0)
01027 {
01028 _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n");
01029 exit (1);
01030 }
01031
01032 babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
01033
01034 _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
01035
01036 write_pid (parent_pipe, grandchild_pid);
01037
01038 check_babysit_events (grandchild_pid, parent_pipe, 0);
01039
01040 while (TRUE)
01041 {
01042 DBusPollFD pfds[2];
01043
01044 pfds[0].fd = parent_pipe;
01045 pfds[0].events = _DBUS_POLLIN;
01046 pfds[0].revents = 0;
01047
01048 pfds[1].fd = sigchld_pipe[READ_END];
01049 pfds[1].events = _DBUS_POLLIN;
01050 pfds[1].revents = 0;
01051
01052 if (_dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1) < 0 && errno != EINTR)
01053 {
01054 _dbus_warn ("_dbus_poll() error: %s\n", strerror (errno));
01055 exit (1);
01056 }
01057
01058 if (pfds[0].revents != 0)
01059 {
01060 check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
01061 }
01062 else if (pfds[1].revents & _DBUS_POLLIN)
01063 {
01064 char b;
01065 read (sigchld_pipe[READ_END], &b, 1);
01066
01067 check_babysit_events (grandchild_pid, parent_pipe, 0);
01068 }
01069 }
01070
01071 exit (1);
01072 }
01073
01074 static void
01075 setup_child_priority (void)
01076 {
01077 int p;
01078 #ifdef _POSIX_PRIORITY_SCHEDULING
01079 struct sched_param sched_param;
01080
01081 sched_param.sched_priority = 0;
01082 sched_setscheduler (0, SCHED_OTHER, &sched_param);
01083 #endif
01084
01085 errno = 0;
01086 p = getpriority (PRIO_PROCESS, 0);
01087 if (!errno && p < 0)
01088 setpriority (PRIO_PROCESS, 0, 0);
01089 }
01090
01110 dbus_bool_t
01111 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
01112 char **argv,
01113 char **env,
01114 DBusSpawnChildSetupFunc child_setup,
01115 void *user_data,
01116 DBusError *error)
01117 {
01118 DBusBabysitter *sitter;
01119 int child_err_report_pipe[2] = { -1, -1 };
01120 int babysitter_pipe[2] = { -1, -1 };
01121 pid_t pid;
01122
01123 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01124
01125 if (sitter_p != NULL)
01126 *sitter_p = NULL;
01127
01128 sitter = NULL;
01129
01130 sitter = _dbus_babysitter_new ();
01131 if (sitter == NULL)
01132 {
01133 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01134 return FALSE;
01135 }
01136
01137 sitter->executable = _dbus_strdup (argv[0]);
01138 if (sitter->executable == NULL)
01139 {
01140 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01141 goto cleanup_and_fail;
01142 }
01143
01144 if (!make_pipe (child_err_report_pipe, error))
01145 goto cleanup_and_fail;
01146
01147 _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]);
01148 _dbus_fd_set_close_on_exec (child_err_report_pipe[WRITE_END]);
01149
01150 if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
01151 goto cleanup_and_fail;
01152
01153 _dbus_fd_set_close_on_exec (babysitter_pipe[0]);
01154 _dbus_fd_set_close_on_exec (babysitter_pipe[1]);
01155
01156
01157
01158
01159
01160
01161 sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
01162 DBUS_WATCH_READABLE,
01163 TRUE, handle_watch, sitter, NULL);
01164 if (sitter->error_watch == NULL)
01165 {
01166 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01167 goto cleanup_and_fail;
01168 }
01169
01170 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch))
01171 {
01172 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01173 goto cleanup_and_fail;
01174 }
01175
01176 sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
01177 DBUS_WATCH_READABLE,
01178 TRUE, handle_watch, sitter, NULL);
01179 if (sitter->sitter_watch == NULL)
01180 {
01181 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01182 goto cleanup_and_fail;
01183 }
01184
01185 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
01186 {
01187 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01188 goto cleanup_and_fail;
01189 }
01190
01191 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01192
01193 pid = fork ();
01194
01195 if (pid < 0)
01196 {
01197 dbus_set_error (error,
01198 DBUS_ERROR_SPAWN_FORK_FAILED,
01199 "Failed to fork (%s)",
01200 _dbus_strerror (errno));
01201 goto cleanup_and_fail;
01202 }
01203 else if (pid == 0)
01204 {
01205
01206 int grandchild_pid;
01207
01208
01209
01210
01211 signal (SIGPIPE, SIG_DFL);
01212
01213
01214 close_and_invalidate (&child_err_report_pipe[READ_END]);
01215 close_and_invalidate (&babysitter_pipe[0]);
01216
01217
01218 grandchild_pid = fork ();
01219
01220 if (grandchild_pid < 0)
01221 {
01222 write_err_and_exit (babysitter_pipe[1],
01223 CHILD_FORK_FAILED);
01224 _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
01225 }
01226 else if (grandchild_pid == 0)
01227 {
01228
01229
01230 if (setsid () == -1)
01231 _dbus_warn ("setsid() failed: %s\n", _dbus_strerror (errno));
01232
01233 setup_child_priority ();
01234
01235 do_exec (child_err_report_pipe[WRITE_END],
01236 argv,
01237 env,
01238 child_setup, user_data);
01239 _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
01240 }
01241 else
01242 {
01243 babysit (grandchild_pid, babysitter_pipe[1]);
01244 _dbus_assert_not_reached ("Got to code after babysit()");
01245 }
01246 }
01247 else
01248 {
01249
01250 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01251 close_and_invalidate (&babysitter_pipe[1]);
01252
01253 sitter->socket_to_babysitter = babysitter_pipe[0];
01254 babysitter_pipe[0] = -1;
01255
01256 sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
01257 child_err_report_pipe[READ_END] = -1;
01258
01259 sitter->sitter_pid = pid;
01260
01261 if (sitter_p != NULL)
01262 *sitter_p = sitter;
01263 else
01264 _dbus_babysitter_unref (sitter);
01265
01266 dbus_free_string_array (env);
01267
01268 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01269
01270 return TRUE;
01271 }
01272
01273 cleanup_and_fail:
01274
01275 _DBUS_ASSERT_ERROR_IS_SET (error);
01276
01277 close_and_invalidate (&child_err_report_pipe[READ_END]);
01278 close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01279 close_and_invalidate (&babysitter_pipe[0]);
01280 close_and_invalidate (&babysitter_pipe[1]);
01281
01282 if (sitter != NULL)
01283 _dbus_babysitter_unref (sitter);
01284
01285 return FALSE;
01286 }
01287
01290 #ifdef DBUS_BUILD_TESTS
01291
01292 static void
01293 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
01294 {
01295 while (LIVE_CHILDREN (sitter))
01296 babysitter_iteration (sitter, TRUE);
01297 }
01298
01299 static dbus_bool_t
01300 check_spawn_nonexistent (void *data)
01301 {
01302 char *argv[4] = { NULL, NULL, NULL, NULL };
01303 DBusBabysitter *sitter = NULL;
01304 DBusError error = DBUS_ERROR_INIT;
01305
01306
01307
01308 argv[0] = "/this/does/not/exist/32542sdgafgafdg";
01309 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01310 NULL, NULL, NULL,
01311 &error))
01312 {
01313 _dbus_babysitter_block_for_child_exit (sitter);
01314 _dbus_babysitter_set_child_exit_error (sitter, &error);
01315 }
01316
01317 if (sitter)
01318 _dbus_babysitter_unref (sitter);
01319
01320 if (!dbus_error_is_set (&error))
01321 {
01322 _dbus_warn ("Did not get an error launching nonexistent executable\n");
01323 return FALSE;
01324 }
01325
01326 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01327 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
01328 {
01329 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
01330 error.name, error.message);
01331 dbus_error_free (&error);
01332 return FALSE;
01333 }
01334
01335 dbus_error_free (&error);
01336
01337 return TRUE;
01338 }
01339
01340 static dbus_bool_t
01341 check_spawn_segfault (void *data)
01342 {
01343 char *argv[4] = { NULL, NULL, NULL, NULL };
01344 DBusBabysitter *sitter = NULL;
01345 DBusError error = DBUS_ERROR_INIT;
01346
01347
01348
01349 argv[0] = TEST_SEGFAULT_BINARY;
01350 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01351 NULL, NULL, NULL,
01352 &error))
01353 {
01354 _dbus_babysitter_block_for_child_exit (sitter);
01355 _dbus_babysitter_set_child_exit_error (sitter, &error);
01356 }
01357
01358 if (sitter)
01359 _dbus_babysitter_unref (sitter);
01360
01361 if (!dbus_error_is_set (&error))
01362 {
01363 _dbus_warn ("Did not get an error launching segfaulting binary\n");
01364 return FALSE;
01365 }
01366
01367 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01368 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01369 {
01370 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
01371 error.name, error.message);
01372 dbus_error_free (&error);
01373 return FALSE;
01374 }
01375
01376 dbus_error_free (&error);
01377
01378 return TRUE;
01379 }
01380
01381 static dbus_bool_t
01382 check_spawn_exit (void *data)
01383 {
01384 char *argv[4] = { NULL, NULL, NULL, NULL };
01385 DBusBabysitter *sitter = NULL;
01386 DBusError error = DBUS_ERROR_INIT;
01387
01388
01389
01390 argv[0] = TEST_EXIT_BINARY;
01391 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01392 NULL, NULL, NULL,
01393 &error))
01394 {
01395 _dbus_babysitter_block_for_child_exit (sitter);
01396 _dbus_babysitter_set_child_exit_error (sitter, &error);
01397 }
01398
01399 if (sitter)
01400 _dbus_babysitter_unref (sitter);
01401
01402 if (!dbus_error_is_set (&error))
01403 {
01404 _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
01405 return FALSE;
01406 }
01407
01408 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01409 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
01410 {
01411 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
01412 error.name, error.message);
01413 dbus_error_free (&error);
01414 return FALSE;
01415 }
01416
01417 dbus_error_free (&error);
01418
01419 return TRUE;
01420 }
01421
01422 static dbus_bool_t
01423 check_spawn_and_kill (void *data)
01424 {
01425 char *argv[4] = { NULL, NULL, NULL, NULL };
01426 DBusBabysitter *sitter = NULL;
01427 DBusError error = DBUS_ERROR_INIT;
01428
01429
01430
01431 argv[0] = TEST_SLEEP_FOREVER_BINARY;
01432 if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01433 NULL, NULL, NULL,
01434 &error))
01435 {
01436 _dbus_babysitter_kill_child (sitter);
01437
01438 _dbus_babysitter_block_for_child_exit (sitter);
01439
01440 _dbus_babysitter_set_child_exit_error (sitter, &error);
01441 }
01442
01443 if (sitter)
01444 _dbus_babysitter_unref (sitter);
01445
01446 if (!dbus_error_is_set (&error))
01447 {
01448 _dbus_warn ("Did not get an error after killing spawned binary\n");
01449 return FALSE;
01450 }
01451
01452 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01453 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01454 {
01455 _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
01456 error.name, error.message);
01457 dbus_error_free (&error);
01458 return FALSE;
01459 }
01460
01461 dbus_error_free (&error);
01462
01463 return TRUE;
01464 }
01465
01466 dbus_bool_t
01467 _dbus_spawn_test (const char *test_data_dir)
01468 {
01469 if (!_dbus_test_oom_handling ("spawn_nonexistent",
01470 check_spawn_nonexistent,
01471 NULL))
01472 return FALSE;
01473
01474 if (!_dbus_test_oom_handling ("spawn_segfault",
01475 check_spawn_segfault,
01476 NULL))
01477 return FALSE;
01478
01479 if (!_dbus_test_oom_handling ("spawn_exit",
01480 check_spawn_exit,
01481 NULL))
01482 return FALSE;
01483
01484 if (!_dbus_test_oom_handling ("spawn_and_kill",
01485 check_spawn_and_kill,
01486 NULL))
01487 return FALSE;
01488
01489 return TRUE;
01490 }
01491 #endif