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

Generated on Fri Jul 11 2014 20:41:53 for D-Bus by  doxygen 1.7.1