Coverage report for dbus/dbus-spawn.c.gcov
-: 0:Source:dbus-spawn.c
-: 0:Graph:.libs/dbus-spawn.gcno
-: 0:Data:.libs/dbus-spawn.gcda
-: 0:Runs:10868
-: 0:Programs:3
-: 1:/* -*- mode: C; c-file-style: "gnu" -*- */
-: 2:/* dbus-spawn.c Wrapper around fork/exec
-: 3: *
-: 4: * Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
-: 5: * Copyright (C) 2003 CodeFactory AB
-: 6: *
-: 7: * Licensed under the Academic Free License version 2.1
-: 8: *
-: 9: * This program is free software; you can redistribute it and/or modify
-: 10: * it under the terms of the GNU General Public License as published by
-: 11: * the Free Software Foundation; either version 2 of the License, or
-: 12: * (at your option) any later version.
-: 13: *
-: 14: * This program is distributed in the hope that it will be useful,
-: 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of
-: 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-: 17: * GNU General Public License for more details.
-: 18: *
-: 19: * You should have received a copy of the GNU General Public License
-: 20: * along with this program; if not, write to the Free Software
-: 21: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-: 22: *
-: 23: */
-: 24:#include "dbus-spawn.h"
-: 25:#include "dbus-sysdeps.h"
-: 26:#include "dbus-internals.h"
-: 27:#include "dbus-test.h"
-: 28:#include "dbus-protocol.h"
-: 29:
-: 30:#include <unistd.h>
-: 31:#include <fcntl.h>
-: 32:#include <signal.h>
-: 33:#include <sys/wait.h>
-: 34:#include <errno.h>
-: 35:#include <stdlib.h>
-: 36:
-: 37:/**
-: 38: * @addtogroup DBusInternalsUtils
-: 39: * @{
-: 40: */
-: 41:
-: 42:/*
-: 43: * I'm pretty sure this whole spawn file could be made simpler,
-: 44: * if you thought about it a bit.
-: 45: */
-: 46:
-: 47:/**
-: 48: * Enumeration for status of a read()
-: 49: */
-: 50:typedef enum
-: 51:{
-: 52: READ_STATUS_OK, /**< Read succeeded */
-: 53: READ_STATUS_ERROR, /**< Some kind of error */
-: 54: READ_STATUS_EOF /**< EOF returned */
-: 55:} ReadStatus;
-: 56:
-: 57:static ReadStatus
-: 58:read_ints (int fd,
-: 59: int *buf,
-: 60: int n_ints_in_buf,
-: 61: int *n_ints_read,
-: 62: DBusError *error)
function read_ints called 7775 returned 100% blocks executed 93%
7775: 63:{
7775: 64: size_t bytes = 0;
-: 65: ReadStatus retval;
-: 66:
7775: 67: _DBUS_ASSERT_ERROR_IS_CLEAR (error);
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
call 2 returned 100%
branch 3 taken 100% (fallthrough)
branch 4 taken 0%
call 5 returned 100%
-: 68:
7775: 69: retval = READ_STATUS_OK;
-: 70:
-: 71: while (TRUE)
-: 72: {
-: 73: size_t chunk;
-: 74: size_t to_read;
-: 75:
14025: 76: to_read = sizeof (int) * n_ints_in_buf - bytes;
-: 77:
14025: 78: if (to_read == 0)
branch 0 taken 55% (fallthrough)
branch 1 taken 45%
6250: 79: break;
-: 80:
7775: 81: again:
-: 82:
7775: 83: chunk = read (fd,
call 0 returned 100%
-: 84: ((char*)buf) + bytes,
-: 85: to_read);
-: 86:
-: 87: if (chunk < 0 && errno == EINTR)
-: 88: goto again;
-: 89:
-: 90: if (chunk < 0)
-: 91: {
-: 92: dbus_set_error (error,
-: 93: DBUS_ERROR_SPAWN_FAILED,
-: 94: "Failed to read from child pipe (%s)",
-: 95: _dbus_strerror (errno));
-: 96:
-: 97: retval = READ_STATUS_ERROR;
-: 98: break;
-: 99: }
7775: 100: else if (chunk == 0)
branch 0 taken 20% (fallthrough)
branch 1 taken 80%
-: 101: {
1525: 102: retval = READ_STATUS_EOF;
1525: 103: break; /* EOF */
-: 104: }
-: 105: else /* chunk > 0 */
6250: 106: bytes += chunk;
6250: 107: }
-: 108:
7775: 109: *n_ints_read = (int)(bytes / sizeof(int));
-: 110:
7775: 111: return retval;
-: 112:}
-: 113:
-: 114:static ReadStatus
-: 115:read_pid (int fd,
-: 116: pid_t *buf,
-: 117: DBusError *error)
function read_pid called 3108 returned 100% blocks executed 86%
3108: 118:{
3108: 119: size_t bytes = 0;
-: 120: ReadStatus retval;
-: 121:
3108: 122: _DBUS_ASSERT_ERROR_IS_CLEAR (error);
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
call 2 returned 100%
branch 3 taken 100% (fallthrough)
branch 4 taken 0%
call 5 returned 100%
-: 123:
3108: 124: retval = READ_STATUS_OK;
-: 125:
-: 126: while (TRUE)
-: 127: {
-: 128: size_t chunk;
-: 129: size_t to_read;
-: 130:
6216: 131: to_read = sizeof (pid_t) - bytes;
-: 132:
6216: 133: if (to_read == 0)
branch 0 taken 50% (fallthrough)
branch 1 taken 50%
3108: 134: break;
-: 135:
3108: 136: again:
-: 137:
3108: 138: chunk = read (fd,
call 0 returned 100%
-: 139: ((char*)buf) + bytes,
-: 140: to_read);
-: 141: if (chunk < 0 && errno == EINTR)
-: 142: goto again;
-: 143:
-: 144: if (chunk < 0)
-: 145: {
-: 146: dbus_set_error (error,
-: 147: DBUS_ERROR_SPAWN_FAILED,
-: 148: "Failed to read from child pipe (%s)",
-: 149: _dbus_strerror (errno));
-: 150:
-: 151: retval = READ_STATUS_ERROR;
-: 152: break;
-: 153: }
3108: 154: else if (chunk == 0)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 155: {
#####: 156: retval = READ_STATUS_EOF;
#####: 157: break; /* EOF */
-: 158: }
-: 159: else /* chunk > 0 */
3108: 160: bytes += chunk;
3108: 161: }
-: 162:
3108: 163: return retval;
-: 164:}
-: 165:
-: 166:/* The implementation uses an intermediate child between the main process
-: 167: * and the grandchild. The grandchild is our spawned process. The intermediate
-: 168: * child is a babysitter process; it keeps track of when the grandchild
-: 169: * exits/crashes, and reaps the grandchild.
-: 170: */
-: 171:
-: 172:/* Messages from children to parents */
-: 173:enum
-: 174:{
-: 175: CHILD_EXITED, /* This message is followed by the exit status int */
-: 176: CHILD_FORK_FAILED, /* Followed by errno */
-: 177: CHILD_EXEC_FAILED, /* Followed by errno */
-: 178: CHILD_PID /* Followed by pid_t */
-: 179:};
-: 180:
-: 181:/**
-: 182: * Babysitter implementation details
-: 183: */
-: 184:struct DBusBabysitter
-: 185:{
-: 186: int refcount; /**< Reference count */
-: 187:
-: 188: char *executable; /**< executable name to use in error messages */
-: 189:
-: 190: int socket_to_babysitter; /**< Connection to the babysitter process */
-: 191: int error_pipe_from_child; /**< Connection to the process that does the exec() */
-: 192:
-: 193: pid_t sitter_pid; /**< PID Of the babysitter */
-: 194: pid_t grandchild_pid; /**< PID of the grandchild */
-: 195:
-: 196: DBusWatchList *watches; /**< Watches */
-: 197:
-: 198: DBusWatch *error_watch; /**< Error pipe watch */
-: 199: DBusWatch *sitter_watch; /**< Sitter pipe watch */
-: 200:
-: 201: int errnum; /**< Error number */
-: 202: int status; /**< Exit status code */
-: 203: unsigned int have_child_status : 1; /**< True if child status has been reaped */
-: 204: unsigned int have_fork_errnum : 1; /**< True if we have an error code from fork() */
-: 205: unsigned int have_exec_errnum : 1; /**< True if we have an error code from exec() */
-: 206:};
-: 207:
-: 208:static DBusBabysitter*
-: 209:_dbus_babysitter_new (void)
function _dbus_babysitter_new called 3270 returned 100% blocks executed 100%
3270: 210:{
-: 211: DBusBabysitter *sitter;
-: 212:
3270: 213: sitter = dbus_new0 (DBusBabysitter, 1);
call 0 returned 100%
3270: 214: if (sitter == NULL)
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
21: 215: return NULL;
-: 216:
3249: 217: sitter->refcount = 1;
-: 218:
3249: 219: sitter->socket_to_babysitter = -1;
3249: 220: sitter->error_pipe_from_child = -1;
-: 221:
3249: 222: sitter->sitter_pid = -1;
3249: 223: sitter->grandchild_pid = -1;
-: 224:
3249: 225: sitter->watches = _dbus_watch_list_new ();
call 0 returned 100%
3249: 226: if (sitter->watches == NULL)
branch 0 taken 99% (fallthrough)
branch 1 taken 1%
21: 227: goto failed;
-: 228:
3228: 229: return sitter;
-: 230:
21: 231: failed:
21: 232: _dbus_babysitter_unref (sitter);
call 0 returned 100%
21: 233: return NULL;
-: 234:}
-: 235:
-: 236:/**
-: 237: * Increment the reference count on the babysitter object.
-: 238: *
-: 239: * @param sitter the babysitter
-: 240: * @returns the babysitter
-: 241: */
-: 242:DBusBabysitter *
-: 243:_dbus_babysitter_ref (DBusBabysitter *sitter)
function _dbus_babysitter_ref called 6074 returned 100% blocks executed 100%
6074: 244:{
6074: 245: _dbus_assert (sitter != NULL);
call 0 returned 100%
6074: 246: _dbus_assert (sitter->refcount > 0);
call 0 returned 100%
-: 247:
6074: 248: sitter->refcount += 1;
-: 249:
6074: 250: return sitter;
-: 251:}
-: 252:
-: 253:/**
-: 254: * Decrement the reference count on the babysitter object.
-: 255: * When the reference count of the babysitter object reaches
-: 256: * zero, the babysitter is killed and the child that was being
-: 257: * babysat gets emancipated.
-: 258: *
-: 259: * @param sitter the babysitter
-: 260: */
-: 261:void
-: 262:_dbus_babysitter_unref (DBusBabysitter *sitter)
function _dbus_babysitter_unref called 9323 returned 100% blocks executed 75%
9323: 263:{
9323: 264: _dbus_assert (sitter != NULL);
call 0 returned 100%
9323: 265: _dbus_assert (sitter->refcount > 0);
call 0 returned 100%
-: 266:
9323: 267: sitter->refcount -= 1;
9323: 268: if (sitter->refcount == 0)
branch 0 taken 35% (fallthrough)
branch 1 taken 65%
-: 269: {
3249: 270: if (sitter->socket_to_babysitter >= 0)
branch 0 taken 49% (fallthrough)
branch 1 taken 51%
-: 271: {
-: 272: /* If we haven't forked other babysitters
-: 273: * since this babysitter and socket were
-: 274: * created then this close will cause the
-: 275: * babysitter to wake up from poll with
-: 276: * a hangup and then the babysitter will
-: 277: * quit itself.
-: 278: */
1585: 279: close (sitter->socket_to_babysitter);
call 0 returned 100%
1585: 280: sitter->socket_to_babysitter = -1;
-: 281: }
-: 282:
3249: 283: if (sitter->error_pipe_from_child >= 0)
branch 0 taken 49% (fallthrough)
branch 1 taken 51%
-: 284: {
1585: 285: close (sitter->error_pipe_from_child);
call 0 returned 100%
1585: 286: sitter->error_pipe_from_child = -1;
-: 287: }
-: 288:
3249: 289: if (sitter->sitter_pid > 0)
branch 0 taken 96% (fallthrough)
branch 1 taken 4%
-: 290: {
-: 291: int status;
-: 292: int ret;
-: 293:
-: 294: /* It's possible the babysitter died on its own above
-: 295: * from the close, or was killed randomly
-: 296: * by some other process, so first try to reap it
-: 297: */
3110: 298: ret = waitpid (sitter->sitter_pid, &status, WNOHANG);
call 0 returned 100%
-: 299:
-: 300: /* If we couldn't reap the child then kill it, and
-: 301: * try again
-: 302: */
3110: 303: if (ret == 0)
branch 0 taken 54% (fallthrough)
branch 1 taken 46%
1687: 304: kill (sitter->sitter_pid, SIGKILL);
call 0 returned 100%
-: 305:
3110: 306: again:
3110: 307: if (ret == 0)
branch 0 taken 54% (fallthrough)
branch 1 taken 46%
1687: 308: ret = waitpid (sitter->sitter_pid, &status, 0);
call 0 returned 100%
-: 309:
3110: 310: if (ret < 0)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 311: {
#####: 312: if (errno == EINTR)
call 0 never executed
branch 1 never executed
branch 2 never executed
#####: 313: goto again;
#####: 314: else if (errno == ECHILD)
call 0 never executed
branch 1 never executed
branch 2 never executed
#####: 315: _dbus_warn ("Babysitter process not available to be reaped; should not happen\n");
call 0 never executed
-: 316: else
#####: 317: _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s\n",
call 0 never executed
call 1 never executed
call 2 never executed
call 3 never executed
-: 318: errno, _dbus_strerror (errno));
-: 319: }
-: 320: else
-: 321: {
3110: 322: _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n",
call 0 returned 100%
-: 323: (long) ret, (long) sitter->sitter_pid);
-: 324:
3110: 325: if (WIFEXITED (sitter->status))
branch 0 taken 84% (fallthrough)
branch 1 taken 16%
2605: 326: _dbus_verbose ("Babysitter exited with status %d\n",
call 0 returned 100%
2605: 327: WEXITSTATUS (sitter->status));
505: 328: else if (WIFSIGNALED (sitter->status))
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
505: 329: _dbus_verbose ("Babysitter received signal %d\n",
call 0 returned 100%
505: 330: WTERMSIG (sitter->status));
-: 331: else
#####: 332: _dbus_verbose ("Babysitter exited abnormally\n");
call 0 never executed
-: 333: }
-: 334:
3110: 335: sitter->sitter_pid = -1;
-: 336: }
-: 337:
3249: 338: if (sitter->error_watch)
branch 0 taken 98% (fallthrough)
branch 1 taken 2%
-: 339: {
3185: 340: _dbus_watch_invalidate (sitter->error_watch);
call 0 returned 100%
3185: 341: _dbus_watch_unref (sitter->error_watch);
call 0 returned 100%
3185: 342: sitter->error_watch = NULL;
-: 343: }
-: 344:
3249: 345: if (sitter->sitter_watch)
branch 0 taken 96% (fallthrough)
branch 1 taken 4%
-: 346: {
3131: 347: _dbus_watch_invalidate (sitter->sitter_watch);
call 0 returned 100%
3131: 348: _dbus_watch_unref (sitter->sitter_watch);
call 0 returned 100%
3131: 349: sitter->sitter_watch = NULL;
-: 350: }
-: 351:
3249: 352: if (sitter->watches)
branch 0 taken 99% (fallthrough)
branch 1 taken 1%
3228: 353: _dbus_watch_list_free (sitter->watches);
call 0 returned 100%
-: 354:
3249: 355: dbus_free (sitter->executable);
call 0 returned 100%
-: 356:
3249: 357: dbus_free (sitter);
call 0 returned 100%
-: 358: }
9323: 359:}
-: 360:
-: 361:static ReadStatus
-: 362:read_data (DBusBabysitter *sitter,
-: 363: int fd)
function read_data called 6204 returned 100% blocks executed 62%
6204: 364:{
-: 365: int what;
-: 366: int got;
-: 367: DBusError error;
-: 368: ReadStatus r;
-: 369:
6204: 370: dbus_error_init (&error);
call 0 returned 100%
-: 371:
6204: 372: r = read_ints (fd, &what, 1, &got, &error);
call 0 returned 100%
-: 373:
6204: 374: switch (r)
branch 0 taken 0%
branch 1 taken 25%
branch 2 taken 75%
-: 375: {
-: 376: case READ_STATUS_ERROR:
#####: 377: _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message);
call 0 never executed
#####: 378: dbus_error_free (&error);
call 0 never executed
#####: 379: return r;
-: 380:
-: 381: case READ_STATUS_EOF:
1525: 382: return r;
-: 383:
-: 384: case READ_STATUS_OK:
-: 385: break;
-: 386: }
-: 387:
4679: 388: if (got == 1)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
-: 389: {
4679: 390: switch (what)
branch 0 taken 34%
branch 1 taken 66%
branch 2 taken 0%
-: 391: {
-: 392: case CHILD_EXITED:
-: 393: case CHILD_FORK_FAILED:
-: 394: case CHILD_EXEC_FAILED:
-: 395: {
-: 396: int arg;
-: 397:
1571: 398: r = read_ints (fd, &arg, 1, &got, &error);
call 0 returned 100%
-: 399:
1571: 400: switch (r)
branch 0 taken 0%
branch 1 taken 0%
branch 2 taken 100%
-: 401: {
-: 402: case READ_STATUS_ERROR:
#####: 403: _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message);
call 0 never executed
#####: 404: dbus_error_free (&error);
call 0 never executed
#####: 405: return r;
-: 406: case READ_STATUS_EOF:
#####: 407: return r;
-: 408: case READ_STATUS_OK:
-: 409: break;
-: 410: }
-: 411:
1571: 412: if (got == 1)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
-: 413: {
1571: 414: if (what == CHILD_EXITED)
branch 0 taken 97% (fallthrough)
branch 1 taken 3%
-: 415: {
1525: 416: sitter->have_child_status = TRUE;
1525: 417: sitter->status = arg;
6100: 418: _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
call 0 returned 100%
3050: 419: WIFEXITED (sitter->status), WIFSIGNALED (sitter->status),
3050: 420: WEXITSTATUS (sitter->status), WTERMSIG (sitter->status));
-: 421: }
46: 422: else if (what == CHILD_FORK_FAILED)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 423: {
#####: 424: sitter->have_fork_errnum = TRUE;
#####: 425: sitter->errnum = arg;
#####: 426: _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum);
call 0 never executed
-: 427: }
46: 428: else if (what == CHILD_EXEC_FAILED)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
-: 429: {
46: 430: sitter->have_exec_errnum = TRUE;
46: 431: sitter->errnum = arg;
46: 432: _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum);
call 0 returned 100%
-: 433: }
-: 434: }
-: 435: }
1571: 436: break;
-: 437: case CHILD_PID:
-: 438: {
3108: 439: pid_t pid = -1;
-: 440:
3108: 441: r = read_pid (fd, &pid, &error);
call 0 returned 100%
-: 442:
3108: 443: switch (r)
branch 0 taken 0%
branch 1 taken 0%
branch 2 taken 100%
-: 444: {
-: 445: case READ_STATUS_ERROR:
#####: 446: _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message);
call 0 never executed
#####: 447: dbus_error_free (&error);
call 0 never executed
#####: 448: return r;
-: 449: case READ_STATUS_EOF:
#####: 450: return r;
-: 451: case READ_STATUS_OK:
-: 452: break;
-: 453: }
-: 454:
3108: 455: sitter->grandchild_pid = pid;
-: 456:
3108: 457: _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid);
call 0 returned 100%
-: 458: }
3108: 459: break;
-: 460: default:
#####: 461: _dbus_warn ("Unknown message received from babysitter process\n");
call 0 never executed
-: 462: break;
-: 463: }
-: 464: }
-: 465:
4679: 466: return r;
-: 467:}
-: 468:
-: 469:static void
-: 470:close_socket_to_babysitter (DBusBabysitter *sitter)
function close_socket_to_babysitter called 1525 returned 100% blocks executed 100%
1525: 471:{
1525: 472: _dbus_verbose ("Closing babysitter\n");
call 0 returned 100%
1525: 473: close (sitter->socket_to_babysitter);
call 0 returned 100%
1525: 474: sitter->socket_to_babysitter = -1;
1525: 475:}
-: 476:
-: 477:static void
-: 478:close_error_pipe_from_child (DBusBabysitter *sitter)
function close_error_pipe_from_child called 1525 returned 100% blocks executed 100%
1525: 479:{
1525: 480: _dbus_verbose ("Closing child error\n");
call 0 returned 100%
1525: 481: close (sitter->error_pipe_from_child);
call 0 returned 100%
1525: 482: sitter->error_pipe_from_child = -1;
1525: 483:}
-: 484:
-: 485:static void
-: 486:handle_babysitter_socket (DBusBabysitter *sitter,
-: 487: int revents)
function handle_babysitter_socket called 6378 returned 100% blocks executed 89%
6378: 488:{
-: 489: /* Even if we have POLLHUP, we want to keep reading
-: 490: * data until POLLIN goes away; so this function only
-: 491: * looks at HUP/ERR if no IN is set.
-: 492: */
6378: 493: if (revents & _DBUS_POLLIN)
branch 0 taken 97% (fallthrough)
branch 1 taken 3%
-: 494: {
6158: 495: _dbus_verbose ("Reading data from babysitter\n");
call 0 returned 100%
6158: 496: if (read_data (sitter, sitter->socket_to_babysitter) != READ_STATUS_OK)
call 0 returned 100%
branch 1 taken 25% (fallthrough)
branch 2 taken 75%
1525: 497: close_socket_to_babysitter (sitter);
call 0 returned 100%
-: 498: }
220: 499: else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 500: {
#####: 501: close_socket_to_babysitter (sitter);
call 0 never executed
-: 502: }
6378: 503:}
-: 504:
-: 505:static void
-: 506:handle_error_pipe (DBusBabysitter *sitter,
-: 507: int revents)
function handle_error_pipe called 1981 returned 100% blocks executed 89%
1981: 508:{
1981: 509: if (revents & _DBUS_POLLIN)
branch 0 taken 2% (fallthrough)
branch 1 taken 98%
-: 510: {
46: 511: _dbus_verbose ("Reading data from child error\n");
call 0 returned 100%
46: 512: if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK)
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
#####: 513: close_error_pipe_from_child (sitter);
call 0 never executed
-: 514: }
1935: 515: else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
branch 0 taken 79% (fallthrough)
branch 1 taken 21%
-: 516: {
1525: 517: close_error_pipe_from_child (sitter);
call 0 returned 100%
-: 518: }
1981: 519:}
-: 520:
-: 521:/* returns whether there were any poll events handled */
-: 522:static dbus_bool_t
-: 523:babysitter_iteration (DBusBabysitter *sitter,
-: 524: dbus_bool_t block)
function babysitter_iteration called 11113 returned 100% blocks executed 100%
11113: 525:{
-: 526: DBusPollFD fds[2];
-: 527: int i;
-: 528: dbus_bool_t descriptors_ready;
-: 529:
11113: 530: descriptors_ready = FALSE;
-: 531:
11113: 532: i = 0;
-: 533:
11113: 534: if (sitter->error_pipe_from_child >= 0)
branch 0 taken 79% (fallthrough)
branch 1 taken 21%
-: 535: {
8780: 536: fds[i].fd = sitter->error_pipe_from_child;
8780: 537: fds[i].events = _DBUS_POLLIN;
8780: 538: fds[i].revents = 0;
8780: 539: ++i;
-: 540: }
-: 541:
11113: 542: if (sitter->socket_to_babysitter >= 0)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
-: 543: {
11113: 544: fds[i].fd = sitter->socket_to_babysitter;
11113: 545: fds[i].events = _DBUS_POLLIN;
11113: 546: fds[i].revents = 0;
11113: 547: ++i;
-: 548: }
-: 549:
11113: 550: if (i > 0)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
-: 551: {
-: 552: int ret;
-: 553:
11113: 554: ret = _dbus_poll (fds, i, 0);
call 0 returned 100%
11113: 555: if (ret == 0 && block)
branch 0 taken 92% (fallthrough)
branch 1 taken 8%
branch 2 taken 7% (fallthrough)
branch 3 taken 93%
729: 556: ret = _dbus_poll (fds, i, -1);
call 0 returned 100%
-: 557:
11113: 558: if (ret > 0)
branch 0 taken 15% (fallthrough)
branch 1 taken 85%
-: 559: {
1645: 560: descriptors_ready = TRUE;
-: 561:
5575: 562: while (i > 0)
branch 0 taken 58%
branch 1 taken 42% (fallthrough)
-: 563: {
2285: 564: --i;
2285: 565: if (fds[i].fd == sitter->error_pipe_from_child)
branch 0 taken 28% (fallthrough)
branch 1 taken 72%
640: 566: handle_error_pipe (sitter, fds[i].revents);
call 0 returned 100%
1645: 567: else if (fds[i].fd == sitter->socket_to_babysitter)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
1645: 568: handle_babysitter_socket (sitter, fds[i].revents);
call 0 returned 100%
-: 569: }
-: 570: }
-: 571: }
-: 572:
11113: 573: return descriptors_ready;
-: 574:}
-: 575:
-: 576:/**
-: 577: * Macro returns #TRUE if the babysitter still has live sockets open to the
-: 578: * babysitter child or the grandchild.
-: 579: */
-: 580:#define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter >= 0 || (sitter)->error_pipe_from_child >= 0)
-: 581:
-: 582:/**
-: 583: * Blocks until the babysitter process gives us the PID of the spawned grandchild,
-: 584: * then kills the spawned grandchild.
-: 585: *
-: 586: * @param sitter the babysitter object
-: 587: */
-: 588:void
-: 589:_dbus_babysitter_kill_child (DBusBabysitter *sitter)
function _dbus_babysitter_kill_child called 93 returned 100% blocks executed 80%
93: 590:{
-: 591: /* be sure we have the PID of the child */
279: 592: while (LIVE_CHILDREN (sitter) &&
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
branch 2 never executed
branch 3 never executed
branch 4 taken 50%
branch 5 taken 50% (fallthrough)
-: 593: sitter->grandchild_pid == -1)
93: 594: babysitter_iteration (sitter, TRUE);
call 0 returned 100%
-: 595:
93: 596: _dbus_verbose ("Got child PID %ld for killing\n",
call 0 returned 100%
-: 597: (long) sitter->grandchild_pid);
-: 598:
93: 599: if (sitter->grandchild_pid == -1)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
#####: 600: return; /* child is already dead, or we're so hosed we'll never recover */
-: 601:
93: 602: kill (sitter->grandchild_pid, SIGKILL);
call 0 returned 100%
-: 603:}
-: 604:
-: 605:/**
-: 606: * Checks whether the child has exited, without blocking.
-: 607: *
-: 608: * @param sitter the babysitter
-: 609: */
-: 610:dbus_bool_t
-: 611:_dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
function _dbus_babysitter_get_child_exited called 7599 returned 100% blocks executed 100%
7601: 612:{
-: 613:
-: 614: /* Be sure we're up-to-date */
7601: 615: while (LIVE_CHILDREN (sitter) &&
branch 0 taken 38% (fallthrough)
branch 1 taken 62%
branch 2 taken 0% (fallthrough)
branch 3 taken 100%
call 4 returned 100%
branch 5 taken 1%
branch 6 taken 99% (fallthrough)
-: 616: babysitter_iteration (sitter, FALSE))
-: 617: ;
-: 618:
-: 619: /* We will have exited the babysitter when the child has exited */
7599: 620: return sitter->socket_to_babysitter < 0;
-: 621:}
-: 622:
-: 623:/**
-: 624: * Sets the #DBusError with an explanation of why the spawned
-: 625: * child process exited (on a signal, or whatever). If
-: 626: * the child process has not exited, does nothing (error
-: 627: * will remain unset).
-: 628: *
-: 629: * @param sitter the babysitter
-: 630: * @param error an error to fill in
-: 631: */
-: 632:void
-: 633:_dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
-: 634: DBusError *error)
function _dbus_babysitter_set_child_exit_error called 1525 returned 100% blocks executed 72%
1525: 635:{
1525: 636: if (!_dbus_babysitter_get_child_exited (sitter))
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
#####: 637: return;
-: 638:
-: 639: /* Note that if exec fails, we will also get a child status
-: 640: * from the babysitter saying the child exited,
-: 641: * so we need to give priority to the exec error
-: 642: */
1525: 643: if (sitter->have_exec_errnum)
branch 0 taken 3% (fallthrough)
branch 1 taken 97%
-: 644: {
46: 645: dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
call 0 returned 100%
call 1 returned 100%
-: 646: "Failed to execute program %s: %s",
-: 647: sitter->executable, _dbus_strerror (sitter->errnum));
-: 648: }
1479: 649: else if (sitter->have_fork_errnum)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 650: {
#####: 651: dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
call 0 never executed
call 1 never executed
-: 652: "Failed to fork a new process %s: %s",
-: 653: sitter->executable, _dbus_strerror (sitter->errnum));
-: 654: }
1479: 655: else if (sitter->have_child_status)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
-: 656: {
1479: 657: if (WIFEXITED (sitter->status))
branch 0 taken 66% (fallthrough)
branch 1 taken 34%
974: 658: dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
call 0 returned 100%
-: 659: "Process %s exited with status %d",
974: 660: sitter->executable, WEXITSTATUS (sitter->status));
505: 661: else if (WIFSIGNALED (sitter->status))
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
505: 662: dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,
call 0 returned 100%
-: 663: "Process %s received signal %d",
505: 664: sitter->executable, WTERMSIG (sitter->status));
-: 665: else
#####: 666: dbus_set_error (error, DBUS_ERROR_FAILED,
call 0 never executed
-: 667: "Process %s exited abnormally",
-: 668: sitter->executable);
-: 669: }
-: 670: else
-: 671: {
#####: 672: dbus_set_error (error, DBUS_ERROR_FAILED,
call 0 never executed
-: 673: "Process %s exited, reason unknown",
-: 674: sitter->executable);
-: 675: }
-: 676:}
-: 677:
-: 678:/**
-: 679: * Sets watch functions to notify us when the
-: 680: * babysitter object needs to read/write file descriptors.
-: 681: *
-: 682: * @param sitter the babysitter
-: 683: * @param add_function function to begin monitoring a new descriptor.
-: 684: * @param remove_function function to stop monitoring a descriptor.
-: 685: * @param toggled_function function to notify when the watch is enabled/disabled
-: 686: * @param data data to pass to add_function and remove_function.
-: 687: * @param free_data_function function to be called to free the data.
-: 688: * @returns #FALSE on failure (no memory)
-: 689: */
-: 690:dbus_bool_t
-: 691:_dbus_babysitter_set_watch_functions (DBusBabysitter *sitter,
-: 692: DBusAddWatchFunction add_function,
-: 693: DBusRemoveWatchFunction remove_function,
-: 694: DBusWatchToggledFunction toggled_function,
-: 695: void *data,
-: 696: DBusFreeFunction free_data_function)
function _dbus_babysitter_set_watch_functions called 5852 returned 100% blocks executed 100%
5852: 697:{
5852: 698: return _dbus_watch_list_set_functions (sitter->watches,
call 0 returned 100%
-: 699: add_function,
-: 700: remove_function,
-: 701: toggled_function,
-: 702: data,
-: 703: free_data_function);
-: 704:}
-: 705:
-: 706:static dbus_bool_t
-: 707:handle_watch (DBusWatch *watch,
-: 708: unsigned int condition,
-: 709: void *data)
function handle_watch called 6074 returned 100% blocks executed 94%
6074: 710:{
6074: 711: DBusBabysitter *sitter = data;
-: 712: int revents;
-: 713: int fd;
-: 714:
6074: 715: revents = 0;
6074: 716: if (condition & DBUS_WATCH_READABLE)
branch 0 taken 78% (fallthrough)
branch 1 taken 22%
4733: 717: revents |= _DBUS_POLLIN;
6074: 718: if (condition & DBUS_WATCH_ERROR)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
#####: 719: revents |= _DBUS_POLLERR;
6074: 720: if (condition & DBUS_WATCH_HANGUP)
branch 0 taken 33% (fallthrough)
branch 1 taken 67%
2004: 721: revents |= _DBUS_POLLHUP;
-: 722:
6074: 723: fd = dbus_watch_get_fd (watch);
call 0 returned 100%
-: 724:
6074: 725: if (fd == sitter->error_pipe_from_child)
branch 0 taken 22% (fallthrough)
branch 1 taken 78%
1341: 726: handle_error_pipe (sitter, revents);
call 0 returned 100%
4733: 727: else if (fd == sitter->socket_to_babysitter)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
4733: 728: handle_babysitter_socket (sitter, revents);
call 0 returned 100%
-: 729:
6898: 730: while (LIVE_CHILDREN (sitter) &&
branch 0 taken 19% (fallthrough)
branch 1 taken 81%
branch 2 taken 0% (fallthrough)
branch 3 taken 100%
call 4 returned 100%
branch 5 taken 15%
branch 6 taken 85% (fallthrough)
-: 731: babysitter_iteration (sitter, FALSE))
-: 732: ;
-: 733:
6074: 734: return TRUE;
-: 735:}
-: 736:
-: 737:/** Helps remember which end of the pipe is which */
-: 738:#define READ_END 0
-: 739:/** Helps remember which end of the pipe is which */
-: 740:#define WRITE_END 1
-: 741:
-: 742:
-: 743:/* Avoids a danger in threaded situations (calling close()
-: 744: * on a file descriptor twice, and another thread has
-: 745: * re-opened it since the first close)
-: 746: */
-: 747:static int
-: 748:close_and_invalidate (int *fd)
function close_and_invalidate called 12912 returned 100% blocks executed 100%
12912: 749:{
-: 750: int ret;
-: 751:
12912: 752: if (*fd < 0)
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
84: 753: return -1;
-: 754: else
-: 755: {
12828: 756: ret = close (*fd);
call 0 returned 100%
12828: 757: *fd = -1;
-: 758: }
-: 759:
12828: 760: return ret;
-: 761:}
-: 762:
-: 763:static dbus_bool_t
-: 764:make_pipe (int p[2],
-: 765: DBusError *error)
function make_pipe called 3207 returned 100% blocks executed 64%
3207: 766:{
3207: 767: _DBUS_ASSERT_ERROR_IS_CLEAR (error);
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
call 2 returned 100%
branch 3 taken 100% (fallthrough)
branch 4 taken 0%
call 5 returned 100%
-: 768:
3207: 769: if (pipe (p) < 0)
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
-: 770: {
#####: 771: dbus_set_error (error,
call 0 never executed
call 1 never executed
call 2 never executed
-: 772: DBUS_ERROR_SPAWN_FAILED,
-: 773: "Failed to create pipe for communicating with child process (%s)",
-: 774: _dbus_strerror (errno));
#####: 775: return FALSE;
-: 776: }
-: 777:
3207: 778: return TRUE;
-: 779:}
-: 780:
-: 781:static void
-: 782:do_write (int fd, const void *buf, size_t count)
function do_write called 6194 returned 100% blocks executed 45%
6194: 783:{
-: 784: size_t bytes_written;
-: 785: int ret;
-: 786:
6194: 787: bytes_written = 0;
-: 788:
6194: 789: again:
-: 790:
6194: 791: ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
call 0 returned 100%
-: 792:
6194: 793: if (ret < 0)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 794: {
#####: 795: if (errno == EINTR)
call 0 never executed
branch 1 never executed
branch 2 never executed
#####: 796: goto again;
-: 797: else
-: 798: {
#####: 799: _dbus_warn ("Failed to write data to pipe!\n");
call 0 never executed
#####: 800: exit (1); /* give up, we suck */
call 0 never executed
-: 801: }
-: 802: }
-: 803: else
6194: 804: bytes_written += ret;
-: 805:
6194: 806: if (bytes_written < count)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
#####: 807: goto again;
6194: 808:}
-: 809:
-: 810:static void
-: 811:write_err_and_exit (int fd, int msg)
function write_err_and_exit called 46 returned 0% blocks executed 100%
46: 812:{
46: 813: int en = errno;
call 0 returned 100%
-: 814:
46: 815: do_write (fd, &msg, sizeof (msg));
call 0 returned 100%
46: 816: do_write (fd, &en, sizeof (en));
call 0 returned 100%
-: 817:
46: 818: exit (1);
call 0 returned 0%
-: 819:}
-: 820:
-: 821:static void
-: 822:write_pid (int fd, pid_t pid)
function write_pid called 1526 returned 100% blocks executed 100%
1526: 823:{
1526: 824: int msg = CHILD_PID;
-: 825:
1526: 826: do_write (fd, &msg, sizeof (msg));
call 0 returned 100%
1526: 827: do_write (fd, &pid, sizeof (pid));
call 0 returned 100%
1526: 828:}
-: 829:
-: 830:static void
-: 831:write_status_and_exit (int fd, int status)
function write_status_and_exit called 1525 returned 0% blocks executed 100%
1525: 832:{
1525: 833: int msg = CHILD_EXITED;
-: 834:
1525: 835: do_write (fd, &msg, sizeof (msg));
call 0 returned 100%
1525: 836: do_write (fd, &status, sizeof (status));
call 0 returned 100%
-: 837:
1525: 838: exit (0);
call 0 returned 0%
-: 839:}
-: 840:
-: 841:static void
-: 842:do_exec (int child_err_report_fd,
-: 843: char **argv,
-: 844: DBusSpawnChildSetupFunc child_setup,
-: 845: void *user_data)
function do_exec called 3072 returned 0% blocks executed 89%
3072: 846:{
-: 847:#ifdef DBUS_BUILD_TESTS
-: 848: int i, max_open;
-: 849:#endif
-: 850:
3072: 851: _dbus_verbose_reset ();
call 0 returned 100%
3072: 852: _dbus_verbose ("Child process has PID %lu\n",
call 0 returned 100%
call 1 returned 100%
-: 853: _dbus_getpid ());
-: 854:
3072: 855: if (child_setup)
branch 0 taken 95% (fallthrough)
branch 1 taken 5%
2904: 856: (* child_setup) (user_data);
call 0 returned 100%
-: 857:
-: 858:#ifdef DBUS_BUILD_TESTS
3072: 859: max_open = sysconf (_SC_OPEN_MAX);
call 0 returned 100%
-: 860:
3139584: 861: for (i = 3; i < max_open; i++)
branch 0 taken 99%
branch 1 taken 1% (fallthrough)
-: 862: {
-: 863: int retval;
-: 864:
3136512: 865: if (i == child_err_report_fd)
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
3072: 866: continue;
-: 867:
3133440: 868: retval = fcntl (i, F_GETFD);
call 0 returned 100%
-: 869:
3133440: 870: if (retval != -1 && !(retval & FD_CLOEXEC))
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
branch 2 taken 0% (fallthrough)
branch 3 taken 100%
#####: 871: _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
call 0 never executed
-: 872: }
-: 873:#endif
-: 874:
3072: 875: execv (argv[0], argv);
call 0 returned 1%
-: 876:
-: 877: /* Exec failed */
46: 878: write_err_and_exit (child_err_report_fd,
call 0 returned 0%
-: 879: CHILD_EXEC_FAILED);
#####: 880:}
-: 881:
-: 882:static void
-: 883:check_babysit_events (pid_t grandchild_pid,
-: 884: int parent_pipe,
-: 885: int revents)
function check_babysit_events called 3036 returned 50% blocks executed 64%
3036: 886:{
-: 887: pid_t ret;
-: 888: int status;
-: 889:
-: 890: do
-: 891: {
3036: 892: ret = waitpid (grandchild_pid, &status, WNOHANG);
call 0 returned 100%
-: 893: /* The man page says EINTR can't happen with WNOHANG,
-: 894: * but there are reports of it (maybe only with valgrind?)
-: 895: */
-: 896: }
3036: 897: while (ret < 0 && errno == EINTR);
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
call 2 never executed
branch 3 never executed
branch 4 never executed
-: 898:
3036: 899: if (ret == 0)
branch 0 taken 50% (fallthrough)
branch 1 taken 50%
-: 900: {
1511: 901: _dbus_verbose ("no child exited\n");
call 0 returned 100%
-: 902:
-: 903: ; /* no child exited */
-: 904: }
1525: 905: else if (ret < 0)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 906: {
-: 907: /* This isn't supposed to happen. */
#####: 908: _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n",
call 0 never executed
call 1 never executed
call 2 never executed
-: 909: _dbus_strerror (errno));
#####: 910: exit (1);
call 0 never executed
-: 911: }
1525: 912: else if (ret == grandchild_pid)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
-: 913: {
-: 914: /* Child exited */
1525: 915: _dbus_verbose ("reaped child pid %ld\n", (long) ret);
call 0 returned 100%
-: 916:
1525: 917: write_status_and_exit (parent_pipe, status);
call 0 returned 0%
-: 918: }
-: 919: else
-: 920: {
#####: 921: _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n",
call 0 never executed
-: 922: (int) ret);
#####: 923: exit (1);
call 0 never executed
-: 924: }
-: 925:
1511: 926: if (revents & _DBUS_POLLIN)
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
-: 927: {
1: 928: _dbus_verbose ("babysitter got POLLIN from parent pipe\n");
call 0 returned 100%
-: 929: }
-: 930:
1511: 931: if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
-: 932: {
-: 933: /* Parent is gone, so we just exit */
1: 934: _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n");
call 0 returned 100%
1: 935: exit (0);
call 0 returned 0%
-: 936: }
1510: 937:}
-: 938:
-: 939:static int babysit_sigchld_pipe = -1;
-: 940:
-: 941:static void
-: 942:babysit_signal_handler (int signo)
function babysit_signal_handler called 1510 returned 100% blocks executed 83%
1510: 943:{
1510: 944: char b = '\0';
1510: 945: again:
1510: 946: write (babysit_sigchld_pipe, &b, 1);
call 0 returned 100%
1510: 947: if (errno == EINTR)
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
#####: 948: goto again;
1510: 949:}
-: 950:
-: 951:static void
-: 952:babysit (pid_t grandchild_pid,
-: 953: int parent_pipe)
function babysit called 1526 returned 0% blocks executed 87%
1526: 954:{
-: 955: int sigchld_pipe[2];
-: 956:
-: 957: /* We don't exec, so we keep parent state, such as the pid that
-: 958: * _dbus_verbose() uses. Reset the pid here.
-: 959: */
1526: 960: _dbus_verbose_reset ();
call 0 returned 100%
-: 961:
-: 962: /* I thought SIGCHLD would just wake up the poll, but
-: 963: * that didn't seem to work, so added this pipe.
-: 964: * Probably the pipe is more likely to work on busted
-: 965: * operating systems anyhow.
-: 966: */
1526: 967: if (pipe (sigchld_pipe) < 0)
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
-: 968: {
#####: 969: _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n");
call 0 never executed
#####: 970: exit (1);
call 0 never executed
-: 971: }
-: 972:
1526: 973: babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
-: 974:
1526: 975: _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
call 0 returned 100%
-: 976:
1526: 977: write_pid (parent_pipe, grandchild_pid);
call 0 returned 100%
-: 978:
1526: 979: check_babysit_events (grandchild_pid, parent_pipe, 0);
call 0 returned 99%
-: 980:
-: 981: while (TRUE)
-: 982: {
-: 983: DBusPollFD pfds[2];
-: 984:
3019: 985: pfds[0].fd = parent_pipe;
3019: 986: pfds[0].events = _DBUS_POLLIN;
3019: 987: pfds[0].revents = 0;
-: 988:
3019: 989: pfds[1].fd = sigchld_pipe[READ_END];
3019: 990: pfds[1].events = _DBUS_POLLIN;
3019: 991: pfds[1].revents = 0;
-: 992:
3019: 993: _dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1);
call 0 returned 100%
-: 994:
3019: 995: if (pfds[0].revents != 0)
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
-: 996: {
1: 997: check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
call 0 returned 0%
-: 998: }
3018: 999: else if (pfds[1].revents & _DBUS_POLLIN)
branch 0 taken 50% (fallthrough)
branch 1 taken 50%
-: 1000: {
-: 1001: char b;
1509: 1002: read (sigchld_pipe[READ_END], &b, 1);
call 0 returned 100%
-: 1003: /* do waitpid check */
1509: 1004: check_babysit_events (grandchild_pid, parent_pipe, 0);
call 0 returned 0%
-: 1005: }
1509: 1006: }
-: 1007:
-: 1008: exit (1);
-: 1009:}
-: 1010:
-: 1011:/**
-: 1012: * Spawns a new process. The executable name and argv[0]
-: 1013: * are the same, both are provided in argv[0]. The child_setup
-: 1014: * function is passed the given user_data and is run in the child
-: 1015: * just before calling exec().
-: 1016: *
-: 1017: * Also creates a "babysitter" which tracks the status of the
-: 1018: * child process, advising the parent if the child exits.
-: 1019: * If the spawn fails, no babysitter is created.
-: 1020: * If sitter_p is #NULL, no babysitter is kept.
-: 1021: *
-: 1022: * @param sitter_p return location for babysitter or #NULL
-: 1023: * @param argv the executable and arguments
-: 1024: * @param child_setup function to call in child pre-exec()
-: 1025: * @param user_data user data for setup function
-: 1026: * @param error error object to be filled in if function fails
-: 1027: * @returns #TRUE on success, #FALSE if error is filled in
-: 1028: */
-: 1029:dbus_bool_t
-: 1030:_dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
-: 1031: char **argv,
-: 1032: DBusSpawnChildSetupFunc child_setup,
-: 1033: void *user_data,
-: 1034: DBusError *error)
function _dbus_spawn_async_with_babysitter called 3270 returned 100% blocks executed 83%
3270: 1035:{
-: 1036: DBusBabysitter *sitter;
3270: 1037: int child_err_report_pipe[2] = { -1, -1 };
3270: 1038: int babysitter_pipe[2] = { -1, -1 };
-: 1039: pid_t pid;
-: 1040:
3270: 1041: _DBUS_ASSERT_ERROR_IS_CLEAR (error);
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
call 2 returned 100%
branch 3 taken 100% (fallthrough)
branch 4 taken 0%
call 5 returned 100%
-: 1042:
3270: 1043: *sitter_p = NULL;
3270: 1044: sitter = NULL;
-: 1045:
3270: 1046: sitter = _dbus_babysitter_new ();
call 0 returned 100%
3270: 1047: if (sitter == NULL)
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
-: 1048: {
42: 1049: dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
call 0 returned 100%
42: 1050: return FALSE;
-: 1051: }
-: 1052:
3228: 1053: sitter->executable = _dbus_strdup (argv[0]);
call 0 returned 100%
3228: 1054: if (sitter->executable == NULL)
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
-: 1055: {
21: 1056: dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
call 0 returned 100%
21: 1057: goto cleanup_and_fail;
-: 1058: }
-: 1059:
3207: 1060: if (!make_pipe (child_err_report_pipe, error))
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
#####: 1061: goto cleanup_and_fail;
-: 1062:
3207: 1063: _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]);
call 0 returned 100%
-: 1064:
3207: 1065: if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
#####: 1066: goto cleanup_and_fail;
-: 1067:
3207: 1068: _dbus_fd_set_close_on_exec (babysitter_pipe[0]);
call 0 returned 100%
3207: 1069: _dbus_fd_set_close_on_exec (babysitter_pipe[1]);
call 0 returned 100%
-: 1070:
-: 1071: /* Setting up the babysitter is only useful in the parent,
-: 1072: * but we don't want to run out of memory and fail
-: 1073: * after we've already forked, since then we'd leak
-: 1074: * child processes everywhere.
-: 1075: */
3207: 1076: sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
call 0 returned 100%
-: 1077: DBUS_WATCH_READABLE,
-: 1078: TRUE, handle_watch, sitter, NULL);
3207: 1079: if (sitter->error_watch == NULL)
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
-: 1080: {
22: 1081: dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
call 0 returned 100%
22: 1082: goto cleanup_and_fail;
-: 1083: }
-: 1084:
3185: 1085: if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch))
call 0 returned 100%
branch 1 taken 1% (fallthrough)
branch 2 taken 99%
-: 1086: {
33: 1087: dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
call 0 returned 100%
33: 1088: goto cleanup_and_fail;
-: 1089: }
-: 1090:
3152: 1091: sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
call 0 returned 100%
-: 1092: DBUS_WATCH_READABLE,
-: 1093: TRUE, handle_watch, sitter, NULL);
3152: 1094: if (sitter->sitter_watch == NULL)
branch 0 taken 1% (fallthrough)
branch 1 taken 99%
-: 1095: {
21: 1096: dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
call 0 returned 100%
21: 1097: goto cleanup_and_fail;
-: 1098: }
-: 1099:
3131: 1100: if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
call 0 returned 100%
branch 1 taken 1% (fallthrough)
branch 2 taken 99%
-: 1101: {
21: 1102: dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
call 0 returned 100%
21: 1103: goto cleanup_and_fail;
-: 1104: }
-: 1105:
3110: 1106: _DBUS_ASSERT_ERROR_IS_CLEAR (error);
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
call 2 returned 100%
branch 3 taken 100% (fallthrough)
branch 4 taken 0%
call 5 returned 100%
-: 1107:
3110: 1108: pid = fork ();
call 0 returned 99%
-: 1109:
6220: 1110: if (pid < 0)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 1111: {
#####: 1112: dbus_set_error (error,
call 0 never executed
call 1 never executed
call 2 never executed
-: 1113: DBUS_ERROR_SPAWN_FORK_FAILED,
-: 1114: "Failed to fork (%s)",
-: 1115: _dbus_strerror (errno));
#####: 1116: goto cleanup_and_fail;
-: 1117: }
6220: 1118: else if (pid == 0)
branch 0 taken 50% (fallthrough)
branch 1 taken 50%
-: 1119: {
-: 1120: /* Immediate child, this is the babysitter process. */
-: 1121: int grandchild_pid;
-: 1122:
-: 1123: /* Be sure we crash if the parent exits
-: 1124: * and we write to the err_report_pipe
-: 1125: */
3110: 1126: signal (SIGPIPE, SIG_DFL);
call 0 returned 100%
-: 1127:
-: 1128: /* Close the parent's end of the pipes. */
3110: 1129: close_and_invalidate (&child_err_report_pipe[READ_END]);
call 0 returned 100%
3110: 1130: close_and_invalidate (&babysitter_pipe[0]);
call 0 returned 100%
-: 1131:
-: 1132: /* Create the child that will exec () */
3110: 1133: grandchild_pid = fork ();
call 0 returned 99%
-: 1134:
4598: 1135: if (grandchild_pid < 0)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
-: 1136: {
#####: 1137: write_err_and_exit (babysitter_pipe[1],
call 0 never executed
-: 1138: CHILD_FORK_FAILED);
#####: 1139: _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
call 0 never executed
-: 1140: }
4598: 1141: else if (grandchild_pid == 0)
branch 0 taken 67% (fallthrough)
branch 1 taken 33%
-: 1142: {
3072: 1143: do_exec (child_err_report_pipe[WRITE_END],
call 0 returned 0%
-: 1144: argv,
-: 1145: child_setup, user_data);
#####: 1146: _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
call 0 never executed
-: 1147: }
-: 1148: else
-: 1149: {
1526: 1150: babysit (grandchild_pid, babysitter_pipe[1]);
call 0 returned 0%
#####: 1151: _dbus_assert_not_reached ("Got to code after babysit()");
call 0 never executed
-: 1152: }
-: 1153: }
-: 1154: else
-: 1155: {
-: 1156: /* Close the uncared-about ends of the pipes */
3110: 1157: close_and_invalidate (&child_err_report_pipe[WRITE_END]);
call 0 returned 100%
3110: 1158: close_and_invalidate (&babysitter_pipe[1]);
call 0 returned 100%
-: 1159:
3110: 1160: sitter->socket_to_babysitter = babysitter_pipe[0];
3110: 1161: babysitter_pipe[0] = -1;
-: 1162:
3110: 1163: sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
3110: 1164: child_err_report_pipe[READ_END] = -1;
-: 1165:
3110: 1166: sitter->sitter_pid = pid;
-: 1167:
3110: 1168: if (sitter_p != NULL)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
3110: 1169: *sitter_p = sitter;
-: 1170: else
#####: 1171: _dbus_babysitter_unref (sitter);
call 0 never executed
-: 1172:
3110: 1173: _DBUS_ASSERT_ERROR_IS_CLEAR (error);
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
call 2 returned 100%
branch 3 taken 100% (fallthrough)
branch 4 taken 0%
call 5 returned 100%
-: 1174:
3110: 1175: return TRUE;
-: 1176: }
-: 1177:
118: 1178: cleanup_and_fail:
-: 1179:
118: 1180: _DBUS_ASSERT_ERROR_IS_SET (error);
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
call 2 returned 100%
branch 3 taken 100% (fallthrough)
branch 4 taken 0%
call 5 returned 100%
-: 1181:
118: 1182: close_and_invalidate (&child_err_report_pipe[READ_END]);
call 0 returned 100%
118: 1183: close_and_invalidate (&child_err_report_pipe[WRITE_END]);
call 0 returned 100%
118: 1184: close_and_invalidate (&babysitter_pipe[0]);
call 0 returned 100%
118: 1185: close_and_invalidate (&babysitter_pipe[1]);
call 0 returned 100%
-: 1186:
118: 1187: if (sitter != NULL)
branch 0 taken 100% (fallthrough)
branch 1 taken 0%
118: 1188: _dbus_babysitter_unref (sitter);
call 0 returned 100%
-: 1189:
118: 1190: return FALSE;
-: 1191:}
-: 1192:
-: 1193:/** @} */
-: 1194:
-: 1195:#ifdef DBUS_BUILD_TESTS
-: 1196:
-: 1197:static void
-: 1198:_dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
function _dbus_babysitter_block_for_child_exit called 184 returned 100% blocks executed 100%
184: 1199:{
1094: 1200: while (LIVE_CHILDREN (sitter))
branch 0 taken 80%
branch 1 taken 20% (fallthrough)
branch 2 taken 0%
branch 3 taken 100% (fallthrough)
726: 1201: babysitter_iteration (sitter, TRUE);
call 0 returned 100%
184: 1202:}
-: 1203:
-: 1204:static dbus_bool_t
-: 1205:check_spawn_nonexistent (void *data)
function check_spawn_nonexistent called 70 returned 100% blocks executed 76%
70: 1206:{
70: 1207: char *argv[4] = { NULL, NULL, NULL, NULL };
-: 1208: DBusBabysitter *sitter;
-: 1209: DBusError error;
-: 1210:
70: 1211: sitter = NULL;
-: 1212:
70: 1213: dbus_error_init (&error);
call 0 returned 100%
-: 1214:
-: 1215: /*** Test launching nonexistent binary */
-: 1216:
70: 1217: argv[0] = "/this/does/not/exist/32542sdgafgafdg";
70: 1218: if (_dbus_spawn_async_with_babysitter (&sitter, argv,
call 0 returned 100%
branch 1 taken 66% (fallthrough)
branch 2 taken 34%
-: 1219: NULL, NULL,
-: 1220: &error))
-: 1221: {
46: 1222: _dbus_babysitter_block_for_child_exit (sitter);
call 0 returned 100%
46: 1223: _dbus_babysitter_set_child_exit_error (sitter, &error);
call 0 returned 100%
-: 1224: }
-: 1225:
70: 1226: if (sitter)
branch 0 taken 66% (fallthrough)
branch 1 taken 34%
46: 1227: _dbus_babysitter_unref (sitter);
call 0 returned 100%
-: 1228:
70: 1229: if (!dbus_error_is_set (&error))
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
-: 1230: {
#####: 1231: _dbus_warn ("Did not get an error launching nonexistent executable\n");
call 0 never executed
#####: 1232: return FALSE;
-: 1233: }
-: 1234:
70: 1235: if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
call 0 returned 100%
branch 1 taken 49% (fallthrough)
branch 2 taken 51%
call 3 returned 100%
branch 4 taken 0% (fallthrough)
branch 5 taken 100%
-: 1236: dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
-: 1237: {
#####: 1238: _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
call 0 never executed
-: 1239: error.name, error.message);
#####: 1240: dbus_error_free (&error);
call 0 never executed
#####: 1241: return FALSE;
-: 1242: }
-: 1243:
70: 1244: dbus_error_free (&error);
call 0 returned 100%
-: 1245:
70: 1246: return TRUE;
-: 1247:}
-: 1248:
-: 1249:static dbus_bool_t
-: 1250:check_spawn_segfault (void *data)
function check_spawn_segfault called 70 returned 100% blocks executed 76%
70: 1251:{
70: 1252: char *argv[4] = { NULL, NULL, NULL, NULL };
-: 1253: DBusBabysitter *sitter;
-: 1254: DBusError error;
-: 1255:
70: 1256: sitter = NULL;
-: 1257:
70: 1258: dbus_error_init (&error);
call 0 returned 100%
-: 1259:
-: 1260: /*** Test launching segfault binary */
-: 1261:
70: 1262: argv[0] = TEST_SEGFAULT_BINARY;
70: 1263: if (_dbus_spawn_async_with_babysitter (&sitter, argv,
call 0 returned 100%
branch 1 taken 66% (fallthrough)
branch 2 taken 34%
-: 1264: NULL, NULL,
-: 1265: &error))
-: 1266: {
46: 1267: _dbus_babysitter_block_for_child_exit (sitter);
call 0 returned 100%
46: 1268: _dbus_babysitter_set_child_exit_error (sitter, &error);
call 0 returned 100%
-: 1269: }
-: 1270:
70: 1271: if (sitter)
branch 0 taken 66% (fallthrough)
branch 1 taken 34%
46: 1272: _dbus_babysitter_unref (sitter);
call 0 returned 100%
-: 1273:
70: 1274: if (!dbus_error_is_set (&error))
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
-: 1275: {
#####: 1276: _dbus_warn ("Did not get an error launching segfaulting binary\n");
call 0 never executed
#####: 1277: return FALSE;
-: 1278: }
-: 1279:
70: 1280: if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
call 0 returned 100%
branch 1 taken 49% (fallthrough)
branch 2 taken 51%
call 3 returned 100%
branch 4 taken 0% (fallthrough)
branch 5 taken 100%
-: 1281: dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
-: 1282: {
#####: 1283: _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
call 0 never executed
-: 1284: error.name, error.message);
#####: 1285: dbus_error_free (&error);
call 0 never executed
#####: 1286: return FALSE;
-: 1287: }
-: 1288:
70: 1289: dbus_error_free (&error);
call 0 returned 100%
-: 1290:
70: 1291: return TRUE;
-: 1292:}
-: 1293:
-: 1294:static dbus_bool_t
-: 1295:check_spawn_exit (void *data)
function check_spawn_exit called 70 returned 100% blocks executed 76%
70: 1296:{
70: 1297: char *argv[4] = { NULL, NULL, NULL, NULL };
-: 1298: DBusBabysitter *sitter;
-: 1299: DBusError error;
-: 1300:
70: 1301: sitter = NULL;
-: 1302:
70: 1303: dbus_error_init (&error);
call 0 returned 100%
-: 1304:
-: 1305: /*** Test launching exit failure binary */
-: 1306:
70: 1307: argv[0] = TEST_EXIT_BINARY;
70: 1308: if (_dbus_spawn_async_with_babysitter (&sitter, argv,
call 0 returned 100%
branch 1 taken 66% (fallthrough)
branch 2 taken 34%
-: 1309: NULL, NULL,
-: 1310: &error))
-: 1311: {
46: 1312: _dbus_babysitter_block_for_child_exit (sitter);
call 0 returned 100%
46: 1313: _dbus_babysitter_set_child_exit_error (sitter, &error);
call 0 returned 100%
-: 1314: }
-: 1315:
70: 1316: if (sitter)
branch 0 taken 66% (fallthrough)
branch 1 taken 34%
46: 1317: _dbus_babysitter_unref (sitter);
call 0 returned 100%
-: 1318:
70: 1319: if (!dbus_error_is_set (&error))
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
-: 1320: {
#####: 1321: _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
call 0 never executed
#####: 1322: return FALSE;
-: 1323: }
-: 1324:
70: 1325: if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
call 0 returned 100%
branch 1 taken 49% (fallthrough)
branch 2 taken 51%
call 3 returned 100%
branch 4 taken 0% (fallthrough)
branch 5 taken 100%
-: 1326: dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
-: 1327: {
#####: 1328: _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
call 0 never executed
-: 1329: error.name, error.message);
#####: 1330: dbus_error_free (&error);
call 0 never executed
#####: 1331: return FALSE;
-: 1332: }
-: 1333:
70: 1334: dbus_error_free (&error);
call 0 returned 100%
-: 1335:
70: 1336: return TRUE;
-: 1337:}
-: 1338:
-: 1339:static dbus_bool_t
-: 1340:check_spawn_and_kill (void *data)
function check_spawn_and_kill called 70 returned 100% blocks executed 77%
70: 1341:{
70: 1342: char *argv[4] = { NULL, NULL, NULL, NULL };
-: 1343: DBusBabysitter *sitter;
-: 1344: DBusError error;
-: 1345:
70: 1346: sitter = NULL;
-: 1347:
70: 1348: dbus_error_init (&error);
call 0 returned 100%
-: 1349:
-: 1350: /*** Test launching sleeping binary then killing it */
-: 1351:
70: 1352: argv[0] = TEST_SLEEP_FOREVER_BINARY;
70: 1353: if (_dbus_spawn_async_with_babysitter (&sitter, argv,
call 0 returned 100%
branch 1 taken 66% (fallthrough)
branch 2 taken 34%
-: 1354: NULL, NULL,
-: 1355: &error))
-: 1356: {
46: 1357: _dbus_babysitter_kill_child (sitter);
call 0 returned 100%
-: 1358:
46: 1359: _dbus_babysitter_block_for_child_exit (sitter);
call 0 returned 100%
-: 1360:
46: 1361: _dbus_babysitter_set_child_exit_error (sitter, &error);
call 0 returned 100%
-: 1362: }
-: 1363:
70: 1364: if (sitter)
branch 0 taken 66% (fallthrough)
branch 1 taken 34%
46: 1365: _dbus_babysitter_unref (sitter);
call 0 returned 100%
-: 1366:
70: 1367: if (!dbus_error_is_set (&error))
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
-: 1368: {
#####: 1369: _dbus_warn ("Did not get an error after killing spawned binary\n");
call 0 never executed
#####: 1370: return FALSE;
-: 1371: }
-: 1372:
70: 1373: if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
call 0 returned 100%
branch 1 taken 49% (fallthrough)
branch 2 taken 51%
call 3 returned 100%
branch 4 taken 0% (fallthrough)
branch 5 taken 100%
-: 1374: dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
-: 1375: {
#####: 1376: _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
call 0 never executed
-: 1377: error.name, error.message);
#####: 1378: dbus_error_free (&error);
call 0 never executed
#####: 1379: return FALSE;
-: 1380: }
-: 1381:
70: 1382: dbus_error_free (&error);
call 0 returned 100%
-: 1383:
70: 1384: return TRUE;
-: 1385:}
-: 1386:
-: 1387:dbus_bool_t
-: 1388:_dbus_spawn_test (const char *test_data_dir)
function _dbus_spawn_test called 1 returned 100% blocks executed 71%
1: 1389:{
1: 1390: if (!_dbus_test_oom_handling ("spawn_nonexistent",
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
-: 1391: check_spawn_nonexistent,
-: 1392: NULL))
#####: 1393: return FALSE;
-: 1394:
1: 1395: if (!_dbus_test_oom_handling ("spawn_segfault",
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
-: 1396: check_spawn_segfault,
-: 1397: NULL))
#####: 1398: return FALSE;
-: 1399:
1: 1400: if (!_dbus_test_oom_handling ("spawn_exit",
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
-: 1401: check_spawn_exit,
-: 1402: NULL))
#####: 1403: return FALSE;
-: 1404:
1: 1405: if (!_dbus_test_oom_handling ("spawn_and_kill",
call 0 returned 100%
branch 1 taken 0% (fallthrough)
branch 2 taken 100%
-: 1406: check_spawn_and_kill,
-: 1407: NULL))
#####: 1408: return FALSE;
-: 1409:
1: 1410: return TRUE;
-: 1411:}
-: 1412:#endif