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.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
00044
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;
00104 }
00105
else
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;
00157 }
00158
else
00159 bytes += chunk;
00160 }
00161
00162
return retval;
00163 }
00164
00165
00166
00167
00168
00169
00170
00171
00172
enum
00173 {
00174 CHILD_EXITED,
00175 CHILD_FORK_FAILED,
00176 CHILD_EXEC_FAILED,
00177 CHILD_PID
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
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
00466
00467
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
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
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;
00577
00578 kill (sitter->
grandchild_pid, SIGKILL);
00579 }
00580
00586
dbus_bool_t
00587 _dbus_babysitter_get_child_exited (
DBusBabysitter *sitter)
00588 {
00589
00590
00591
while (
LIVE_CHILDREN (sitter) &&
00592 babysitter_iteration (sitter,
FALSE))
00593 ;
00594
00595
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
00616
00617
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
00720
00721
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);
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
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 ;
00873 }
00874
else if (ret < 0)
00875 {
00876
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
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
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
00927
00928
00929 _dbus_verbose_reset ();
00930
00931
00932
00933
00934
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
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
01041
01042
01043
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
01090
int grandchild_pid;
01091
01092
01093
01094
01095 signal (SIGPIPE, SIG_DFL);
01096
01097
01098 close_and_invalidate (&child_err_report_pipe[
READ_END]);
01099 close_and_invalidate (&babysitter_pipe[0]);
01100
01101
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
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
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
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
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
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