Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

dbus-spawn.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */ 00002 /* dbus-spawn.c Wrapper around fork/exec 00003 * 00004 * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. 00005 * Copyright (C) 2003 CodeFactory AB 00006 * 00007 * Licensed under the Academic Free License version 2.1 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program; if not, write to the Free Software 00021 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 * 00023 */ 00024 #include "dbus-spawn.h" 00025 #include "dbus-sysdeps.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 <errno.h> 00035 #include <stdlib.h> 00036 00042 /* 00043 * I'm pretty sure this whole spawn file could be made simpler, 00044 * if you thought about it a bit. 00045 */ 00046 00050 typedef enum 00051 { 00052 READ_STATUS_OK, 00053 READ_STATUS_ERROR, 00054 READ_STATUS_EOF 00055 } ReadStatus; 00056 00057 static ReadStatus 00058 read_ints (int fd, 00059 int *buf, 00060 int n_ints_in_buf, 00061 int *n_ints_read, 00062 DBusError *error) 00063 { 00064 size_t bytes = 0; 00065 ReadStatus retval; 00066 00067 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00068 00069 retval = READ_STATUS_OK; 00070 00071 while (TRUE) 00072 { 00073 size_t chunk; 00074 size_t to_read; 00075 00076 again: 00077 00078 to_read = sizeof (int) * n_ints_in_buf - bytes; 00079 00080 if (to_read == 0) 00081 break; 00082 00083 chunk = read (fd, 00084 ((char*)buf) + bytes, 00085 to_read); 00086 00087 if (chunk < 0 && errno == EINTR) 00088 goto again; 00089 00090 if (chunk < 0) 00091 { 00092 dbus_set_error (error, 00093 DBUS_ERROR_SPAWN_FAILED, 00094 "Failed to read from child pipe (%s)", 00095 _dbus_strerror (errno)); 00096 00097 retval = READ_STATUS_ERROR; 00098 break; 00099 } 00100 else if (chunk == 0) 00101 { 00102 retval = READ_STATUS_EOF; 00103 break; /* EOF */ 00104 } 00105 else /* chunk > 0 */ 00106 bytes += chunk; 00107 } 00108 00109 *n_ints_read = (int)(bytes / sizeof(int)); 00110 00111 return retval; 00112 } 00113 00114 static ReadStatus 00115 read_pid (int fd, 00116 pid_t *buf, 00117 DBusError *error) 00118 { 00119 size_t bytes = 0; 00120 ReadStatus retval; 00121 00122 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00123 00124 retval = READ_STATUS_OK; 00125 00126 while (TRUE) 00127 { 00128 size_t chunk; 00129 size_t to_read; 00130 00131 again: 00132 to_read = sizeof (pid_t) - bytes; 00133 00134 if (to_read == 0) 00135 break; 00136 00137 chunk = read (fd, 00138 ((char*)buf) + bytes, 00139 to_read); 00140 if (chunk < 0 && errno == EINTR) 00141 goto again; 00142 00143 if (chunk < 0) 00144 { 00145 dbus_set_error (error, 00146 DBUS_ERROR_SPAWN_FAILED, 00147 "Failed to read from child pipe (%s)", 00148 _dbus_strerror (errno)); 00149 00150 retval = READ_STATUS_ERROR; 00151 break; 00152 } 00153 else if (chunk == 0) 00154 { 00155 retval = READ_STATUS_EOF; 00156 break; /* EOF */ 00157 } 00158 else /* chunk > 0 */ 00159 bytes += chunk; 00160 } 00161 00162 return retval; 00163 } 00164 00165 /* The implementation uses an intermediate child between the main process 00166 * and the grandchild. The grandchild is our spawned process. The intermediate 00167 * child is a babysitter process; it keeps track of when the grandchild 00168 * exits/crashes, and reaps the grandchild. 00169 */ 00170 00171 /* Messages from children to parents */ 00172 enum 00173 { 00174 CHILD_EXITED, /* This message is followed by the exit status int */ 00175 CHILD_FORK_FAILED, /* Followed by errno */ 00176 CHILD_EXEC_FAILED, /* Followed by errno */ 00177 CHILD_PID /* Followed by pid_t */ 00178 }; 00179 00183 struct DBusBabysitter 00184 { 00185 int refcount; 00187 char *executable; 00189 int socket_to_babysitter; 00190 int error_pipe_from_child; 00192 pid_t sitter_pid; 00193 pid_t grandchild_pid; 00195 DBusWatchList *watches; 00197 DBusWatch *error_watch; 00198 DBusWatch *sitter_watch; 00200 int errnum; 00201 int status; 00202 unsigned int have_child_status : 1; 00203 unsigned int have_fork_errnum : 1; 00204 unsigned int have_exec_errnum : 1; 00205 }; 00206 00207 static DBusBabysitter* 00208 _dbus_babysitter_new (void) 00209 { 00210 DBusBabysitter *sitter; 00211 00212 sitter = dbus_new0 (DBusBabysitter, 1); 00213 if (sitter == NULL) 00214 return NULL; 00215 00216 sitter->refcount = 1; 00217 00218 sitter->socket_to_babysitter = -1; 00219 sitter->error_pipe_from_child = -1; 00220 00221 sitter->sitter_pid = -1; 00222 sitter->grandchild_pid = -1; 00223 00224 sitter->watches = _dbus_watch_list_new (); 00225 if (sitter->watches == NULL) 00226 goto failed; 00227 00228 return sitter; 00229 00230 failed: 00231 _dbus_babysitter_unref (sitter); 00232 return NULL; 00233 } 00234 00241 DBusBabysitter * 00242 _dbus_babysitter_ref (DBusBabysitter *sitter) 00243 { 00244 _dbus_assert (sitter != NULL); 00245 _dbus_assert (sitter->refcount > 0); 00246 00247 sitter->refcount += 1; 00248 00249 return sitter; 00250 } 00251 00257 void 00258 _dbus_babysitter_unref (DBusBabysitter *sitter) 00259 { 00260 _dbus_assert (sitter != NULL); 00261 _dbus_assert (sitter->refcount > 0); 00262 00263 sitter->refcount -= 1; 00264 if (sitter->refcount == 0) 00265 { 00266 if (sitter->socket_to_babysitter >= 0) 00267 { 00268 close (sitter->socket_to_babysitter); 00269 sitter->socket_to_babysitter = -1; 00270 } 00271 00272 if (sitter->error_pipe_from_child >= 0) 00273 { 00274 close (sitter->error_pipe_from_child); 00275 sitter->error_pipe_from_child = -1; 00276 } 00277 00278 if (sitter->sitter_pid != -1) 00279 { 00280 int status; 00281 int ret; 00282 00283 /* Reap the babysitter */ 00284 again: 00285 ret = waitpid (sitter->sitter_pid, &status, 0); 00286 if (ret < 0) 00287 { 00288 if (errno == EINTR) 00289 goto again; 00290 else if (errno == ECHILD) 00291 _dbus_warn ("Babysitter process not available to be reaped; should not happen\n"); 00292 else 00293 _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s\n", 00294 errno, _dbus_strerror (errno)); 00295 } 00296 else 00297 { 00298 _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n", 00299 (long) ret, (long) sitter->sitter_pid); 00300 00301 if (WIFEXITED (sitter->status)) 00302 _dbus_verbose ("Babysitter exited with status %d\n", 00303 WEXITSTATUS (sitter->status)); 00304 else if (WIFSIGNALED (sitter->status)) 00305 _dbus_verbose ("Babysitter received signal %d\n", 00306 WTERMSIG (sitter->status)); 00307 else 00308 _dbus_verbose ("Babysitter exited abnormally\n"); 00309 } 00310 00311 sitter->sitter_pid = -1; 00312 } 00313 00314 if (sitter->error_watch) 00315 { 00316 _dbus_watch_invalidate (sitter->error_watch); 00317 _dbus_watch_unref (sitter->error_watch); 00318 sitter->error_watch = NULL; 00319 } 00320 00321 if (sitter->sitter_watch) 00322 { 00323 _dbus_watch_invalidate (sitter->sitter_watch); 00324 _dbus_watch_unref (sitter->sitter_watch); 00325 sitter->sitter_watch = NULL; 00326 } 00327 00328 if (sitter->watches) 00329 _dbus_watch_list_free (sitter->watches); 00330 00331 dbus_free (sitter->executable); 00332 00333 dbus_free (sitter); 00334 } 00335 } 00336 00337 static ReadStatus 00338 read_data (DBusBabysitter *sitter, 00339 int fd) 00340 { 00341 int what; 00342 int got; 00343 DBusError error; 00344 ReadStatus r; 00345 00346 dbus_error_init (&error); 00347 00348 r = read_ints (fd, &what, 1, &got, &error); 00349 00350 switch (r) 00351 { 00352 case READ_STATUS_ERROR: 00353 _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message); 00354 dbus_error_free (&error); 00355 return r; 00356 00357 case READ_STATUS_EOF: 00358 return r; 00359 00360 case READ_STATUS_OK: 00361 break; 00362 } 00363 00364 if (got == 1) 00365 { 00366 switch (what) 00367 { 00368 case CHILD_EXITED: 00369 case CHILD_FORK_FAILED: 00370 case CHILD_EXEC_FAILED: 00371 { 00372 int arg; 00373 00374 r = read_ints (fd, &arg, 1, &got, &error); 00375 00376 switch (r) 00377 { 00378 case READ_STATUS_ERROR: 00379 _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message); 00380 dbus_error_free (&error); 00381 return r; 00382 case READ_STATUS_EOF: 00383 return r; 00384 case READ_STATUS_OK: 00385 break; 00386 } 00387 00388 if (got == 1) 00389 { 00390 if (what == CHILD_EXITED) 00391 { 00392 sitter->have_child_status = TRUE; 00393 sitter->status = arg; 00394 _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n", 00395 WIFEXITED (sitter->status), WIFSIGNALED (sitter->status), 00396 WEXITSTATUS (sitter->status), WTERMSIG (sitter->status)); 00397 } 00398 else if (what == CHILD_FORK_FAILED) 00399 { 00400 sitter->have_fork_errnum = TRUE; 00401 sitter->errnum = arg; 00402 _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum); 00403 } 00404 else if (what == CHILD_EXEC_FAILED) 00405 { 00406 sitter->have_exec_errnum = TRUE; 00407 sitter->errnum = arg; 00408 _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum); 00409 } 00410 } 00411 } 00412 break; 00413 case CHILD_PID: 00414 { 00415 pid_t pid = -1; 00416 00417 r = read_pid (fd, &pid, &error); 00418 00419 switch (r) 00420 { 00421 case READ_STATUS_ERROR: 00422 _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message); 00423 dbus_error_free (&error); 00424 return r; 00425 case READ_STATUS_EOF: 00426 return r; 00427 case READ_STATUS_OK: 00428 break; 00429 } 00430 00431 sitter->grandchild_pid = pid; 00432 00433 _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid); 00434 } 00435 break; 00436 default: 00437 _dbus_warn ("Unknown message received from babysitter process\n"); 00438 break; 00439 } 00440 } 00441 00442 return r; 00443 } 00444 00445 static void 00446 close_socket_to_babysitter (DBusBabysitter *sitter) 00447 { 00448 _dbus_verbose ("Closing babysitter\n"); 00449 close (sitter->socket_to_babysitter); 00450 sitter->socket_to_babysitter = -1; 00451 } 00452 00453 static void 00454 close_error_pipe_from_child (DBusBabysitter *sitter) 00455 { 00456 _dbus_verbose ("Closing child error\n"); 00457 close (sitter->error_pipe_from_child); 00458 sitter->error_pipe_from_child = -1; 00459 } 00460 00461 static void 00462 handle_babysitter_socket (DBusBabysitter *sitter, 00463 int revents) 00464 { 00465 /* Even if we have POLLHUP, we want to keep reading 00466 * data until POLLIN goes away; so this function only 00467 * looks at HUP/ERR if no IN is set. 00468 */ 00469 if (revents & _DBUS_POLLIN) 00470 { 00471 _dbus_verbose ("Reading data from babysitter\n"); 00472 if (read_data (sitter, sitter->socket_to_babysitter) != READ_STATUS_OK) 00473 close_socket_to_babysitter (sitter); 00474 } 00475 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP)) 00476 { 00477 close_socket_to_babysitter (sitter); 00478 } 00479 } 00480 00481 static void 00482 handle_error_pipe (DBusBabysitter *sitter, 00483 int revents) 00484 { 00485 if (revents & _DBUS_POLLIN) 00486 { 00487 _dbus_verbose ("Reading data from child error\n"); 00488 if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK) 00489 close_error_pipe_from_child (sitter); 00490 } 00491 else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP)) 00492 { 00493 close_error_pipe_from_child (sitter); 00494 } 00495 } 00496 00497 /* returns whether there were any poll events handled */ 00498 static dbus_bool_t 00499 babysitter_iteration (DBusBabysitter *sitter, 00500 dbus_bool_t block) 00501 { 00502 DBusPollFD fds[2]; 00503 int i; 00504 dbus_bool_t descriptors_ready; 00505 00506 descriptors_ready = FALSE; 00507 00508 i = 0; 00509 00510 if (sitter->error_pipe_from_child >= 0) 00511 { 00512 fds[i].fd = sitter->error_pipe_from_child; 00513 fds[i].events = _DBUS_POLLIN; 00514 fds[i].revents = 0; 00515 ++i; 00516 } 00517 00518 if (sitter->socket_to_babysitter >= 0) 00519 { 00520 fds[i].fd = sitter->socket_to_babysitter; 00521 fds[i].events = _DBUS_POLLIN; 00522 fds[i].revents = 0; 00523 ++i; 00524 } 00525 00526 if (i > 0) 00527 { 00528 int ret; 00529 00530 ret = _dbus_poll (fds, i, 0); 00531 if (ret == 0 && block) 00532 ret = _dbus_poll (fds, i, -1); 00533 00534 if (ret > 0) 00535 { 00536 descriptors_ready = TRUE; 00537 00538 while (i > 0) 00539 { 00540 --i; 00541 if (fds[i].fd == sitter->error_pipe_from_child) 00542 handle_error_pipe (sitter, fds[i].revents); 00543 else if (fds[i].fd == sitter->socket_to_babysitter) 00544 handle_babysitter_socket (sitter, fds[i].revents); 00545 } 00546 } 00547 } 00548 00549 return descriptors_ready; 00550 } 00551 00556 #define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter >= 0 || (sitter)->error_pipe_from_child >= 0) 00557 00564 void 00565 _dbus_babysitter_kill_child (DBusBabysitter *sitter) 00566 { 00567 /* be sure we have the PID of the child */ 00568 while (LIVE_CHILDREN (sitter) && 00569 sitter->grandchild_pid == -1) 00570 babysitter_iteration (sitter, TRUE); 00571 00572 _dbus_verbose ("Got child PID %ld for killing\n", 00573 (long) sitter->grandchild_pid); 00574 00575 if (sitter->grandchild_pid == -1) 00576 return; /* child is already dead, or we're so hosed we'll never recover */ 00577 00578 kill (sitter->grandchild_pid, SIGKILL); 00579 } 00580 00586 dbus_bool_t 00587 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter) 00588 { 00589 00590 /* Be sure we're up-to-date */ 00591 while (LIVE_CHILDREN (sitter) && 00592 babysitter_iteration (sitter, FALSE)) 00593 ; 00594 00595 /* We will have exited the babysitter when the child has exited */ 00596 return sitter->socket_to_babysitter < 0; 00597 } 00598 00608 void 00609 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, 00610 DBusError *error) 00611 { 00612 if (!_dbus_babysitter_get_child_exited (sitter)) 00613 return; 00614 00615 /* Note that if exec fails, we will also get a child status 00616 * from the babysitter saying the child exited, 00617 * so we need to give priority to the exec error 00618 */ 00619 if (sitter->have_exec_errnum) 00620 { 00621 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, 00622 "Failed to execute program %s: %s", 00623 sitter->executable, _dbus_strerror (sitter->errnum)); 00624 } 00625 else if (sitter->have_fork_errnum) 00626 { 00627 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, 00628 "Failed to fork a new process %s: %s", 00629 sitter->executable, _dbus_strerror (sitter->errnum)); 00630 } 00631 else if (sitter->have_child_status) 00632 { 00633 if (WIFEXITED (sitter->status)) 00634 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, 00635 "Process %s exited with status %d", 00636 sitter->executable, WEXITSTATUS (sitter->status)); 00637 else if (WIFSIGNALED (sitter->status)) 00638 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED, 00639 "Process %s received signal %d", 00640 sitter->executable, WTERMSIG (sitter->status)); 00641 else 00642 dbus_set_error (error, DBUS_ERROR_FAILED, 00643 "Process %s exited abnormally", 00644 sitter->executable); 00645 } 00646 else 00647 { 00648 dbus_set_error (error, DBUS_ERROR_FAILED, 00649 "Process %s exited, reason unknown", 00650 sitter->executable); 00651 } 00652 } 00653 00666 dbus_bool_t 00667 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter, 00668 DBusAddWatchFunction add_function, 00669 DBusRemoveWatchFunction remove_function, 00670 DBusWatchToggledFunction toggled_function, 00671 void *data, 00672 DBusFreeFunction free_data_function) 00673 { 00674 return _dbus_watch_list_set_functions (sitter->watches, 00675 add_function, 00676 remove_function, 00677 toggled_function, 00678 data, 00679 free_data_function); 00680 } 00681 00682 static dbus_bool_t 00683 handle_watch (DBusWatch *watch, 00684 unsigned int condition, 00685 void *data) 00686 { 00687 DBusBabysitter *sitter = data; 00688 int revents; 00689 int fd; 00690 00691 revents = 0; 00692 if (condition & DBUS_WATCH_READABLE) 00693 revents |= _DBUS_POLLIN; 00694 if (condition & DBUS_WATCH_ERROR) 00695 revents |= _DBUS_POLLERR; 00696 if (condition & DBUS_WATCH_HANGUP) 00697 revents |= _DBUS_POLLHUP; 00698 00699 fd = dbus_watch_get_fd (watch); 00700 00701 if (fd == sitter->error_pipe_from_child) 00702 handle_error_pipe (sitter, revents); 00703 else if (fd == sitter->socket_to_babysitter) 00704 handle_babysitter_socket (sitter, revents); 00705 00706 while (LIVE_CHILDREN (sitter) && 00707 babysitter_iteration (sitter, FALSE)) 00708 ; 00709 00710 return TRUE; 00711 } 00712 00714 #define READ_END 0 00715 00716 #define WRITE_END 1 00717 00718 00719 /* Avoids a danger in threaded situations (calling close() 00720 * on a file descriptor twice, and another thread has 00721 * re-opened it since the first close) 00722 */ 00723 static int 00724 close_and_invalidate (int *fd) 00725 { 00726 int ret; 00727 00728 if (*fd < 0) 00729 return -1; 00730 else 00731 { 00732 ret = close (*fd); 00733 *fd = -1; 00734 } 00735 00736 return ret; 00737 } 00738 00739 static dbus_bool_t 00740 make_pipe (int p[2], 00741 DBusError *error) 00742 { 00743 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00744 00745 if (pipe (p) < 0) 00746 { 00747 dbus_set_error (error, 00748 DBUS_ERROR_SPAWN_FAILED, 00749 "Failed to create pipe for communicating with child process (%s)", 00750 _dbus_strerror (errno)); 00751 return FALSE; 00752 } 00753 00754 return TRUE; 00755 } 00756 00757 static void 00758 do_write (int fd, const void *buf, size_t count) 00759 { 00760 size_t bytes_written; 00761 int ret; 00762 00763 bytes_written = 0; 00764 00765 again: 00766 00767 ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written); 00768 00769 if (ret < 0) 00770 { 00771 if (errno == EINTR) 00772 goto again; 00773 else 00774 { 00775 _dbus_warn ("Failed to write data to pipe!\n"); 00776 exit (1); /* give up, we suck */ 00777 } 00778 } 00779 else 00780 bytes_written += ret; 00781 00782 if (bytes_written < count) 00783 goto again; 00784 } 00785 00786 static void 00787 write_err_and_exit (int fd, int msg) 00788 { 00789 int en = errno; 00790 00791 do_write (fd, &msg, sizeof (msg)); 00792 do_write (fd, &en, sizeof (en)); 00793 00794 exit (1); 00795 } 00796 00797 static void 00798 write_pid (int fd, pid_t pid) 00799 { 00800 int msg = CHILD_PID; 00801 00802 do_write (fd, &msg, sizeof (msg)); 00803 do_write (fd, &pid, sizeof (pid)); 00804 } 00805 00806 static void 00807 write_status_and_exit (int fd, int status) 00808 { 00809 int msg = CHILD_EXITED; 00810 00811 do_write (fd, &msg, sizeof (msg)); 00812 do_write (fd, &status, sizeof (status)); 00813 00814 exit (0); 00815 } 00816 00817 static void 00818 do_exec (int child_err_report_fd, 00819 char **argv, 00820 DBusSpawnChildSetupFunc child_setup, 00821 void *user_data) 00822 { 00823 #ifdef DBUS_BUILD_TESTS 00824 int i, max_open; 00825 #endif 00826 00827 _dbus_verbose_reset (); 00828 _dbus_verbose ("Child process has PID %lu\n", 00829 _dbus_getpid ()); 00830 00831 if (child_setup) 00832 (* child_setup) (user_data); 00833 00834 #ifdef DBUS_BUILD_TESTS 00835 max_open = sysconf (_SC_OPEN_MAX); 00836 00837 for (i = 3; i < max_open; i++) 00838 { 00839 int retval; 00840 00841 if (i == child_err_report_fd) 00842 continue; 00843 00844 retval = fcntl (i, F_GETFD); 00845 00846 if (retval != -1 && !(retval & FD_CLOEXEC)) 00847 _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i); 00848 } 00849 #endif 00850 00851 execv (argv[0], argv); 00852 00853 /* Exec failed */ 00854 write_err_and_exit (child_err_report_fd, 00855 CHILD_EXEC_FAILED); 00856 } 00857 00858 static void 00859 check_babysit_events (pid_t grandchild_pid, 00860 int parent_pipe, 00861 int revents) 00862 { 00863 pid_t ret; 00864 int status; 00865 00866 ret = waitpid (grandchild_pid, &status, WNOHANG); 00867 00868 if (ret == 0) 00869 { 00870 _dbus_verbose ("no child exited\n"); 00871 00872 ; /* no child exited */ 00873 } 00874 else if (ret < 0) 00875 { 00876 /* This isn't supposed to happen. */ 00877 _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n", 00878 _dbus_strerror (errno)); 00879 exit (1); 00880 } 00881 else if (ret == grandchild_pid) 00882 { 00883 /* Child exited */ 00884 _dbus_verbose ("reaped child pid %ld\n", (long) ret); 00885 00886 write_status_and_exit (parent_pipe, status); 00887 } 00888 else 00889 { 00890 _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n", 00891 (int) ret); 00892 exit (1); 00893 } 00894 00895 if (revents & _DBUS_POLLIN) 00896 { 00897 _dbus_verbose ("babysitter got POLLIN from parent pipe\n"); 00898 } 00899 00900 if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP)) 00901 { 00902 /* Parent is gone, so we just exit */ 00903 _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n"); 00904 exit (0); 00905 } 00906 } 00907 00908 static int babysit_sigchld_pipe = -1; 00909 00910 static void 00911 babysit_signal_handler (int signo) 00912 { 00913 char b = '\0'; 00914 again: 00915 write (babysit_sigchld_pipe, &b, 1); 00916 if (errno == EINTR) 00917 goto again; 00918 } 00919 00920 static void 00921 babysit (pid_t grandchild_pid, 00922 int parent_pipe) 00923 { 00924 int sigchld_pipe[2]; 00925 00926 /* We don't exec, so we keep parent state, such as the pid that 00927 * _dbus_verbose() uses. Reset the pid here. 00928 */ 00929 _dbus_verbose_reset (); 00930 00931 /* I thought SIGCHLD would just wake up the poll, but 00932 * that didn't seem to work, so added this pipe. 00933 * Probably the pipe is more likely to work on busted 00934 * operating systems anyhow. 00935 */ 00936 if (pipe (sigchld_pipe) < 0) 00937 { 00938 _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n"); 00939 exit (1); 00940 } 00941 00942 babysit_sigchld_pipe = sigchld_pipe[WRITE_END]; 00943 00944 _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler); 00945 00946 write_pid (parent_pipe, grandchild_pid); 00947 00948 check_babysit_events (grandchild_pid, parent_pipe, 0); 00949 00950 while (TRUE) 00951 { 00952 DBusPollFD pfds[2]; 00953 00954 pfds[0].fd = parent_pipe; 00955 pfds[0].events = _DBUS_POLLIN; 00956 pfds[0].revents = 0; 00957 00958 pfds[1].fd = sigchld_pipe[READ_END]; 00959 pfds[1].events = _DBUS_POLLIN; 00960 pfds[1].revents = 0; 00961 00962 _dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1); 00963 00964 if (pfds[0].revents != 0) 00965 { 00966 check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents); 00967 } 00968 else if (pfds[1].revents & _DBUS_POLLIN) 00969 { 00970 char b; 00971 read (sigchld_pipe[READ_END], &b, 1); 00972 /* do waitpid check */ 00973 check_babysit_events (grandchild_pid, parent_pipe, 0); 00974 } 00975 } 00976 00977 exit (1); 00978 } 00979 00998 dbus_bool_t 00999 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, 01000 char **argv, 01001 DBusSpawnChildSetupFunc child_setup, 01002 void *user_data, 01003 DBusError *error) 01004 { 01005 DBusBabysitter *sitter; 01006 int child_err_report_pipe[2] = { -1, -1 }; 01007 int babysitter_pipe[2] = { -1, -1 }; 01008 pid_t pid; 01009 01010 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 01011 01012 *sitter_p = NULL; 01013 sitter = NULL; 01014 01015 sitter = _dbus_babysitter_new (); 01016 if (sitter == NULL) 01017 { 01018 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 01019 return FALSE; 01020 } 01021 01022 sitter->executable = _dbus_strdup (argv[0]); 01023 if (sitter->executable == NULL) 01024 { 01025 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 01026 goto cleanup_and_fail; 01027 } 01028 01029 if (!make_pipe (child_err_report_pipe, error)) 01030 goto cleanup_and_fail; 01031 01032 _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]); 01033 01034 if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error)) 01035 goto cleanup_and_fail; 01036 01037 _dbus_fd_set_close_on_exec (babysitter_pipe[0]); 01038 _dbus_fd_set_close_on_exec (babysitter_pipe[1]); 01039 01040 /* Setting up the babysitter is only useful in the parent, 01041 * but we don't want to run out of memory and fail 01042 * after we've already forked, since then we'd leak 01043 * child processes everywhere. 01044 */ 01045 sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END], 01046 DBUS_WATCH_READABLE, 01047 TRUE, handle_watch, sitter, NULL); 01048 if (sitter->error_watch == NULL) 01049 { 01050 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 01051 goto cleanup_and_fail; 01052 } 01053 01054 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch)) 01055 { 01056 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 01057 goto cleanup_and_fail; 01058 } 01059 01060 sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0], 01061 DBUS_WATCH_READABLE, 01062 TRUE, handle_watch, sitter, NULL); 01063 if (sitter->sitter_watch == NULL) 01064 { 01065 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 01066 goto cleanup_and_fail; 01067 } 01068 01069 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) 01070 { 01071 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 01072 goto cleanup_and_fail; 01073 } 01074 01075 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 01076 01077 pid = fork (); 01078 01079 if (pid < 0) 01080 { 01081 dbus_set_error (error, 01082 DBUS_ERROR_SPAWN_FORK_FAILED, 01083 "Failed to fork (%s)", 01084 _dbus_strerror (errno)); 01085 goto cleanup_and_fail; 01086 } 01087 else if (pid == 0) 01088 { 01089 /* Immediate child, this is the babysitter process. */ 01090 int grandchild_pid; 01091 01092 /* Be sure we crash if the parent exits 01093 * and we write to the err_report_pipe 01094 */ 01095 signal (SIGPIPE, SIG_DFL); 01096 01097 /* Close the parent's end of the pipes. */ 01098 close_and_invalidate (&child_err_report_pipe[READ_END]); 01099 close_and_invalidate (&babysitter_pipe[0]); 01100 01101 /* Create the child that will exec () */ 01102 grandchild_pid = fork (); 01103 01104 if (grandchild_pid < 0) 01105 { 01106 write_err_and_exit (babysitter_pipe[1], 01107 CHILD_FORK_FAILED); 01108 _dbus_assert_not_reached ("Got to code after write_err_and_exit()"); 01109 } 01110 else if (grandchild_pid == 0) 01111 { 01112 do_exec (child_err_report_pipe[WRITE_END], 01113 argv, 01114 child_setup, user_data); 01115 _dbus_assert_not_reached ("Got to code after exec() - should have exited on error"); 01116 } 01117 else 01118 { 01119 babysit (grandchild_pid, babysitter_pipe[1]); 01120 _dbus_assert_not_reached ("Got to code after babysit()"); 01121 } 01122 } 01123 else 01124 { 01125 /* Close the uncared-about ends of the pipes */ 01126 close_and_invalidate (&child_err_report_pipe[WRITE_END]); 01127 close_and_invalidate (&babysitter_pipe[1]); 01128 01129 sitter->socket_to_babysitter = babysitter_pipe[0]; 01130 babysitter_pipe[0] = -1; 01131 01132 sitter->error_pipe_from_child = child_err_report_pipe[READ_END]; 01133 child_err_report_pipe[READ_END] = -1; 01134 01135 sitter->sitter_pid = pid; 01136 01137 if (sitter_p != NULL) 01138 *sitter_p = sitter; 01139 else 01140 _dbus_babysitter_unref (sitter); 01141 01142 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 01143 01144 return TRUE; 01145 } 01146 01147 cleanup_and_fail: 01148 01149 _DBUS_ASSERT_ERROR_IS_SET (error); 01150 01151 close_and_invalidate (&child_err_report_pipe[READ_END]); 01152 close_and_invalidate (&child_err_report_pipe[WRITE_END]); 01153 close_and_invalidate (&babysitter_pipe[0]); 01154 close_and_invalidate (&babysitter_pipe[1]); 01155 01156 if (sitter != NULL) 01157 _dbus_babysitter_unref (sitter); 01158 01159 return FALSE; 01160 } 01161 01164 #ifdef DBUS_BUILD_TESTS 01165 01166 static void 01167 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter) 01168 { 01169 while (LIVE_CHILDREN (sitter)) 01170 babysitter_iteration (sitter, TRUE); 01171 } 01172 01173 static dbus_bool_t 01174 check_spawn_nonexistent (void *data) 01175 { 01176 char *argv[4] = { NULL, NULL, NULL, NULL }; 01177 DBusBabysitter *sitter; 01178 DBusError error; 01179 01180 sitter = NULL; 01181 01182 dbus_error_init (&error); 01183 01184 /*** Test launching nonexistent binary */ 01185 01186 argv[0] = "/this/does/not/exist/32542sdgafgafdg"; 01187 if (_dbus_spawn_async_with_babysitter (&sitter, argv, 01188 NULL, NULL, 01189 &error)) 01190 { 01191 _dbus_babysitter_block_for_child_exit (sitter); 01192 _dbus_babysitter_set_child_exit_error (sitter, &error); 01193 } 01194 01195 if (sitter) 01196 _dbus_babysitter_unref (sitter); 01197 01198 if (!dbus_error_is_set (&error)) 01199 { 01200 _dbus_warn ("Did not get an error launching nonexistent executable\n"); 01201 return FALSE; 01202 } 01203 01204 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 01205 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED))) 01206 { 01207 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n", 01208 error.name, error.message); 01209 dbus_error_free (&error); 01210 return FALSE; 01211 } 01212 01213 dbus_error_free (&error); 01214 01215 return TRUE; 01216 } 01217 01218 static dbus_bool_t 01219 check_spawn_segfault (void *data) 01220 { 01221 char *argv[4] = { NULL, NULL, NULL, NULL }; 01222 DBusBabysitter *sitter; 01223 DBusError error; 01224 01225 sitter = NULL; 01226 01227 dbus_error_init (&error); 01228 01229 /*** Test launching segfault binary */ 01230 01231 argv[0] = TEST_SEGFAULT_BINARY; 01232 if (_dbus_spawn_async_with_babysitter (&sitter, argv, 01233 NULL, NULL, 01234 &error)) 01235 { 01236 _dbus_babysitter_block_for_child_exit (sitter); 01237 _dbus_babysitter_set_child_exit_error (sitter, &error); 01238 } 01239 01240 if (sitter) 01241 _dbus_babysitter_unref (sitter); 01242 01243 if (!dbus_error_is_set (&error)) 01244 { 01245 _dbus_warn ("Did not get an error launching segfaulting binary\n"); 01246 return FALSE; 01247 } 01248 01249 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 01250 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED))) 01251 { 01252 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n", 01253 error.name, error.message); 01254 dbus_error_free (&error); 01255 return FALSE; 01256 } 01257 01258 dbus_error_free (&error); 01259 01260 return TRUE; 01261 } 01262 01263 static dbus_bool_t 01264 check_spawn_exit (void *data) 01265 { 01266 char *argv[4] = { NULL, NULL, NULL, NULL }; 01267 DBusBabysitter *sitter; 01268 DBusError error; 01269 01270 sitter = NULL; 01271 01272 dbus_error_init (&error); 01273 01274 /*** Test launching exit failure binary */ 01275 01276 argv[0] = TEST_EXIT_BINARY; 01277 if (_dbus_spawn_async_with_babysitter (&sitter, argv, 01278 NULL, NULL, 01279 &error)) 01280 { 01281 _dbus_babysitter_block_for_child_exit (sitter); 01282 _dbus_babysitter_set_child_exit_error (sitter, &error); 01283 } 01284 01285 if (sitter) 01286 _dbus_babysitter_unref (sitter); 01287 01288 if (!dbus_error_is_set (&error)) 01289 { 01290 _dbus_warn ("Did not get an error launching binary that exited with failure code\n"); 01291 return FALSE; 01292 } 01293 01294 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 01295 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 01296 { 01297 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n", 01298 error.name, error.message); 01299 dbus_error_free (&error); 01300 return FALSE; 01301 } 01302 01303 dbus_error_free (&error); 01304 01305 return TRUE; 01306 } 01307 01308 static dbus_bool_t 01309 check_spawn_and_kill (void *data) 01310 { 01311 char *argv[4] = { NULL, NULL, NULL, NULL }; 01312 DBusBabysitter *sitter; 01313 DBusError error; 01314 01315 sitter = NULL; 01316 01317 dbus_error_init (&error); 01318 01319 /*** Test launching sleeping binary then killing it */ 01320 01321 argv[0] = TEST_SLEEP_FOREVER_BINARY; 01322 if (_dbus_spawn_async_with_babysitter (&sitter, argv, 01323 NULL, NULL, 01324 &error)) 01325 { 01326 _dbus_babysitter_kill_child (sitter); 01327 01328 _dbus_babysitter_block_for_child_exit (sitter); 01329 01330 _dbus_babysitter_set_child_exit_error (sitter, &error); 01331 } 01332 01333 if (sitter) 01334 _dbus_babysitter_unref (sitter); 01335 01336 if (!dbus_error_is_set (&error)) 01337 { 01338 _dbus_warn ("Did not get an error after killing spawned binary\n"); 01339 return FALSE; 01340 } 01341 01342 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 01343 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED))) 01344 { 01345 _dbus_warn ("Not expecting error when killing executable: %s: %s\n", 01346 error.name, error.message); 01347 dbus_error_free (&error); 01348 return FALSE; 01349 } 01350 01351 dbus_error_free (&error); 01352 01353 return TRUE; 01354 } 01355 01356 dbus_bool_t 01357 _dbus_spawn_test (const char *test_data_dir) 01358 { 01359 if (!_dbus_test_oom_handling ("spawn_nonexistent", 01360 check_spawn_nonexistent, 01361 NULL)) 01362 return FALSE; 01363 01364 if (!_dbus_test_oom_handling ("spawn_segfault", 01365 check_spawn_segfault, 01366 NULL)) 01367 return FALSE; 01368 01369 if (!_dbus_test_oom_handling ("spawn_exit", 01370 check_spawn_exit, 01371 NULL)) 01372 return FALSE; 01373 01374 if (!_dbus_test_oom_handling ("spawn_and_kill", 01375 check_spawn_and_kill, 01376 NULL)) 01377 return FALSE; 01378 01379 return TRUE; 01380 } 01381 #endif

Generated on Mon Jun 27 07:48:22 2005 for D-BUS by doxygen 1.3.7