index.html
Main Page
|
modules.html
Modules
|
namespaces.html
Namespace List
|
hierarchy.html
Class Hierarchy
|
annotated.html
Data Structures
|
dirs.html
Directories
|
files.html
File List
|
namespacemembers.html
Namespace Members
|
functions.html
Data Fields
|
pages.html
Related Pages
dir_000004.html
dbus
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
group__DBusInternalsUtils.html#ga159
00050
typedef
enum
00051 {
00052
group__DBusInternalsUtils.html#gga159a4
READ_STATUS_OK
,
00053
group__DBusInternalsUtils.html#gga159a5
READ_STATUS_ERROR
,
group__DBusInternalsUtils.html#gga159a6
00054
group__DBusInternalsUtils.html#gga159a6
READ_STATUS_EOF
00055 }
group__DBusInternalsUtils.html#ga159
ReadStatus
;
00056
00057
static
group__DBusInternalsUtils.html#ga159
ReadStatus
00058 read_ints (
int
fd,
00059
int
*buf,
00060
int
n_ints_in_buf,
00061
int
*n_ints_read,
00062
structDBusError.html
DBusError
*error)
00063 {
00064   size_t bytes = 0;
00065
group__DBusInternalsUtils.html#ga159
ReadStatus
retval;
00066
00067   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00068
00069   retval =
group__DBusInternalsUtils.html#gga159a4
READ_STATUS_OK
;
00070
00071
while
(
group__DBusMacros.html#ga2
TRUE
)
00072     {
00073       size_t chunk;
00074       size_t to_read;
00075
00076       to_read =
sizeof
(int) * n_ints_in_buf - bytes;
00077
00078
if
(to_read == 0)
00079
break
;
00080
00081     again:
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
group__DBusErrors.html#ga6
dbus_set_error
(error,
00093                           DBUS_ERROR_SPAWN_FAILED,
00094
"Failed to read from child pipe (%s)"
,
00095
group__DBusInternalsUtils.html#ga96
_dbus_strerror
(errno));
00096
00097           retval =
group__DBusInternalsUtils.html#gga159a5
READ_STATUS_ERROR
;
00098
break
;
00099         }
00100
else
if
(chunk == 0)
00101         {
00102           retval =
group__DBusInternalsUtils.html#gga159a6
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
group__DBusInternalsUtils.html#ga159
ReadStatus
00115 read_pid (
int
fd,
00116           pid_t     *buf,
00117
structDBusError.html
DBusError
*error)
00118 {
00119   size_t bytes = 0;
00120
group__DBusInternalsUtils.html#ga159
ReadStatus
retval;
00121
00122   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00123
00124   retval =
group__DBusInternalsUtils.html#gga159a4
READ_STATUS_OK
;
00125
00126
while
(
group__DBusMacros.html#ga2
TRUE
)
00127     {
00128       size_t chunk;
00129       size_t to_read;
00130
00131       to_read =
sizeof
(pid_t) - bytes;
00132
00133
if
(to_read == 0)
00134
break
;
00135
00136     again:
00137
00138       chunk = read (fd,
00139                     ((
char
*)buf) + bytes,
00140                     to_read);
00141
if
(chunk < 0 && errno == EINTR)
00142
goto
again;
00143
00144
if
(chunk < 0)
00145         {
00146
group__DBusErrors.html#ga6
dbus_set_error
(error,
00147                           DBUS_ERROR_SPAWN_FAILED,
00148
"Failed to read from child pipe (%s)"
,
00149
group__DBusInternalsUtils.html#ga96
_dbus_strerror
(errno));
00150
00151           retval =
group__DBusInternalsUtils.html#gga159a5
READ_STATUS_ERROR
;
00152
break
;
00153         }
00154
else
if
(chunk == 0)
00155         {
00156           retval =
group__DBusInternalsUtils.html#gga159a6
READ_STATUS_EOF
;
00157
break
;
/* EOF */
00158         }
00159
else
/* chunk > 0 */
00160         bytes += chunk;
00161     }
00162
00163
return
retval;
00164 }
00165
00166
/* The implementation uses an intermediate child between the main process
00167
* and the grandchild. The grandchild is our spawned process. The intermediate
00168
* child is a babysitter process; it keeps track of when the grandchild
00169
* exits/crashes, and reaps the grandchild.
00170
*/
00171
00172
/* Messages from children to parents */
00173
enum
00174 {
00175   CHILD_EXITED,
/* This message is followed by the exit status int */
00176   CHILD_FORK_FAILED,
/* Followed by errno */
00177   CHILD_EXEC_FAILED,
/* Followed by errno */
00178   CHILD_PID
/* Followed by pid_t */
00179 };
00180
structDBusBabysitter.html
00184
struct
structDBusBabysitter.html
DBusBabysitter
00185 {
structDBusBabysitter.html#o0
00186
int
structDBusBabysitter.html#o0
refcount
;
structDBusBabysitter.html#o1
00188
char
*
structDBusBabysitter.html#o1
executable
;
structDBusBabysitter.html#o2
00190
int
structDBusBabysitter.html#o2
socket_to_babysitter
;
structDBusBabysitter.html#o3
00191
int
structDBusBabysitter.html#o3
error_pipe_from_child
;
structDBusBabysitter.html#o4
00193
pid_t
structDBusBabysitter.html#o4
sitter_pid
;
structDBusBabysitter.html#o5
00194
pid_t
structDBusBabysitter.html#o5
grandchild_pid
;
structDBusBabysitter.html#o6
00196
structDBusWatchList.html
DBusWatchList
*
structDBusBabysitter.html#o6
watches
;
structDBusBabysitter.html#o7
00198
structDBusWatch.html
DBusWatch
*
structDBusBabysitter.html#o7
error_watch
;
structDBusBabysitter.html#o8
00199
structDBusWatch.html
DBusWatch
*
structDBusBabysitter.html#o8
sitter_watch
;
structDBusBabysitter.html#o9
00201
int
structDBusBabysitter.html#o9
errnum
;
structDBusBabysitter.html#o10
00202
int
structDBusBabysitter.html#o10
status
;
structDBusBabysitter.html#o11
00203
unsigned
int
structDBusBabysitter.html#o11
have_child_status
: 1;
structDBusBabysitter.html#o12
00204
unsigned
int
structDBusBabysitter.html#o12
have_fork_errnum
: 1;
structDBusBabysitter.html#o13
00205
unsigned
int
structDBusBabysitter.html#o13
have_exec_errnum
: 1;
00206 };
00207
00208
static
structDBusBabysitter.html
DBusBabysitter
*
00209 _dbus_babysitter_new (
void
)
00210 {
00211
structDBusBabysitter.html
DBusBabysitter
*sitter;
00212
00213   sitter =
group__DBusMemory.html#ga7
dbus_new0
(
structDBusBabysitter.html
DBusBabysitter
, 1);
00214
if
(sitter ==
group__DBusMacros.html#ga4
NULL
)
00215
return
group__DBusMacros.html#ga4
NULL
;
00216
00217   sitter->
structDBusBabysitter.html#o0
refcount
= 1;
00218
00219   sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
= -1;
00220   sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
= -1;
00221
00222   sitter->
structDBusBabysitter.html#o4
sitter_pid
= -1;
00223   sitter->
structDBusBabysitter.html#o5
grandchild_pid
= -1;
00224
00225   sitter->
structDBusBabysitter.html#o6
watches
=
group__DBusWatchInternals.html#ga5
_dbus_watch_list_new
();
00226
if
(sitter->
structDBusBabysitter.html#o6
watches
==
group__DBusMacros.html#ga4
NULL
)
00227
goto
failed;
00228
00229
return
sitter;
00230
00231  failed:
00232
group__DBusInternalsUtils.html#ga16
_dbus_babysitter_unref
(sitter);
00233
return
group__DBusMacros.html#ga4
NULL
;
00234 }
00235
00242
structDBusBabysitter.html
DBusBabysitter
*
group__DBusInternalsUtils.html#ga15
00243
group__DBusInternalsUtils.html#ga15
_dbus_babysitter_ref
(
structDBusBabysitter.html
DBusBabysitter
*sitter)
00244 {
00245
group__DBusInternalsUtils.html#ga130
_dbus_assert
(sitter !=
group__DBusMacros.html#ga4
NULL
);
00246
group__DBusInternalsUtils.html#ga130
_dbus_assert
(sitter->
structDBusBabysitter.html#o0
refcount
> 0);
00247
00248   sitter->
structDBusBabysitter.html#o0
refcount
+= 1;
00249
00250
return
sitter;
00251 }
00252
00261
void
group__DBusInternalsUtils.html#ga16
00262
group__DBusInternalsUtils.html#ga16
_dbus_babysitter_unref
(
structDBusBabysitter.html
DBusBabysitter
*sitter)
00263 {
00264
group__DBusInternalsUtils.html#ga130
_dbus_assert
(sitter !=
group__DBusMacros.html#ga4
NULL
);
00265
group__DBusInternalsUtils.html#ga130
_dbus_assert
(sitter->
structDBusBabysitter.html#o0
refcount
> 0);
00266
00267   sitter->
structDBusBabysitter.html#o0
refcount
-= 1;
00268
if
(sitter->
structDBusBabysitter.html#o0
refcount
== 0)
00269     {
00270
if
(sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
>= 0)
00271         {
00272
/* If we haven't forked other babysitters
00273
* since this babysitter and socket were
00274
* created then this close will cause the
00275
* babysitter to wake up from poll with
00276
* a hangup and then the babysitter will
00277
* quit itself.
00278
*/
00279           close (sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
);
00280           sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
= -1;
00281         }
00282
00283
if
(sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
>= 0)
00284         {
00285           close (sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
);
00286           sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
= -1;
00287         }
00288
00289
if
(sitter->
structDBusBabysitter.html#o4
sitter_pid
> 0)
00290         {
00291
int
status;
00292
int
ret;
00293
00294
/* It's possible the babysitter died on its own above
00295
* from the close, or was killed randomly
00296
* by some other process, so first try to reap it
00297
*/
00298           ret = waitpid (sitter->
structDBusBabysitter.html#o4
sitter_pid
, &status, WNOHANG);
00299
00300
/* If we couldn't reap the child then kill it, and
00301
* try again
00302
*/
00303
if
(ret == 0)
00304             kill (sitter->
structDBusBabysitter.html#o4
sitter_pid
, SIGKILL);
00305
00306         again:
00307
if
(ret == 0)
00308             ret = waitpid (sitter->
structDBusBabysitter.html#o4
sitter_pid
, &status, 0);
00309
00310
if
(ret < 0)
00311             {
00312
if
(errno == EINTR)
00313
goto
again;
00314
else
if
(errno == ECHILD)
00315
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Babysitter process not available to be reaped; should not happen\n"
);
00316
else
00317
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Unexpected error %d in waitpid() for babysitter: %s\n"
,
00318                             errno,
group__DBusInternalsUtils.html#ga96
_dbus_strerror
(errno));
00319             }
00320
else
00321             {
00322               _dbus_verbose (
"Reaped %ld, waiting for babysitter %ld\n"
,
00323                              (
long
) ret, (
long
) sitter->
structDBusBabysitter.html#o4
sitter_pid
);
00324
00325
if
(WIFEXITED (sitter->
structDBusBabysitter.html#o10
status
))
00326                 _dbus_verbose (
"Babysitter exited with status %d\n"
,
00327                                WEXITSTATUS (sitter->
structDBusBabysitter.html#o10
status
));
00328
else
if
(WIFSIGNALED (sitter->
structDBusBabysitter.html#o10
status
))
00329                 _dbus_verbose (
"Babysitter received signal %d\n"
,
00330                                WTERMSIG (sitter->
structDBusBabysitter.html#o10
status
));
00331
else
00332                 _dbus_verbose (
"Babysitter exited abnormally\n"
);
00333             }
00334
00335           sitter->
structDBusBabysitter.html#o4
sitter_pid
= -1;
00336         }
00337
00338
if
(sitter->
structDBusBabysitter.html#o7
error_watch
)
00339         {
00340
group__DBusWatchInternals.html#ga3
_dbus_watch_invalidate
(sitter->
structDBusBabysitter.html#o7
error_watch
);
00341
group__DBusWatchInternals.html#ga2
_dbus_watch_unref
(sitter->
structDBusBabysitter.html#o7
error_watch
);
00342           sitter->
structDBusBabysitter.html#o7
error_watch
=
group__DBusMacros.html#ga4
NULL
;
00343         }
00344
00345
if
(sitter->
structDBusBabysitter.html#o8
sitter_watch
)
00346         {
00347
group__DBusWatchInternals.html#ga3
_dbus_watch_invalidate
(sitter->
structDBusBabysitter.html#o8
sitter_watch
);
00348
group__DBusWatchInternals.html#ga2
_dbus_watch_unref
(sitter->
structDBusBabysitter.html#o8
sitter_watch
);
00349           sitter->
structDBusBabysitter.html#o8
sitter_watch
=
group__DBusMacros.html#ga4
NULL
;
00350         }
00351
00352
if
(sitter->
structDBusBabysitter.html#o6
watches
)
00353
group__DBusWatchInternals.html#ga6
_dbus_watch_list_free
(sitter->
structDBusBabysitter.html#o6
watches
);
00354
00355
group__DBusMemory.html#ga3
dbus_free
(sitter->
structDBusBabysitter.html#o1
executable
);
00356
00357
group__DBusMemory.html#ga3
dbus_free
(sitter);
00358     }
00359 }
00360
00361
static
group__DBusInternalsUtils.html#ga159
ReadStatus
00362 read_data (
structDBusBabysitter.html
DBusBabysitter
*sitter,
00363
int
fd)
00364 {
00365
int
what;
00366
int
got;
00367
structDBusError.html
DBusError
error;
00368
group__DBusInternalsUtils.html#ga159
ReadStatus
r;
00369
00370
group__DBusErrors.html#ga0
dbus_error_init
(&error);
00371
00372   r = read_ints (fd, &what, 1, &got, &error);
00373
00374
switch
(r)
00375     {
00376
case
group__DBusInternalsUtils.html#gga159a5
READ_STATUS_ERROR
:
00377
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Failed to read data from fd %d: %s\n"
, fd, error.
structDBusError.html#o1
message
);
00378
group__DBusErrors.html#ga1
dbus_error_free
(&error);
00379
return
r;
00380
00381
case
group__DBusInternalsUtils.html#gga159a6
READ_STATUS_EOF
:
00382
return
r;
00383
00384
case
group__DBusInternalsUtils.html#gga159a4
READ_STATUS_OK
:
00385
break
;
00386     }
00387
00388
if
(got == 1)
00389     {
00390
switch
(what)
00391         {
00392
case
CHILD_EXITED:
00393
case
CHILD_FORK_FAILED:
00394
case
CHILD_EXEC_FAILED:
00395           {
00396
int
arg;
00397
00398             r = read_ints (fd, &arg, 1, &got, &error);
00399
00400
switch
(r)
00401               {
00402
case
group__DBusInternalsUtils.html#gga159a5
READ_STATUS_ERROR
:
00403
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Failed to read arg from fd %d: %s\n"
, fd, error.
structDBusError.html#o1
message
);
00404
group__DBusErrors.html#ga1
dbus_error_free
(&error);
00405
return
r;
00406
case
group__DBusInternalsUtils.html#gga159a6
READ_STATUS_EOF
:
00407
return
r;
00408
case
group__DBusInternalsUtils.html#gga159a4
READ_STATUS_OK
:
00409
break
;
00410               }
00411
00412
if
(got == 1)
00413               {
00414
if
(what == CHILD_EXITED)
00415                   {
00416                     sitter->
structDBusBabysitter.html#o11
have_child_status
=
group__DBusMacros.html#ga2
TRUE
;
00417                     sitter->
structDBusBabysitter.html#o10
status
= arg;
00418                     _dbus_verbose (
"recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n"
,
00419                                    WIFEXITED (sitter->
structDBusBabysitter.html#o10
status
), WIFSIGNALED (sitter->
structDBusBabysitter.html#o10
status
),
00420                                    WEXITSTATUS (sitter->
structDBusBabysitter.html#o10
status
), WTERMSIG (sitter->
structDBusBabysitter.html#o10
status
));
00421                   }
00422
else
if
(what == CHILD_FORK_FAILED)
00423                   {
00424                     sitter->
structDBusBabysitter.html#o12
have_fork_errnum
=
group__DBusMacros.html#ga2
TRUE
;
00425                     sitter->
structDBusBabysitter.html#o9
errnum
= arg;
00426                     _dbus_verbose (
"recorded fork errnum %d\n"
, sitter->
structDBusBabysitter.html#o9
errnum
);
00427                   }
00428
else
if
(what == CHILD_EXEC_FAILED)
00429                   {
00430                     sitter->
structDBusBabysitter.html#o13
have_exec_errnum
=
group__DBusMacros.html#ga2
TRUE
;
00431                     sitter->
structDBusBabysitter.html#o9
errnum
= arg;
00432                     _dbus_verbose (
"recorded exec errnum %d\n"
, sitter->
structDBusBabysitter.html#o9
errnum
);
00433                   }
00434               }
00435           }
00436
break
;
00437
case
CHILD_PID:
00438           {
00439             pid_t pid = -1;
00440
00441             r = read_pid (fd, &pid, &error);
00442
00443
switch
(r)
00444               {
00445
case
group__DBusInternalsUtils.html#gga159a5
READ_STATUS_ERROR
:
00446
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Failed to read PID from fd %d: %s\n"
, fd, error.
structDBusError.html#o1
message
);
00447
group__DBusErrors.html#ga1
dbus_error_free
(&error);
00448
return
r;
00449
case
group__DBusInternalsUtils.html#gga159a6
READ_STATUS_EOF
:
00450
return
r;
00451
case
group__DBusInternalsUtils.html#gga159a4
READ_STATUS_OK
:
00452
break
;
00453               }
00454
00455             sitter->
structDBusBabysitter.html#o5
grandchild_pid
= pid;
00456
00457             _dbus_verbose (
"recorded grandchild pid %d\n"
, sitter->
structDBusBabysitter.html#o5
grandchild_pid
);
00458           }
00459
break
;
00460
default
:
00461
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Unknown message received from babysitter process\n"
);
00462
break
;
00463         }
00464     }
00465
00466
return
r;
00467 }
00468
00469
static
void
00470 close_socket_to_babysitter (
structDBusBabysitter.html
DBusBabysitter
*sitter)
00471 {
00472   _dbus_verbose (
"Closing babysitter\n"
);
00473   close (sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
);
00474   sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
= -1;
00475 }
00476
00477
static
void
00478 close_error_pipe_from_child (
structDBusBabysitter.html
DBusBabysitter
*sitter)
00479 {
00480   _dbus_verbose (
"Closing child error\n"
);
00481   close (sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
);
00482   sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
= -1;
00483 }
00484
00485
static
void
00486 handle_babysitter_socket (
structDBusBabysitter.html
DBusBabysitter
*sitter,
00487
int
revents)
00488 {
00489
/* Even if we have POLLHUP, we want to keep reading
00490
* data until POLLIN goes away; so this function only
00491
* looks at HUP/ERR if no IN is set.
00492
*/
00493
if
(revents & _DBUS_POLLIN)
00494     {
00495       _dbus_verbose (
"Reading data from babysitter\n"
);
00496
if
(read_data (sitter, sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
) !=
group__DBusInternalsUtils.html#gga159a4
READ_STATUS_OK
)
00497         close_socket_to_babysitter (sitter);
00498     }
00499
else
if
(revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00500     {
00501       close_socket_to_babysitter (sitter);
00502     }
00503 }
00504
00505
static
void
00506 handle_error_pipe (
structDBusBabysitter.html
DBusBabysitter
*sitter,
00507
int
revents)
00508 {
00509
if
(revents & _DBUS_POLLIN)
00510     {
00511       _dbus_verbose (
"Reading data from child error\n"
);
00512
if
(read_data (sitter, sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
) !=
group__DBusInternalsUtils.html#gga159a4
READ_STATUS_OK
)
00513         close_error_pipe_from_child (sitter);
00514     }
00515
else
if
(revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00516     {
00517       close_error_pipe_from_child (sitter);
00518     }
00519 }
00520
00521
/* returns whether there were any poll events handled */
00522
static
group__DBusTypes.html#ga2
dbus_bool_t
00523 babysitter_iteration (
structDBusBabysitter.html
DBusBabysitter
*sitter,
00524
group__DBusTypes.html#ga2
dbus_bool_t
block)
00525 {
00526
structDBusPollFD.html
DBusPollFD
fds[2];
00527
int
i;
00528
group__DBusTypes.html#ga2
dbus_bool_t
descriptors_ready;
00529
00530   descriptors_ready =
group__DBusMacros.html#ga3
FALSE
;
00531
00532   i = 0;
00533
00534
if
(sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
>= 0)
00535     {
00536       fds[i].
structDBusPollFD.html#o0
fd
= sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
;
00537       fds[i].
structDBusPollFD.html#o1
events
= _DBUS_POLLIN;
00538       fds[i].
structDBusPollFD.html#o2
revents
= 0;
00539       ++i;
00540     }
00541
00542
if
(sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
>= 0)
00543     {
00544       fds[i].
structDBusPollFD.html#o0
fd
= sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
;
00545       fds[i].
structDBusPollFD.html#o1
events
= _DBUS_POLLIN;
00546       fds[i].
structDBusPollFD.html#o2
revents
= 0;
00547       ++i;
00548     }
00549
00550
if
(i > 0)
00551     {
00552
int
ret;
00553
00554       ret =
group__DBusInternalsUtils.html#ga82
_dbus_poll
(fds, i, 0);
00555
if
(ret == 0 && block)
00556         ret =
group__DBusInternalsUtils.html#ga82
_dbus_poll
(fds, i, -1);
00557
00558
if
(ret > 0)
00559         {
00560           descriptors_ready =
group__DBusMacros.html#ga2
TRUE
;
00561
00562
while
(i > 0)
00563             {
00564               --i;
00565
if
(fds[i].fd == sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
)
00566                 handle_error_pipe (sitter, fds[i].revents);
00567
else
if
(fds[i].fd == sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
)
00568                 handle_babysitter_socket (sitter, fds[i].revents);
00569             }
00570         }
00571     }
00572
00573
return
descriptors_ready;
00574 }
00575
group__DBusInternalsUtils.html#ga150
00580
#define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter >= 0 || (sitter)->error_pipe_from_child >= 0)
00581
00588
void
group__DBusInternalsUtils.html#ga23
00589
group__DBusInternalsUtils.html#ga23
_dbus_babysitter_kill_child
(
structDBusBabysitter.html
DBusBabysitter
*sitter)
00590 {
00591
/* be sure we have the PID of the child */
00592
while
(
group__DBusInternalsUtils.html#ga150
LIVE_CHILDREN
(sitter) &&
00593          sitter->grandchild_pid == -1)
00594     babysitter_iteration (sitter,
group__DBusMacros.html#ga2
TRUE
);
00595
00596   _dbus_verbose (
"Got child PID %ld for killing\n"
,
00597                  (
long
) sitter->grandchild_pid);
00598
00599
if
(sitter->grandchild_pid == -1)
00600
return
;
/* child is already dead, or we're so hosed we'll never recover */
00601
00602   kill (sitter->grandchild_pid, SIGKILL);
00603 }
00604
00610
group__DBusTypes.html#ga2
dbus_bool_t
group__DBusInternalsUtils.html#ga24
00611
group__DBusInternalsUtils.html#ga24
_dbus_babysitter_get_child_exited
(
structDBusBabysitter.html
DBusBabysitter
*sitter)
00612 {
00613
00614
/* Be sure we're up-to-date */
00615
while
(
group__DBusInternalsUtils.html#ga150
LIVE_CHILDREN
(sitter) &&
00616          babysitter_iteration (sitter,
group__DBusMacros.html#ga3
FALSE
))
00617     ;
00618
00619
/* We will have exited the babysitter when the child has exited */
00620
return
sitter->socket_to_babysitter < 0;
00621 }
00622
00632
void
group__DBusInternalsUtils.html#ga25
00633
group__DBusInternalsUtils.html#ga25
_dbus_babysitter_set_child_exit_error
(
structDBusBabysitter.html
DBusBabysitter
*sitter,
00634
structDBusError.html
DBusError
*error)
00635 {
00636
if
(!
group__DBusInternalsUtils.html#ga24
_dbus_babysitter_get_child_exited
(sitter))
00637
return
;
00638
00639
/* Note that if exec fails, we will also get a child status
00640
* from the babysitter saying the child exited,
00641
* so we need to give priority to the exec error
00642
*/
00643
if
(sitter->have_exec_errnum)
00644     {
00645
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00646
"Failed to execute program %s: %s"
,
00647                       sitter->executable,
group__DBusInternalsUtils.html#ga96
_dbus_strerror
(sitter->errnum));
00648     }
00649
else
if
(sitter->have_fork_errnum)
00650     {
00651
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_NO_MEMORY,
00652
"Failed to fork a new process %s: %s"
,
00653                       sitter->executable,
group__DBusInternalsUtils.html#ga96
_dbus_strerror
(sitter->errnum));
00654     }
00655
else
if
(sitter->have_child_status)
00656     {
00657
if
(WIFEXITED (sitter->status))
00658
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00659
"Process %s exited with status %d"
,
00660                         sitter->executable, WEXITSTATUS (sitter->status));
00661
else
if
(WIFSIGNALED (sitter->status))
00662
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,
00663
"Process %s received signal %d"
,
00664                         sitter->executable, WTERMSIG (sitter->status));
00665
else
00666
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_FAILED,
00667
"Process %s exited abnormally"
,
00668                         sitter->executable);
00669     }
00670
else
00671     {
00672
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_FAILED,
00673
"Process %s exited, reason unknown"
,
00674                       sitter->executable);
00675     }
00676 }
00677
00690
group__DBusTypes.html#ga2
dbus_bool_t
group__DBusInternalsUtils.html#ga26
00691
group__DBusInternalsUtils.html#ga26
_dbus_babysitter_set_watch_functions
(
structDBusBabysitter.html
DBusBabysitter
*sitter,
00692                                       DBusAddWatchFunction       add_function,
00693                                       DBusRemoveWatchFunction    remove_function,
00694                                       DBusWatchToggledFunction   toggled_function,
00695
void
*data,
00696
group__DBusMemory.html#ga8
DBusFreeFunction
free_data_function)
00697 {
00698
return
group__DBusWatchInternals.html#ga7
_dbus_watch_list_set_functions
(sitter->
structDBusBabysitter.html#o6
watches
,
00699                                          add_function,
00700                                          remove_function,
00701                                          toggled_function,
00702                                          data,
00703                                          free_data_function);
00704 }
00705
00706
static
group__DBusTypes.html#ga2
dbus_bool_t
00707 handle_watch (
structDBusWatch.html
DBusWatch
*watch,
00708
unsigned
int
condition,
00709
void
*data)
00710 {
00711
structDBusBabysitter.html
DBusBabysitter
*sitter = data;
00712
int
revents;
00713
int
fd;
00714
00715   revents = 0;
00716
if
(condition & DBUS_WATCH_READABLE)
00717     revents |= _DBUS_POLLIN;
00718
if
(condition & DBUS_WATCH_ERROR)
00719     revents |= _DBUS_POLLERR;
00720
if
(condition & DBUS_WATCH_HANGUP)
00721     revents |= _DBUS_POLLHUP;
00722
00723   fd =
group__DBusWatch.html#ga0
dbus_watch_get_fd
(watch);
00724
00725
if
(fd == sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
)
00726     handle_error_pipe (sitter, revents);
00727
else
if
(fd == sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
)
00728     handle_babysitter_socket (sitter, revents);
00729
00730
while
(
group__DBusInternalsUtils.html#ga150
LIVE_CHILDREN
(sitter) &&
00731          babysitter_iteration (sitter,
group__DBusMacros.html#ga3
FALSE
))
00732     ;
00733
00734
return
group__DBusMacros.html#ga2
TRUE
;
00735 }
00736
group__DBusInternalsUtils.html#ga151
00738
#define READ_END 0
00739
group__DBusInternalsUtils.html#ga152
00740
#define WRITE_END 1
00741
00742
00743
/* Avoids a danger in threaded situations (calling close()
00744
* on a file descriptor twice, and another thread has
00745
* re-opened it since the first close)
00746
*/
00747
static
int
00748 close_and_invalidate (
int
*fd)
00749 {
00750
int
ret;
00751
00752
if
(*fd < 0)
00753
return
-1;
00754
else
00755     {
00756       ret = close (*fd);
00757       *fd = -1;
00758     }
00759
00760
return
ret;
00761 }
00762
00763
static
group__DBusTypes.html#ga2
dbus_bool_t
00764 make_pipe (
int
p[2],
00765
structDBusError.html
DBusError
*error)
00766 {
00767   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00768
00769
if
(pipe (p) < 0)
00770     {
00771
group__DBusErrors.html#ga6
dbus_set_error
(error,
00772                       DBUS_ERROR_SPAWN_FAILED,
00773
"Failed to create pipe for communicating with child process (%s)"
,
00774
group__DBusInternalsUtils.html#ga96
_dbus_strerror
(errno));
00775
return
group__DBusMacros.html#ga3
FALSE
;
00776     }
00777
00778
return
group__DBusMacros.html#ga2
TRUE
;
00779 }
00780
00781
static
void
00782 do_write (
int
fd,
const
void
*buf, size_t count)
00783 {
00784   size_t bytes_written;
00785
int
ret;
00786
00787   bytes_written = 0;
00788
00789  again:
00790
00791   ret = write (fd, ((
const
char
*)buf) + bytes_written, count - bytes_written);
00792
00793
if
(ret < 0)
00794     {
00795
if
(errno == EINTR)
00796
goto
again;
00797
else
00798         {
00799
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Failed to write data to pipe!\n"
);
00800           exit (1);
/* give up, we suck */
00801         }
00802     }
00803
else
00804     bytes_written += ret;
00805
00806
if
(bytes_written < count)
00807
goto
again;
00808 }
00809
00810
static
void
00811 write_err_and_exit (
int
fd,
int
msg)
00812 {
00813
int
en = errno;
00814
00815   do_write (fd, &msg,
sizeof
(msg));
00816   do_write (fd, &en,
sizeof
(en));
00817
00818   exit (1);
00819 }
00820
00821
static
void
00822 write_pid (
int
fd, pid_t pid)
00823 {
00824
int
msg = CHILD_PID;
00825
00826   do_write (fd, &msg,
sizeof
(msg));
00827   do_write (fd, &pid,
sizeof
(pid));
00828 }
00829
00830
static
void
00831 write_status_and_exit (
int
fd,
int
status)
00832 {
00833
int
msg = CHILD_EXITED;
00834
00835   do_write (fd, &msg,
sizeof
(msg));
00836   do_write (fd, &status,
sizeof
(status));
00837
00838   exit (0);
00839 }
00840
00841
static
void
00842 do_exec (
int
child_err_report_fd,
00843
char
**argv,
00844          DBusSpawnChildSetupFunc   child_setup,
00845
void
*user_data)
00846 {
00847
#ifdef DBUS_BUILD_TESTS
00848
int
i, max_open;
00849
#endif
00850
00851   _dbus_verbose_reset ();
00852   _dbus_verbose (
"Child process has PID %lu\n"
,
00853
group__DBusInternalsUtils.html#ga77
_dbus_getpid
());
00854
00855
if
(child_setup)
00856     (* child_setup) (user_data);
00857
00858
#ifdef DBUS_BUILD_TESTS
00859
max_open = sysconf (_SC_OPEN_MAX);
00860
00861
for
(i = 3; i < max_open; i++)
00862     {
00863
int
retval;
00864
00865
if
(i == child_err_report_fd)
00866
continue
;
00867
00868       retval = fcntl (i, F_GETFD);
00869
00870
if
(retval != -1 && !(retval & FD_CLOEXEC))
00871
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Fd %d did not have the close-on-exec flag set!\n"
, i);
00872     }
00873
#endif
00874
00875   execv (argv[0], argv);
00876
00877
/* Exec failed */
00878   write_err_and_exit (child_err_report_fd,
00879                       CHILD_EXEC_FAILED);
00880 }
00881
00882
static
void
00883 check_babysit_events (pid_t grandchild_pid,
00884
int
parent_pipe,
00885
int
revents)
00886 {
00887   pid_t ret;
00888
int
status;
00889
00890
do
00891     {
00892       ret = waitpid (grandchild_pid, &status, WNOHANG);
00893
/* The man page says EINTR can't happen with WNOHANG,
00894
* but there are reports of it (maybe only with valgrind?)
00895
*/
00896     }
00897
while
(ret < 0 && errno == EINTR);
00898
00899
if
(ret == 0)
00900     {
00901       _dbus_verbose (
"no child exited\n"
);
00902
00903       ;
/* no child exited */
00904     }
00905
else
if
(ret < 0)
00906     {
00907
/* This isn't supposed to happen. */
00908
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"unexpected waitpid() failure in check_babysit_events(): %s\n"
,
00909
group__DBusInternalsUtils.html#ga96
_dbus_strerror
(errno));
00910       exit (1);
00911     }
00912
else
if
(ret == grandchild_pid)
00913     {
00914
/* Child exited */
00915       _dbus_verbose (
"reaped child pid %ld\n"
, (
long
) ret);
00916
00917       write_status_and_exit (parent_pipe, status);
00918     }
00919
else
00920     {
00921
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"waitpid() reaped pid %d that we've never heard of\n"
,
00922                   (
int
) ret);
00923       exit (1);
00924     }
00925
00926
if
(revents & _DBUS_POLLIN)
00927     {
00928       _dbus_verbose (
"babysitter got POLLIN from parent pipe\n"
);
00929     }
00930
00931
if
(revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00932     {
00933
/* Parent is gone, so we just exit */
00934       _dbus_verbose (
"babysitter got POLLERR or POLLHUP from parent\n"
);
00935       exit (0);
00936     }
00937 }
00938
00939
static
int
babysit_sigchld_pipe = -1;
00940
00941
static
void
00942 babysit_signal_handler (
int
signo)
00943 {
00944
char
b =
'\0'
;
00945  again:
00946   write (babysit_sigchld_pipe, &b, 1);
00947
if
(errno == EINTR)
00948
goto
again;
00949 }
00950
00951
static
void
00952 babysit (pid_t grandchild_pid,
00953
int
parent_pipe)
00954 {
00955
int
sigchld_pipe[2];
00956
00957
/* We don't exec, so we keep parent state, such as the pid that
00958
* _dbus_verbose() uses. Reset the pid here.
00959
*/
00960   _dbus_verbose_reset ();
00961
00962
/* I thought SIGCHLD would just wake up the poll, but
00963
* that didn't seem to work, so added this pipe.
00964
* Probably the pipe is more likely to work on busted
00965
* operating systems anyhow.
00966
*/
00967
if
(pipe (sigchld_pipe) < 0)
00968     {
00969
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Not enough file descriptors to create pipe in babysitter process\n"
);
00970       exit (1);
00971     }
00972
00973   babysit_sigchld_pipe = sigchld_pipe[
group__DBusInternalsUtils.html#ga152
WRITE_END
];
00974
00975
group__DBusInternalsUtils.html#ga42
_dbus_set_signal_handler
(SIGCHLD, babysit_signal_handler);
00976
00977   write_pid (parent_pipe, grandchild_pid);
00978
00979   check_babysit_events (grandchild_pid, parent_pipe, 0);
00980
00981
while
(
group__DBusMacros.html#ga2
TRUE
)
00982     {
00983
structDBusPollFD.html
DBusPollFD
pfds[2];
00984
00985       pfds[0].
structDBusPollFD.html#o0
fd
= parent_pipe;
00986       pfds[0].
structDBusPollFD.html#o1
events
= _DBUS_POLLIN;
00987       pfds[0].
structDBusPollFD.html#o2
revents
= 0;
00988
00989       pfds[1].
structDBusPollFD.html#o0
fd
= sigchld_pipe[
group__DBusInternalsUtils.html#ga151
READ_END
];
00990       pfds[1].
structDBusPollFD.html#o1
events
= _DBUS_POLLIN;
00991       pfds[1].
structDBusPollFD.html#o2
revents
= 0;
00992
00993
group__DBusInternalsUtils.html#ga82
_dbus_poll
(pfds,
group__DBusInternalsUtils.html#ga132
_DBUS_N_ELEMENTS
(pfds), -1);
00994
00995
if
(pfds[0].revents != 0)
00996         {
00997           check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
00998         }
00999
else
if
(pfds[1].revents & _DBUS_POLLIN)
01000         {
01001
char
b;
01002           read (sigchld_pipe[
group__DBusInternalsUtils.html#ga151
READ_END
], &b, 1);
01003
/* do waitpid check */
01004           check_babysit_events (grandchild_pid, parent_pipe, 0);
01005         }
01006     }
01007
01008   exit (1);
01009 }
01010
01029
group__DBusTypes.html#ga2
dbus_bool_t
group__DBusInternalsUtils.html#ga38
01030
group__DBusInternalsUtils.html#ga38
_dbus_spawn_async_with_babysitter
(
structDBusBabysitter.html
DBusBabysitter
**sitter_p,
01031
char
**argv,
01032                                    DBusSpawnChildSetupFunc   child_setup,
01033
void
*user_data,
01034
structDBusError.html
DBusError
*error)
01035 {
01036
structDBusBabysitter.html
DBusBabysitter
*sitter;
01037
int
child_err_report_pipe[2] = { -1, -1 };
01038
int
babysitter_pipe[2] = { -1, -1 };
01039   pid_t pid;
01040
01041   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01042
01043   *sitter_p =
group__DBusMacros.html#ga4
NULL
;
01044   sitter =
group__DBusMacros.html#ga4
NULL
;
01045
01046   sitter = _dbus_babysitter_new ();
01047
if
(sitter ==
group__DBusMacros.html#ga4
NULL
)
01048     {
01049
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_NO_MEMORY,
group__DBusMacros.html#ga4
NULL
);
01050
return
group__DBusMacros.html#ga3
FALSE
;
01051     }
01052
01053   sitter->
structDBusBabysitter.html#o1
executable
=
group__DBusInternalsUtils.html#ga8
_dbus_strdup
(argv[0]);
01054
if
(sitter->
structDBusBabysitter.html#o1
executable
==
group__DBusMacros.html#ga4
NULL
)
01055     {
01056
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_NO_MEMORY,
group__DBusMacros.html#ga4
NULL
);
01057
goto
cleanup_and_fail;
01058     }
01059
01060
if
(!make_pipe (child_err_report_pipe, error))
01061
goto
cleanup_and_fail;
01062
01063
group__DBusInternalsUtils.html#ga98
_dbus_fd_set_close_on_exec
(child_err_report_pipe[
group__DBusInternalsUtils.html#ga151
READ_END
]);
01064
01065
if
(!
group__DBusInternalsUtils.html#ga104
_dbus_full_duplex_pipe
(&babysitter_pipe[0], &babysitter_pipe[1],
group__DBusMacros.html#ga2
TRUE
, error))
01066
goto
cleanup_and_fail;
01067
01068
group__DBusInternalsUtils.html#ga98
_dbus_fd_set_close_on_exec
(babysitter_pipe[0]);
01069
group__DBusInternalsUtils.html#ga98
_dbus_fd_set_close_on_exec
(babysitter_pipe[1]);
01070
01071
/* Setting up the babysitter is only useful in the parent,
01072
* but we don't want to run out of memory and fail
01073
* after we've already forked, since then we'd leak
01074
* child processes everywhere.
01075
*/
01076   sitter->
structDBusBabysitter.html#o7
error_watch
=
group__DBusWatchInternals.html#ga0
_dbus_watch_new
(child_err_report_pipe[READ_END],
01077                                          DBUS_WATCH_READABLE,
01078
group__DBusMacros.html#ga2
TRUE
, handle_watch, sitter,
group__DBusMacros.html#ga4
NULL
);
01079
if
(sitter->
structDBusBabysitter.html#o7
error_watch
==
group__DBusMacros.html#ga4
NULL
)
01080     {
01081
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_NO_MEMORY,
group__DBusMacros.html#ga4
NULL
);
01082
goto
cleanup_and_fail;
01083     }
01084
01085
if
(!
group__DBusWatchInternals.html#ga8
_dbus_watch_list_add_watch
(sitter->
structDBusBabysitter.html#o6
watches
,  sitter->
structDBusBabysitter.html#o7
error_watch
))
01086     {
01087
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_NO_MEMORY,
group__DBusMacros.html#ga4
NULL
);
01088
goto
cleanup_and_fail;
01089     }
01090
01091   sitter->
structDBusBabysitter.html#o8
sitter_watch
=
group__DBusWatchInternals.html#ga0
_dbus_watch_new
(babysitter_pipe[0],
01092                                           DBUS_WATCH_READABLE,
01093
group__DBusMacros.html#ga2
TRUE
, handle_watch, sitter,
group__DBusMacros.html#ga4
NULL
);
01094
if
(sitter->
structDBusBabysitter.html#o8
sitter_watch
==
group__DBusMacros.html#ga4
NULL
)
01095     {
01096
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_NO_MEMORY,
group__DBusMacros.html#ga4
NULL
);
01097
goto
cleanup_and_fail;
01098     }
01099
01100
if
(!
group__DBusWatchInternals.html#ga8
_dbus_watch_list_add_watch
(sitter->
structDBusBabysitter.html#o6
watches
,  sitter->
structDBusBabysitter.html#o8
sitter_watch
))
01101     {
01102
group__DBusErrors.html#ga6
dbus_set_error
(error, DBUS_ERROR_NO_MEMORY,
group__DBusMacros.html#ga4
NULL
);
01103
goto
cleanup_and_fail;
01104     }
01105
01106   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01107
01108   pid = fork ();
01109
01110
if
(pid < 0)
01111     {
01112
group__DBusErrors.html#ga6
dbus_set_error
(error,
01113                       DBUS_ERROR_SPAWN_FORK_FAILED,
01114
"Failed to fork (%s)"
,
01115
group__DBusInternalsUtils.html#ga96
_dbus_strerror
(errno));
01116
goto
cleanup_and_fail;
01117     }
01118
else
if
(pid == 0)
01119     {
01120
/* Immediate child, this is the babysitter process. */
01121
int
grandchild_pid;
01122
01123
/* Be sure we crash if the parent exits
01124
* and we write to the err_report_pipe
01125
*/
01126       signal (SIGPIPE, SIG_DFL);
01127
01128
/* Close the parent's end of the pipes. */
01129       close_and_invalidate (&child_err_report_pipe[READ_END]);
01130       close_and_invalidate (&babysitter_pipe[0]);
01131
01132
/* Create the child that will exec () */
01133       grandchild_pid = fork ();
01134
01135
if
(grandchild_pid < 0)
01136         {
01137           write_err_and_exit (babysitter_pipe[1],
01138                               CHILD_FORK_FAILED);
01139
group__DBusInternalsUtils.html#ga131
_dbus_assert_not_reached
(
"Got to code after write_err_and_exit()"
);
01140         }
01141
else
if
(grandchild_pid == 0)
01142         {
01143           do_exec (child_err_report_pipe[
group__DBusInternalsUtils.html#ga152
WRITE_END
],
01144                    argv,
01145                    child_setup, user_data);
01146
group__DBusInternalsUtils.html#ga131
_dbus_assert_not_reached
(
"Got to code after exec() - should have exited on error"
);
01147         }
01148
else
01149         {
01150           babysit (grandchild_pid, babysitter_pipe[1]);
01151
group__DBusInternalsUtils.html#ga131
_dbus_assert_not_reached
(
"Got to code after babysit()"
);
01152         }
01153     }
01154
else
01155     {
01156
/* Close the uncared-about ends of the pipes */
01157       close_and_invalidate (&child_err_report_pipe[
group__DBusInternalsUtils.html#ga152
WRITE_END
]);
01158       close_and_invalidate (&babysitter_pipe[1]);
01159
01160       sitter->
structDBusBabysitter.html#o2
socket_to_babysitter
= babysitter_pipe[0];
01161       babysitter_pipe[0] = -1;
01162
01163       sitter->
structDBusBabysitter.html#o3
error_pipe_from_child
= child_err_report_pipe[READ_END];
01164       child_err_report_pipe[READ_END] = -1;
01165
01166       sitter->
structDBusBabysitter.html#o4
sitter_pid
= pid;
01167
01168
if
(sitter_p !=
group__DBusMacros.html#ga4
NULL
)
01169         *sitter_p = sitter;
01170
else
01171
group__DBusInternalsUtils.html#ga16
_dbus_babysitter_unref
(sitter);
01172
01173       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01174
01175
return
group__DBusMacros.html#ga2
TRUE
;
01176     }
01177
01178  cleanup_and_fail:
01179
01180   _DBUS_ASSERT_ERROR_IS_SET (error);
01181
01182   close_and_invalidate (&child_err_report_pipe[READ_END]);
01183   close_and_invalidate (&child_err_report_pipe[
group__DBusInternalsUtils.html#ga152
WRITE_END
]);
01184   close_and_invalidate (&babysitter_pipe[0]);
01185   close_and_invalidate (&babysitter_pipe[1]);
01186
01187
if
(sitter !=
group__DBusMacros.html#ga4
NULL
)
01188
group__DBusInternalsUtils.html#ga16
_dbus_babysitter_unref
(sitter);
01189
01190
return
group__DBusMacros.html#ga3
FALSE
;
01191 }
01192
01195
#ifdef DBUS_BUILD_TESTS
01196
01197
static
void
01198 _dbus_babysitter_block_for_child_exit (
structDBusBabysitter.html
DBusBabysitter
*sitter)
01199 {
01200
while
(
group__DBusInternalsUtils.html#ga150
LIVE_CHILDREN
(sitter))
01201     babysitter_iteration (sitter,
group__DBusMacros.html#ga2
TRUE
);
01202 }
01203
01204
static
group__DBusTypes.html#ga2
dbus_bool_t
01205 check_spawn_nonexistent (
void
*data)
01206 {
01207
char
*argv[4] = {
group__DBusMacros.html#ga4
NULL
,
group__DBusMacros.html#ga4
NULL
, NULL, NULL };
01208
structDBusBabysitter.html
DBusBabysitter
*sitter;
01209
structDBusError.html
DBusError
error;
01210
01211   sitter = NULL;
01212
01213
group__DBusErrors.html#ga0
dbus_error_init
(&error);
01214
01215
/*** Test launching nonexistent binary */
01216
01217   argv[0] =
"/this/does/not/exist/32542sdgafgafdg"
;
01218
if
(
group__DBusInternalsUtils.html#ga38
_dbus_spawn_async_with_babysitter
(&sitter, argv,
01219                                          NULL, NULL,
01220                                          &error))
01221     {
01222       _dbus_babysitter_block_for_child_exit (sitter);
01223
group__DBusInternalsUtils.html#ga25
_dbus_babysitter_set_child_exit_error
(sitter, &error);
01224     }
01225
01226
if
(sitter)
01227
group__DBusInternalsUtils.html#ga16
_dbus_babysitter_unref
(sitter);
01228
01229
if
(!
group__DBusErrors.html#ga5
dbus_error_is_set
(&error))
01230     {
01231
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Did not get an error launching nonexistent executable\n"
);
01232
return
group__DBusMacros.html#ga3
FALSE
;
01233     }
01234
01235
if
(!(
group__DBusErrors.html#ga4
dbus_error_has_name
(&error, DBUS_ERROR_NO_MEMORY) ||
01236
group__DBusErrors.html#ga4
dbus_error_has_name
(&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
01237     {
01238
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Not expecting error when launching nonexistent executable: %s: %s\n"
,
01239                   error.name, error.message);
01240
group__DBusErrors.html#ga1
dbus_error_free
(&error);
01241
return
group__DBusMacros.html#ga3
FALSE
;
01242     }
01243
01244
group__DBusErrors.html#ga1
dbus_error_free
(&error);
01245
01246
return
group__DBusMacros.html#ga2
TRUE
;
01247 }
01248
01249
static
group__DBusTypes.html#ga2
dbus_bool_t
01250 check_spawn_segfault (
void
*data)
01251 {
01252
char
*argv[4] = { NULL, NULL, NULL, NULL };
01253
structDBusBabysitter.html
DBusBabysitter
*sitter;
01254
structDBusError.html
DBusError
error;
01255
01256   sitter = NULL;
01257
01258
group__DBusErrors.html#ga0
dbus_error_init
(&error);
01259
01260
/*** Test launching segfault binary */
01261
01262   argv[0] = TEST_SEGFAULT_BINARY;
01263
if
(
group__DBusInternalsUtils.html#ga38
_dbus_spawn_async_with_babysitter
(&sitter, argv,
01264                                          NULL, NULL,
01265                                          &error))
01266     {
01267       _dbus_babysitter_block_for_child_exit (sitter);
01268
group__DBusInternalsUtils.html#ga25
_dbus_babysitter_set_child_exit_error
(sitter, &error);
01269     }
01270
01271
if
(sitter)
01272
group__DBusInternalsUtils.html#ga16
_dbus_babysitter_unref
(sitter);
01273
01274
if
(!
group__DBusErrors.html#ga5
dbus_error_is_set
(&error))
01275     {
01276
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Did not get an error launching segfaulting binary\n"
);
01277
return
group__DBusMacros.html#ga3
FALSE
;
01278     }
01279
01280
if
(!(
group__DBusErrors.html#ga4
dbus_error_has_name
(&error, DBUS_ERROR_NO_MEMORY) ||
01281
group__DBusErrors.html#ga4
dbus_error_has_name
(&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01282     {
01283
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Not expecting error when launching segfaulting executable: %s: %s\n"
,
01284                   error.name, error.message);
01285
group__DBusErrors.html#ga1
dbus_error_free
(&error);
01286
return
group__DBusMacros.html#ga3
FALSE
;
01287     }
01288
01289
group__DBusErrors.html#ga1
dbus_error_free
(&error);
01290
01291
return
group__DBusMacros.html#ga2
TRUE
;
01292 }
01293
01294
static
group__DBusTypes.html#ga2
dbus_bool_t
01295 check_spawn_exit (
void
*data)
01296 {
01297
char
*argv[4] = { NULL, NULL, NULL, NULL };
01298
structDBusBabysitter.html
DBusBabysitter
*sitter;
01299
structDBusError.html
DBusError
error;
01300
01301   sitter = NULL;
01302
01303
group__DBusErrors.html#ga0
dbus_error_init
(&error);
01304
01305
/*** Test launching exit failure binary */
01306
01307   argv[0] = TEST_EXIT_BINARY;
01308
if
(
group__DBusInternalsUtils.html#ga38
_dbus_spawn_async_with_babysitter
(&sitter, argv,
01309                                          NULL, NULL,
01310                                          &error))
01311     {
01312       _dbus_babysitter_block_for_child_exit (sitter);
01313
group__DBusInternalsUtils.html#ga25
_dbus_babysitter_set_child_exit_error
(sitter, &error);
01314     }
01315
01316
if
(sitter)
01317
group__DBusInternalsUtils.html#ga16
_dbus_babysitter_unref
(sitter);
01318
01319
if
(!
group__DBusErrors.html#ga5
dbus_error_is_set
(&error))
01320     {
01321
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Did not get an error launching binary that exited with failure code\n"
);
01322
return
group__DBusMacros.html#ga3
FALSE
;
01323     }
01324
01325
if
(!(
group__DBusErrors.html#ga4
dbus_error_has_name
(&error, DBUS_ERROR_NO_MEMORY) ||
01326
group__DBusErrors.html#ga4
dbus_error_has_name
(&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
01327     {
01328
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Not expecting error when launching exiting executable: %s: %s\n"
,
01329                   error.name, error.message);
01330
group__DBusErrors.html#ga1
dbus_error_free
(&error);
01331
return
group__DBusMacros.html#ga3
FALSE
;
01332     }
01333
01334
group__DBusErrors.html#ga1
dbus_error_free
(&error);
01335
01336
return
group__DBusMacros.html#ga2
TRUE
;
01337 }
01338
01339
static
group__DBusTypes.html#ga2
dbus_bool_t
01340 check_spawn_and_kill (
void
*data)
01341 {
01342
char
*argv[4] = { NULL, NULL, NULL, NULL };
01343
structDBusBabysitter.html
DBusBabysitter
*sitter;
01344
structDBusError.html
DBusError
error;
01345
01346   sitter = NULL;
01347
01348
group__DBusErrors.html#ga0
dbus_error_init
(&error);
01349
01350
/*** Test launching sleeping binary then killing it */
01351
01352   argv[0] = TEST_SLEEP_FOREVER_BINARY;
01353
if
(
group__DBusInternalsUtils.html#ga38
_dbus_spawn_async_with_babysitter
(&sitter, argv,
01354                                          NULL, NULL,
01355                                          &error))
01356     {
01357
group__DBusInternalsUtils.html#ga23
_dbus_babysitter_kill_child
(sitter);
01358
01359       _dbus_babysitter_block_for_child_exit (sitter);
01360
01361
group__DBusInternalsUtils.html#ga25
_dbus_babysitter_set_child_exit_error
(sitter, &error);
01362     }
01363
01364
if
(sitter)
01365
group__DBusInternalsUtils.html#ga16
_dbus_babysitter_unref
(sitter);
01366
01367
if
(!
group__DBusErrors.html#ga5
dbus_error_is_set
(&error))
01368     {
01369
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Did not get an error after killing spawned binary\n"
);
01370
return
group__DBusMacros.html#ga3
FALSE
;
01371     }
01372
01373
if
(!(
group__DBusErrors.html#ga4
dbus_error_has_name
(&error, DBUS_ERROR_NO_MEMORY) ||
01374
group__DBusErrors.html#ga4
dbus_error_has_name
(&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01375     {
01376
group__DBusInternalsUtils.html#ga7
_dbus_warn
(
"Not expecting error when killing executable: %s: %s\n"
,
01377                   error.name, error.message);
01378
group__DBusErrors.html#ga1
dbus_error_free
(&error);
01379
return
group__DBusMacros.html#ga3
FALSE
;
01380     }
01381
01382
group__DBusErrors.html#ga1
dbus_error_free
(&error);
01383
01384
return
group__DBusMacros.html#ga2
TRUE
;
01385 }
01386
01387
group__DBusTypes.html#ga2
dbus_bool_t
01388 _dbus_spawn_test (
const
char
*test_data_dir)
01389 {
01390
if
(!_dbus_test_oom_handling (
"spawn_nonexistent"
,
01391                                 check_spawn_nonexistent,
01392                                 NULL))
01393
return
group__DBusMacros.html#ga3
FALSE
;
01394
01395
if
(!_dbus_test_oom_handling (
"spawn_segfault"
,
01396                                 check_spawn_segfault,
01397                                 NULL))
01398
return
group__DBusMacros.html#ga3
FALSE
;
01399
01400
if
(!_dbus_test_oom_handling (
"spawn_exit"
,
01401                                 check_spawn_exit,
01402                                 NULL))
01403
return
group__DBusMacros.html#ga3
FALSE
;
01404
01405
if
(!_dbus_test_oom_handling (
"spawn_and_kill"
,
01406                                 check_spawn_and_kill,
01407                                 NULL))
01408
return
group__DBusMacros.html#ga3
FALSE
;
01409
01410
return
group__DBusMacros.html#ga2
TRUE
;
01411 }
01412
#endif
Generated on Tue Sep 13 01:28:07 2005 for D-BUS by
http://www.doxygen.org/index.html
doxygen
1.4.4
