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

Generated on Mon Feb 1 19:15:26 2010 for D-Bus by  doxygen 1.4.7