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