• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List

dbus-spawn.c

00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 
00027 #include "dbus-spawn.h"
00028 #include "dbus-sysdeps-unix.h"
00029 #include "dbus-internals.h"
00030 #include "dbus-test.h"
00031 #include "dbus-protocol.h"
00032 
00033 #include <unistd.h>
00034 #include <fcntl.h>
00035 #include <signal.h>
00036 #include <sys/wait.h>
00037 #include <stdlib.h>
00038 #ifdef HAVE_ERRNO_H
00039 #include <errno.h>
00040 #endif
00041 
00042 extern char **environ;
00043 
00049 /*
00050  * I'm pretty sure this whole spawn file could be made simpler,
00051  * if you thought about it a bit.
00052  */
00053 
00057 typedef enum
00058 {
00059   READ_STATUS_OK,    
00060   READ_STATUS_ERROR, 
00061   READ_STATUS_EOF    
00062 } ReadStatus;
00063 
00064 static ReadStatus
00065 read_ints (int        fd,
00066            int       *buf,
00067            int        n_ints_in_buf,
00068            int       *n_ints_read,
00069            DBusError *error)
00070 {
00071   size_t bytes = 0;    
00072   ReadStatus retval;
00073   
00074   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00075 
00076   retval = READ_STATUS_OK;
00077   
00078   while (TRUE)
00079     {
00080       ssize_t chunk;
00081       size_t to_read;
00082 
00083       to_read = sizeof (int) * n_ints_in_buf - bytes;
00084 
00085       if (to_read == 0)
00086         break;
00087 
00088     again:
00089       
00090       chunk = read (fd,
00091                     ((char*)buf) + bytes,
00092                     to_read);
00093       
00094       if (chunk < 0 && errno == EINTR)
00095         goto again;
00096           
00097       if (chunk < 0)
00098         {
00099           dbus_set_error (error,
00100                           DBUS_ERROR_SPAWN_FAILED,
00101                           "Failed to read from child pipe (%s)",
00102                           _dbus_strerror (errno));
00103 
00104           retval = READ_STATUS_ERROR;
00105           break;
00106         }
00107       else if (chunk == 0)
00108         {
00109           retval = READ_STATUS_EOF;
00110           break; /* EOF */
00111         }
00112       else /* chunk > 0 */
00113         bytes += chunk;
00114     }
00115 
00116   *n_ints_read = (int)(bytes / sizeof(int));
00117 
00118   return retval;
00119 }
00120 
00121 static ReadStatus
00122 read_pid (int        fd,
00123           pid_t     *buf,
00124           DBusError *error)
00125 {
00126   size_t bytes = 0;    
00127   ReadStatus retval;
00128   
00129   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00130 
00131   retval = READ_STATUS_OK;
00132   
00133   while (TRUE)
00134     {
00135       ssize_t chunk;
00136       size_t to_read;
00137 
00138       to_read = sizeof (pid_t) - bytes;
00139 
00140       if (to_read == 0)
00141         break;
00142 
00143     again:
00144       
00145       chunk = read (fd,
00146                     ((char*)buf) + bytes,
00147                     to_read);
00148       if (chunk < 0 && errno == EINTR)
00149         goto again;
00150           
00151       if (chunk < 0)
00152         {
00153           dbus_set_error (error,
00154                           DBUS_ERROR_SPAWN_FAILED,
00155                           "Failed to read from child pipe (%s)",
00156                           _dbus_strerror (errno));
00157 
00158           retval = READ_STATUS_ERROR;
00159           break;
00160         }
00161       else if (chunk == 0)
00162         {
00163           retval = READ_STATUS_EOF;
00164           break; /* EOF */
00165         }
00166       else /* chunk > 0 */
00167         bytes += chunk;
00168     }
00169 
00170   return retval;
00171 }
00172 
00173 /* The implementation uses an intermediate child between the main process
00174  * and the grandchild. The grandchild is our spawned process. The intermediate
00175  * child is a babysitter process; it keeps track of when the grandchild
00176  * exits/crashes, and reaps the grandchild.
00177  */
00178 
00179 /* Messages from children to parents */
00180 enum
00181 {
00182   CHILD_EXITED,            /* This message is followed by the exit status int */
00183   CHILD_FORK_FAILED,       /* Followed by errno */
00184   CHILD_EXEC_FAILED,       /* Followed by errno */
00185   CHILD_PID                /* Followed by pid_t */
00186 };
00187 
00191 struct DBusBabysitter
00192 {
00193   int refcount; 
00195   char *executable; 
00197   int socket_to_babysitter; 
00198   int error_pipe_from_child; 
00200   pid_t sitter_pid;  
00201   pid_t grandchild_pid; 
00203   DBusWatchList *watches; 
00205   DBusWatch *error_watch; 
00206   DBusWatch *sitter_watch; 
00208   int errnum; 
00209   int status; 
00210   unsigned int have_child_status : 1; 
00211   unsigned int have_fork_errnum : 1; 
00212   unsigned int have_exec_errnum : 1; 
00213 };
00214 
00215 static DBusBabysitter*
00216 _dbus_babysitter_new (void)
00217 {
00218   DBusBabysitter *sitter;
00219 
00220   sitter = dbus_new0 (DBusBabysitter, 1);
00221   if (sitter == NULL)
00222     return NULL;
00223 
00224   sitter->refcount = 1;
00225 
00226   sitter->socket_to_babysitter = -1;
00227   sitter->error_pipe_from_child = -1;
00228   
00229   sitter->sitter_pid = -1;
00230   sitter->grandchild_pid = -1;
00231 
00232   sitter->watches = _dbus_watch_list_new ();
00233   if (sitter->watches == NULL)
00234     goto failed;
00235   
00236   return sitter;
00237 
00238  failed:
00239   _dbus_babysitter_unref (sitter);
00240   return NULL;
00241 }
00242 
00249 DBusBabysitter *
00250 _dbus_babysitter_ref (DBusBabysitter *sitter)
00251 {
00252   _dbus_assert (sitter != NULL);
00253   _dbus_assert (sitter->refcount > 0);
00254   
00255   sitter->refcount += 1;
00256 
00257   return sitter;
00258 }
00259 
00268 void
00269 _dbus_babysitter_unref (DBusBabysitter *sitter)
00270 {
00271   _dbus_assert (sitter != NULL);
00272   _dbus_assert (sitter->refcount > 0);
00273   
00274   sitter->refcount -= 1;
00275   if (sitter->refcount == 0)
00276     {      
00277       if (sitter->socket_to_babysitter >= 0)
00278         {
00279           /* If we haven't forked other babysitters
00280            * since this babysitter and socket were
00281            * created then this close will cause the
00282            * babysitter to wake up from poll with
00283            * a hangup and then the babysitter will
00284            * quit itself.
00285            */
00286           _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00287           sitter->socket_to_babysitter = -1;
00288         }
00289 
00290       if (sitter->error_pipe_from_child >= 0)
00291         {
00292           _dbus_close_socket (sitter->error_pipe_from_child, NULL);
00293           sitter->error_pipe_from_child = -1;
00294         }
00295 
00296       if (sitter->sitter_pid > 0)
00297         {
00298           int status;
00299           int ret;
00300 
00301           /* It's possible the babysitter died on its own above 
00302            * from the close, or was killed randomly
00303            * by some other process, so first try to reap it
00304            */
00305           ret = waitpid (sitter->sitter_pid, &status, WNOHANG);
00306 
00307           /* If we couldn't reap the child then kill it, and
00308            * try again
00309            */
00310           if (ret == 0)
00311             kill (sitter->sitter_pid, SIGKILL);
00312 
00313         again:
00314           if (ret == 0)
00315             ret = waitpid (sitter->sitter_pid, &status, 0);
00316 
00317           if (ret < 0)
00318             {
00319               if (errno == EINTR)
00320                 goto again;
00321               else if (errno == ECHILD)
00322                 _dbus_warn ("Babysitter process not available to be reaped; should not happen\n");
00323               else
00324                 _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s\n",
00325                             errno, _dbus_strerror (errno));
00326             }
00327           else
00328             {
00329               _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n",
00330                              (long) ret, (long) sitter->sitter_pid);
00331               
00332               if (WIFEXITED (sitter->status))
00333                 _dbus_verbose ("Babysitter exited with status %d\n",
00334                                WEXITSTATUS (sitter->status));
00335               else if (WIFSIGNALED (sitter->status))
00336                 _dbus_verbose ("Babysitter received signal %d\n",
00337                                WTERMSIG (sitter->status));
00338               else
00339                 _dbus_verbose ("Babysitter exited abnormally\n");
00340             }
00341 
00342           sitter->sitter_pid = -1;
00343         }
00344       
00345       if (sitter->error_watch)
00346         {
00347           _dbus_watch_invalidate (sitter->error_watch);
00348           _dbus_watch_unref (sitter->error_watch);
00349           sitter->error_watch = NULL;
00350         }
00351 
00352       if (sitter->sitter_watch)
00353         {
00354           _dbus_watch_invalidate (sitter->sitter_watch);
00355           _dbus_watch_unref (sitter->sitter_watch);
00356           sitter->sitter_watch = NULL;
00357         }
00358       
00359       if (sitter->watches)
00360         _dbus_watch_list_free (sitter->watches);
00361 
00362       dbus_free (sitter->executable);
00363       
00364       dbus_free (sitter);
00365     }
00366 }
00367 
00368 static ReadStatus
00369 read_data (DBusBabysitter *sitter,
00370            int             fd)
00371 {
00372   int what;
00373   int got;
00374   DBusError error = DBUS_ERROR_INIT;
00375   ReadStatus r;
00376 
00377   r = read_ints (fd, &what, 1, &got, &error);
00378 
00379   switch (r)
00380     {
00381     case READ_STATUS_ERROR:
00382       _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message);
00383       dbus_error_free (&error);
00384       return r;
00385 
00386     case READ_STATUS_EOF:
00387       return r;
00388 
00389     case READ_STATUS_OK:
00390       break;
00391     }
00392   
00393   if (got == 1)
00394     {
00395       switch (what)
00396         {
00397         case CHILD_EXITED:
00398         case CHILD_FORK_FAILED:
00399         case CHILD_EXEC_FAILED:
00400           {
00401             int arg;
00402             
00403             r = read_ints (fd, &arg, 1, &got, &error);
00404 
00405             switch (r)
00406               {
00407               case READ_STATUS_ERROR:
00408                 _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message);
00409                 dbus_error_free (&error);
00410                 return r;
00411               case READ_STATUS_EOF:
00412                 return r;
00413               case READ_STATUS_OK:
00414                 break;
00415               }
00416             
00417             if (got == 1)
00418               {
00419                 if (what == CHILD_EXITED)
00420                   {
00421                     sitter->have_child_status = TRUE;
00422                     sitter->status = arg;
00423                     sitter->errnum = 0;
00424                     _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
00425                                    WIFEXITED (sitter->status), WIFSIGNALED (sitter->status),
00426                                    WEXITSTATUS (sitter->status), WTERMSIG (sitter->status));
00427                   }
00428                 else if (what == CHILD_FORK_FAILED)
00429                   {
00430                     sitter->have_fork_errnum = TRUE;
00431                     sitter->errnum = arg;
00432                     _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum);
00433                   }
00434                 else if (what == CHILD_EXEC_FAILED)
00435                   {
00436                     sitter->have_exec_errnum = TRUE;
00437                     sitter->errnum = arg;
00438                     _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum);
00439                   }
00440               }
00441           }
00442           break;
00443         case CHILD_PID:
00444           {
00445             pid_t pid = -1;
00446 
00447             r = read_pid (fd, &pid, &error);
00448             
00449             switch (r)
00450               {
00451               case READ_STATUS_ERROR:
00452                 _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message);
00453                 dbus_error_free (&error);
00454                 return r;
00455               case READ_STATUS_EOF:
00456                 return r;
00457               case READ_STATUS_OK:
00458                 break;
00459               }
00460             
00461             sitter->grandchild_pid = pid;
00462             
00463             _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid);
00464           }
00465           break;
00466         default:
00467           _dbus_warn ("Unknown message received from babysitter process\n");
00468           break;
00469         }
00470     }
00471 
00472   return r;
00473 }
00474 
00475 static void
00476 close_socket_to_babysitter (DBusBabysitter *sitter)
00477 {
00478   _dbus_verbose ("Closing babysitter\n");
00479   _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00480   sitter->socket_to_babysitter = -1;
00481 }
00482 
00483 static void
00484 close_error_pipe_from_child (DBusBabysitter *sitter)
00485 {
00486   _dbus_verbose ("Closing child error\n");
00487   _dbus_close_socket (sitter->error_pipe_from_child, NULL);
00488   sitter->error_pipe_from_child = -1;
00489 }
00490 
00491 static void
00492 handle_babysitter_socket (DBusBabysitter *sitter,
00493                           int             revents)
00494 {
00495   /* Even if we have POLLHUP, we want to keep reading
00496    * data until POLLIN goes away; so this function only
00497    * looks at HUP/ERR if no IN is set.
00498    */
00499   if (revents & _DBUS_POLLIN)
00500     {
00501       _dbus_verbose ("Reading data from babysitter\n");
00502       if (read_data (sitter, sitter->socket_to_babysitter) != READ_STATUS_OK)
00503         close_socket_to_babysitter (sitter);
00504     }
00505   else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00506     {
00507       close_socket_to_babysitter (sitter);
00508     }
00509 }
00510 
00511 static void
00512 handle_error_pipe (DBusBabysitter *sitter,
00513                    int             revents)
00514 {
00515   if (revents & _DBUS_POLLIN)
00516     {
00517       _dbus_verbose ("Reading data from child error\n");
00518       if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK)
00519         close_error_pipe_from_child (sitter);
00520     }
00521   else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00522     {
00523       close_error_pipe_from_child (sitter);
00524     }
00525 }
00526 
00527 /* returns whether there were any poll events handled */
00528 static dbus_bool_t
00529 babysitter_iteration (DBusBabysitter *sitter,
00530                       dbus_bool_t     block)
00531 {
00532   DBusPollFD fds[2];
00533   int i;
00534   dbus_bool_t descriptors_ready;
00535 
00536   descriptors_ready = FALSE;
00537   
00538   i = 0;
00539 
00540   if (sitter->error_pipe_from_child >= 0)
00541     {
00542       fds[i].fd = sitter->error_pipe_from_child;
00543       fds[i].events = _DBUS_POLLIN;
00544       fds[i].revents = 0;
00545       ++i;
00546     }
00547   
00548   if (sitter->socket_to_babysitter >= 0)
00549     {
00550       fds[i].fd = sitter->socket_to_babysitter;
00551       fds[i].events = _DBUS_POLLIN;
00552       fds[i].revents = 0;
00553       ++i;
00554     }
00555 
00556   if (i > 0)
00557     {
00558       int ret;
00559 
00560       do
00561         {
00562           ret = _dbus_poll (fds, i, 0);
00563         }
00564       while (ret < 0 && errno == EINTR);
00565 
00566       if (ret == 0 && block)
00567         {
00568           do
00569             {
00570               ret = _dbus_poll (fds, i, -1);
00571             }
00572           while (ret < 0 && errno == EINTR);
00573         }
00574 
00575       if (ret > 0)
00576         {
00577           descriptors_ready = TRUE;
00578           
00579           while (i > 0)
00580             {
00581               --i;
00582               if (fds[i].fd == sitter->error_pipe_from_child)
00583                 handle_error_pipe (sitter, fds[i].revents);
00584               else if (fds[i].fd == sitter->socket_to_babysitter)
00585                 handle_babysitter_socket (sitter, fds[i].revents);
00586             }
00587         }
00588     }
00589 
00590   return descriptors_ready;
00591 }
00592 
00597 #define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter >= 0 || (sitter)->error_pipe_from_child >= 0)
00598 
00605 void
00606 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
00607 {
00608   /* be sure we have the PID of the child */
00609   while (LIVE_CHILDREN (sitter) &&
00610          sitter->grandchild_pid == -1)
00611     babysitter_iteration (sitter, TRUE);
00612 
00613   _dbus_verbose ("Got child PID %ld for killing\n",
00614                  (long) sitter->grandchild_pid);
00615   
00616   if (sitter->grandchild_pid == -1)
00617     return; /* child is already dead, or we're so hosed we'll never recover */
00618 
00619   kill (sitter->grandchild_pid, SIGKILL);
00620 }
00621 
00627 dbus_bool_t
00628 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
00629 {
00630 
00631   /* Be sure we're up-to-date */
00632   while (LIVE_CHILDREN (sitter) &&
00633          babysitter_iteration (sitter, FALSE))
00634     ;
00635 
00636   /* We will have exited the babysitter when the child has exited */
00637   return sitter->socket_to_babysitter < 0;
00638 }
00639 
00652 dbus_bool_t
00653 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
00654                                         int            *status)
00655 {
00656   if (!_dbus_babysitter_get_child_exited (sitter))
00657     _dbus_assert_not_reached ("Child has not exited");
00658   
00659   if (!sitter->have_child_status ||
00660       !(WIFEXITED (sitter->status)))
00661     return FALSE;
00662 
00663   *status = WEXITSTATUS (sitter->status);
00664   return TRUE;
00665 }
00666 
00676 void
00677 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
00678                                        DBusError      *error)
00679 {
00680   if (!_dbus_babysitter_get_child_exited (sitter))
00681     return;
00682 
00683   /* Note that if exec fails, we will also get a child status
00684    * from the babysitter saying the child exited,
00685    * so we need to give priority to the exec error
00686    */
00687   if (sitter->have_exec_errnum)
00688     {
00689       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00690                       "Failed to execute program %s: %s",
00691                       sitter->executable, _dbus_strerror (sitter->errnum));
00692     }
00693   else if (sitter->have_fork_errnum)
00694     {
00695       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00696                       "Failed to fork a new process %s: %s",
00697                       sitter->executable, _dbus_strerror (sitter->errnum));
00698     }
00699   else if (sitter->have_child_status)
00700     {
00701       if (WIFEXITED (sitter->status))
00702         dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00703                         "Process %s exited with status %d",
00704                         sitter->executable, WEXITSTATUS (sitter->status));
00705       else if (WIFSIGNALED (sitter->status))
00706         dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,
00707                         "Process %s received signal %d",
00708                         sitter->executable, WTERMSIG (sitter->status));
00709       else
00710         dbus_set_error (error, DBUS_ERROR_FAILED,
00711                         "Process %s exited abnormally",
00712                         sitter->executable);
00713     }
00714   else
00715     {
00716       dbus_set_error (error, DBUS_ERROR_FAILED,
00717                       "Process %s exited, reason unknown",
00718                       sitter->executable);
00719     }
00720 }
00721 
00734 dbus_bool_t
00735 _dbus_babysitter_set_watch_functions (DBusBabysitter            *sitter,
00736                                       DBusAddWatchFunction       add_function,
00737                                       DBusRemoveWatchFunction    remove_function,
00738                                       DBusWatchToggledFunction   toggled_function,
00739                                       void                      *data,
00740                                       DBusFreeFunction           free_data_function)
00741 {
00742   return _dbus_watch_list_set_functions (sitter->watches,
00743                                          add_function,
00744                                          remove_function,
00745                                          toggled_function,
00746                                          data,
00747                                          free_data_function);
00748 }
00749 
00750 static dbus_bool_t
00751 handle_watch (DBusWatch       *watch,
00752               unsigned int     condition,
00753               void            *data)
00754 {
00755   DBusBabysitter *sitter = data;
00756   int revents;
00757   int fd;
00758   
00759   revents = 0;
00760   if (condition & DBUS_WATCH_READABLE)
00761     revents |= _DBUS_POLLIN;
00762   if (condition & DBUS_WATCH_ERROR)
00763     revents |= _DBUS_POLLERR;
00764   if (condition & DBUS_WATCH_HANGUP)
00765     revents |= _DBUS_POLLHUP;
00766 
00767   fd = dbus_watch_get_socket (watch);
00768 
00769   if (fd == sitter->error_pipe_from_child)
00770     handle_error_pipe (sitter, revents);
00771   else if (fd == sitter->socket_to_babysitter)
00772     handle_babysitter_socket (sitter, revents);
00773 
00774   while (LIVE_CHILDREN (sitter) &&
00775          babysitter_iteration (sitter, FALSE))
00776     ;
00777   
00778   return TRUE;
00779 }
00780 
00782 #define READ_END 0
00783 
00784 #define WRITE_END 1
00785 
00786 
00787 /* Avoids a danger in threaded situations (calling close()
00788  * on a file descriptor twice, and another thread has
00789  * re-opened it since the first close)
00790  */
00791 static int
00792 close_and_invalidate (int *fd)
00793 {
00794   int ret;
00795 
00796   if (*fd < 0)
00797     return -1;
00798   else
00799     {
00800       ret = _dbus_close_socket (*fd, NULL);
00801       *fd = -1;
00802     }
00803 
00804   return ret;
00805 }
00806 
00807 static dbus_bool_t
00808 make_pipe (int         p[2],
00809            DBusError  *error)
00810 {
00811   int retval;
00812 
00813 #ifdef HAVE_PIPE2
00814   dbus_bool_t cloexec_done;
00815 
00816   retval = pipe2 (p, O_CLOEXEC);
00817   cloexec_done = retval >= 0;
00818 
00819   /* Check if kernel seems to be too old to know pipe2(). We assume
00820      that if pipe2 is available, O_CLOEXEC is too.  */
00821   if (retval < 0 && errno == ENOSYS)
00822 #endif
00823     {
00824       retval = pipe(p);
00825     }
00826 
00827   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00828 
00829   if (retval < 0)
00830     {
00831       dbus_set_error (error,
00832                       DBUS_ERROR_SPAWN_FAILED,
00833                       "Failed to create pipe for communicating with child process (%s)",
00834                       _dbus_strerror (errno));
00835       return FALSE;
00836     }
00837 
00838 #ifdef HAVE_PIPE2
00839   if (!cloexec_done)
00840 #endif
00841     {
00842       _dbus_fd_set_close_on_exec (p[0]);
00843       _dbus_fd_set_close_on_exec (p[1]);
00844     }
00845 
00846   return TRUE;
00847 }
00848 
00849 static void
00850 do_write (int fd, const void *buf, size_t count)
00851 {
00852   size_t bytes_written;
00853   int ret;
00854   
00855   bytes_written = 0;
00856   
00857  again:
00858   
00859   ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
00860 
00861   if (ret < 0)
00862     {
00863       if (errno == EINTR)
00864         goto again;
00865       else
00866         {
00867           _dbus_warn ("Failed to write data to pipe!\n");
00868           exit (1); /* give up, we suck */
00869         }
00870     }
00871   else
00872     bytes_written += ret;
00873   
00874   if (bytes_written < count)
00875     goto again;
00876 }
00877 
00878 static void
00879 write_err_and_exit (int fd, int msg)
00880 {
00881   int en = errno;
00882 
00883   do_write (fd, &msg, sizeof (msg));
00884   do_write (fd, &en, sizeof (en));
00885   
00886   exit (1);
00887 }
00888 
00889 static void
00890 write_pid (int fd, pid_t pid)
00891 {
00892   int msg = CHILD_PID;
00893   
00894   do_write (fd, &msg, sizeof (msg));
00895   do_write (fd, &pid, sizeof (pid));
00896 }
00897 
00898 static void
00899 write_status_and_exit (int fd, int status)
00900 {
00901   int msg = CHILD_EXITED;
00902   
00903   do_write (fd, &msg, sizeof (msg));
00904   do_write (fd, &status, sizeof (status));
00905   
00906   exit (0);
00907 }
00908 
00909 static void
00910 do_exec (int                       child_err_report_fd,
00911          char                    **argv,
00912          char                    **envp,
00913          DBusSpawnChildSetupFunc   child_setup,
00914          void                     *user_data)
00915 {
00916 #ifdef DBUS_BUILD_TESTS
00917   int i, max_open;
00918 #endif
00919 
00920   _dbus_verbose_reset ();
00921   _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n",
00922                  _dbus_getpid ());
00923   
00924   if (child_setup)
00925     (* child_setup) (user_data);
00926 
00927 #ifdef DBUS_BUILD_TESTS
00928   max_open = sysconf (_SC_OPEN_MAX);
00929   
00930   for (i = 3; i < max_open; i++)
00931     {
00932       int retval;
00933 
00934       if (i == child_err_report_fd)
00935         continue;
00936       
00937       retval = fcntl (i, F_GETFD);
00938 
00939       if (retval != -1 && !(retval & FD_CLOEXEC))
00940         _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
00941     }
00942 #endif
00943 
00944   if (envp == NULL)
00945     {
00946       _dbus_assert (environ != NULL);
00947 
00948       envp = environ;
00949     }
00950   
00951   execve (argv[0], argv, envp);
00952   
00953   /* Exec failed */
00954   write_err_and_exit (child_err_report_fd,
00955                       CHILD_EXEC_FAILED);
00956 }
00957 
00958 static void
00959 check_babysit_events (pid_t grandchild_pid,
00960                       int   parent_pipe,
00961                       int   revents)
00962 {
00963   pid_t ret;
00964   int status;
00965   
00966   do
00967     {
00968       ret = waitpid (grandchild_pid, &status, WNOHANG);
00969       /* The man page says EINTR can't happen with WNOHANG,
00970        * but there are reports of it (maybe only with valgrind?)
00971        */
00972     }
00973   while (ret < 0 && errno == EINTR);
00974 
00975   if (ret == 0)
00976     {
00977       _dbus_verbose ("no child exited\n");
00978       
00979       ; /* no child exited */
00980     }
00981   else if (ret < 0)
00982     {
00983       /* This isn't supposed to happen. */
00984       _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n",
00985                   _dbus_strerror (errno));
00986       exit (1);
00987     }
00988   else if (ret == grandchild_pid)
00989     {
00990       /* Child exited */
00991       _dbus_verbose ("reaped child pid %ld\n", (long) ret);
00992       
00993       write_status_and_exit (parent_pipe, status);
00994     }
00995   else
00996     {
00997       _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n",
00998                   (int) ret);
00999       exit (1);
01000     }
01001 
01002   if (revents & _DBUS_POLLIN)
01003     {
01004       _dbus_verbose ("babysitter got POLLIN from parent pipe\n");
01005     }
01006 
01007   if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
01008     {
01009       /* Parent is gone, so we just exit */
01010       _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n");
01011       exit (0);
01012     }
01013 }
01014 
01015 static int babysit_sigchld_pipe = -1;
01016 
01017 static void
01018 babysit_signal_handler (int signo)
01019 {
01020   char b = '\0';
01021  again:
01022   if (write (babysit_sigchld_pipe, &b, 1) <= 0) 
01023     if (errno == EINTR)
01024       goto again;
01025 }
01026 
01027 static void
01028 babysit (pid_t grandchild_pid,
01029          int   parent_pipe)
01030 {
01031   int sigchld_pipe[2];
01032 
01033   /* We don't exec, so we keep parent state, such as the pid that
01034    * _dbus_verbose() uses. Reset the pid here.
01035    */
01036   _dbus_verbose_reset ();
01037   
01038   /* I thought SIGCHLD would just wake up the poll, but
01039    * that didn't seem to work, so added this pipe.
01040    * Probably the pipe is more likely to work on busted
01041    * operating systems anyhow.
01042    */
01043   if (pipe (sigchld_pipe) < 0)
01044     {
01045       _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n");
01046       exit (1);
01047     }
01048 
01049   babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
01050 
01051   _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
01052   
01053   write_pid (parent_pipe, grandchild_pid);
01054 
01055   check_babysit_events (grandchild_pid, parent_pipe, 0);
01056 
01057   while (TRUE)
01058     {
01059       DBusPollFD pfds[2];
01060       
01061       pfds[0].fd = parent_pipe;
01062       pfds[0].events = _DBUS_POLLIN;
01063       pfds[0].revents = 0;
01064 
01065       pfds[1].fd = sigchld_pipe[READ_END];
01066       pfds[1].events = _DBUS_POLLIN;
01067       pfds[1].revents = 0;
01068       
01069       if (_dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1) < 0 && errno != EINTR)
01070         {
01071           _dbus_warn ("_dbus_poll() error: %s\n", strerror (errno));
01072           exit (1);
01073         }
01074 
01075       if (pfds[0].revents != 0)
01076         {
01077           check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
01078         }
01079       else if (pfds[1].revents & _DBUS_POLLIN)
01080         {
01081           char b;
01082           if (read (sigchld_pipe[READ_END], &b, 1) == -1)
01083             /* ignore */;
01084           /* do waitpid check */
01085           check_babysit_events (grandchild_pid, parent_pipe, 0);
01086         }
01087     }
01088   
01089   exit (1);
01090 }
01091 
01111 dbus_bool_t
01112 _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
01113                                    char                    **argv,
01114                                    char                    **env,
01115                                    DBusSpawnChildSetupFunc   child_setup,
01116                                    void                     *user_data,
01117                                    DBusError                *error)
01118 {
01119   DBusBabysitter *sitter;
01120   int child_err_report_pipe[2] = { -1, -1 };
01121   int babysitter_pipe[2] = { -1, -1 };
01122   pid_t pid;
01123   
01124   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01125 
01126   if (sitter_p != NULL)
01127     *sitter_p = NULL;
01128 
01129   sitter = NULL;
01130 
01131   sitter = _dbus_babysitter_new ();
01132   if (sitter == NULL)
01133     {
01134       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01135       return FALSE;
01136     }
01137 
01138   sitter->executable = _dbus_strdup (argv[0]);
01139   if (sitter->executable == NULL)
01140     {
01141       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01142       goto cleanup_and_fail;
01143     }
01144   
01145   if (!make_pipe (child_err_report_pipe, error))
01146     goto cleanup_and_fail;
01147 
01148   if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
01149     goto cleanup_and_fail;
01150 
01151   /* Setting up the babysitter is only useful in the parent,
01152    * but we don't want to run out of memory and fail
01153    * after we've already forked, since then we'd leak
01154    * child processes everywhere.
01155    */
01156   sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
01157                                          DBUS_WATCH_READABLE,
01158                                          TRUE, handle_watch, sitter, NULL);
01159   if (sitter->error_watch == NULL)
01160     {
01161       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01162       goto cleanup_and_fail;
01163     }
01164         
01165   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->error_watch))
01166     {
01167       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01168       goto cleanup_and_fail;
01169     }
01170       
01171   sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
01172                                           DBUS_WATCH_READABLE,
01173                                           TRUE, handle_watch, sitter, NULL);
01174   if (sitter->sitter_watch == NULL)
01175     {
01176       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01177       goto cleanup_and_fail;
01178     }
01179       
01180   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
01181     {
01182       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01183       goto cleanup_and_fail;
01184     }
01185 
01186   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01187   
01188   pid = fork ();
01189   
01190   if (pid < 0)
01191     {
01192       dbus_set_error (error,
01193                       DBUS_ERROR_SPAWN_FORK_FAILED,
01194                       "Failed to fork (%s)",
01195                       _dbus_strerror (errno));
01196       goto cleanup_and_fail;
01197     }
01198   else if (pid == 0)
01199     {
01200       /* Immediate child, this is the babysitter process. */
01201       int grandchild_pid;
01202       
01203       /* Be sure we crash if the parent exits
01204        * and we write to the err_report_pipe
01205        */
01206       signal (SIGPIPE, SIG_DFL);
01207 
01208       /* Close the parent's end of the pipes. */
01209       close_and_invalidate (&child_err_report_pipe[READ_END]);
01210       close_and_invalidate (&babysitter_pipe[0]);
01211       
01212       /* Create the child that will exec () */
01213       grandchild_pid = fork ();
01214       
01215       if (grandchild_pid < 0)
01216         {
01217           write_err_and_exit (babysitter_pipe[1],
01218                               CHILD_FORK_FAILED);
01219           _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
01220         }
01221       else if (grandchild_pid == 0)
01222         {
01223           do_exec (child_err_report_pipe[WRITE_END],
01224                    argv,
01225                    env,
01226                    child_setup, user_data);
01227           _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
01228         }
01229       else
01230         {
01231           babysit (grandchild_pid, babysitter_pipe[1]);
01232           _dbus_assert_not_reached ("Got to code after babysit()");
01233         }
01234     }
01235   else
01236     {      
01237       /* Close the uncared-about ends of the pipes */
01238       close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01239       close_and_invalidate (&babysitter_pipe[1]);
01240 
01241       sitter->socket_to_babysitter = babysitter_pipe[0];
01242       babysitter_pipe[0] = -1;
01243       
01244       sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
01245       child_err_report_pipe[READ_END] = -1;
01246 
01247       sitter->sitter_pid = pid;
01248 
01249       if (sitter_p != NULL)
01250         *sitter_p = sitter;
01251       else
01252         _dbus_babysitter_unref (sitter);
01253 
01254       dbus_free_string_array (env);
01255 
01256       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01257       
01258       return TRUE;
01259     }
01260 
01261  cleanup_and_fail:
01262 
01263   _DBUS_ASSERT_ERROR_IS_SET (error);
01264   
01265   close_and_invalidate (&child_err_report_pipe[READ_END]);
01266   close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01267   close_and_invalidate (&babysitter_pipe[0]);
01268   close_and_invalidate (&babysitter_pipe[1]);
01269 
01270   if (sitter != NULL)
01271     _dbus_babysitter_unref (sitter);
01272   
01273   return FALSE;
01274 }
01275 
01278 #ifdef DBUS_BUILD_TESTS
01279 
01280 static void
01281 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
01282 {
01283   while (LIVE_CHILDREN (sitter))
01284     babysitter_iteration (sitter, TRUE);
01285 }
01286 
01287 static dbus_bool_t
01288 check_spawn_nonexistent (void *data)
01289 {
01290   char *argv[4] = { NULL, NULL, NULL, NULL };
01291   DBusBabysitter *sitter = NULL;
01292   DBusError error = DBUS_ERROR_INIT;
01293 
01294   /*** Test launching nonexistent binary */
01295   
01296   argv[0] = "/this/does/not/exist/32542sdgafgafdg";
01297   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01298                                          NULL, NULL, NULL,
01299                                          &error))
01300     {
01301       _dbus_babysitter_block_for_child_exit (sitter);
01302       _dbus_babysitter_set_child_exit_error (sitter, &error);
01303     }
01304 
01305   if (sitter)
01306     _dbus_babysitter_unref (sitter);
01307 
01308   if (!dbus_error_is_set (&error))
01309     {
01310       _dbus_warn ("Did not get an error launching nonexistent executable\n");
01311       return FALSE;
01312     }
01313 
01314   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01315         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
01316     {
01317       _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
01318                   error.name, error.message);
01319       dbus_error_free (&error);
01320       return FALSE;
01321     }
01322 
01323   dbus_error_free (&error);
01324   
01325   return TRUE;
01326 }
01327 
01328 static dbus_bool_t
01329 check_spawn_segfault (void *data)
01330 {
01331   char *argv[4] = { NULL, NULL, NULL, NULL };
01332   DBusBabysitter *sitter = NULL;
01333   DBusError error = DBUS_ERROR_INIT;
01334 
01335   /*** Test launching segfault binary */
01336   
01337   argv[0] = TEST_SEGFAULT_BINARY;
01338   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01339                                          NULL, NULL, NULL,
01340                                          &error))
01341     {
01342       _dbus_babysitter_block_for_child_exit (sitter);
01343       _dbus_babysitter_set_child_exit_error (sitter, &error);
01344     }
01345 
01346   if (sitter)
01347     _dbus_babysitter_unref (sitter);
01348 
01349   if (!dbus_error_is_set (&error))
01350     {
01351       _dbus_warn ("Did not get an error launching segfaulting binary\n");
01352       return FALSE;
01353     }
01354 
01355   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01356         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01357     {
01358       _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
01359                   error.name, error.message);
01360       dbus_error_free (&error);
01361       return FALSE;
01362     }
01363 
01364   dbus_error_free (&error);
01365   
01366   return TRUE;
01367 }
01368 
01369 static dbus_bool_t
01370 check_spawn_exit (void *data)
01371 {
01372   char *argv[4] = { NULL, NULL, NULL, NULL };
01373   DBusBabysitter *sitter = NULL;
01374   DBusError error = DBUS_ERROR_INIT;
01375 
01376   /*** Test launching exit failure binary */
01377   
01378   argv[0] = TEST_EXIT_BINARY;
01379   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01380                                          NULL, NULL, NULL,
01381                                          &error))
01382     {
01383       _dbus_babysitter_block_for_child_exit (sitter);
01384       _dbus_babysitter_set_child_exit_error (sitter, &error);
01385     }
01386 
01387   if (sitter)
01388     _dbus_babysitter_unref (sitter);
01389 
01390   if (!dbus_error_is_set (&error))
01391     {
01392       _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
01393       return FALSE;
01394     }
01395 
01396   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01397         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
01398     {
01399       _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
01400                   error.name, error.message);
01401       dbus_error_free (&error);
01402       return FALSE;
01403     }
01404 
01405   dbus_error_free (&error);
01406   
01407   return TRUE;
01408 }
01409 
01410 static dbus_bool_t
01411 check_spawn_and_kill (void *data)
01412 {
01413   char *argv[4] = { NULL, NULL, NULL, NULL };
01414   DBusBabysitter *sitter = NULL;
01415   DBusError error = DBUS_ERROR_INIT;
01416 
01417   /*** Test launching sleeping binary then killing it */
01418 
01419   argv[0] = TEST_SLEEP_FOREVER_BINARY;
01420   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01421                                          NULL, NULL, NULL,
01422                                          &error))
01423     {
01424       _dbus_babysitter_kill_child (sitter);
01425       
01426       _dbus_babysitter_block_for_child_exit (sitter);
01427       
01428       _dbus_babysitter_set_child_exit_error (sitter, &error);
01429     }
01430 
01431   if (sitter)
01432     _dbus_babysitter_unref (sitter);
01433 
01434   if (!dbus_error_is_set (&error))
01435     {
01436       _dbus_warn ("Did not get an error after killing spawned binary\n");
01437       return FALSE;
01438     }
01439 
01440   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01441         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01442     {
01443       _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
01444                   error.name, error.message);
01445       dbus_error_free (&error);
01446       return FALSE;
01447     }
01448 
01449   dbus_error_free (&error);
01450   
01451   return TRUE;
01452 }
01453 
01454 dbus_bool_t
01455 _dbus_spawn_test (const char *test_data_dir)
01456 {
01457   if (!_dbus_test_oom_handling ("spawn_nonexistent",
01458                                 check_spawn_nonexistent,
01459                                 NULL))
01460     return FALSE;
01461 
01462   if (!_dbus_test_oom_handling ("spawn_segfault",
01463                                 check_spawn_segfault,
01464                                 NULL))
01465     return FALSE;
01466 
01467   if (!_dbus_test_oom_handling ("spawn_exit",
01468                                 check_spawn_exit,
01469                                 NULL))
01470     return FALSE;
01471 
01472   if (!_dbus_test_oom_handling ("spawn_and_kill",
01473                                 check_spawn_and_kill,
01474                                 NULL))
01475     return FALSE;
01476   
01477   return TRUE;
01478 }
01479 #endif

Generated on Tue Dec 21 2010 for D-Bus by  doxygen 1.7.1