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       ssize_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       ssize_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 = DBUS_ERROR_INIT;
00370   ReadStatus r;
00371 
00372   r = read_ints (fd, &what, 1, &got, &error);
00373 
00374   switch (r)
00375     {
00376     case READ_STATUS_ERROR:
00377       _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message);
00378       dbus_error_free (&error);
00379       return r;
00380 
00381     case READ_STATUS_EOF:
00382       return r;
00383 
00384     case READ_STATUS_OK:
00385       break;
00386     }
00387   
00388   if (got == 1)
00389     {
00390       switch (what)
00391         {
00392         case CHILD_EXITED:
00393         case CHILD_FORK_FAILED:
00394         case CHILD_EXEC_FAILED:
00395           {
00396             int arg;
00397             
00398             r = read_ints (fd, &arg, 1, &got, &error);
00399 
00400             switch (r)
00401               {
00402               case READ_STATUS_ERROR:
00403                 _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message);
00404                 dbus_error_free (&error);
00405                 return r;
00406               case READ_STATUS_EOF:
00407                 return r;
00408               case READ_STATUS_OK:
00409                 break;
00410               }
00411             
00412             if (got == 1)
00413               {
00414                 if (what == CHILD_EXITED)
00415                   {
00416                     sitter->have_child_status = TRUE;
00417                     sitter->status = arg;
00418                     sitter->errnum = 0;
00419                     _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
00420                                    WIFEXITED (sitter->status), WIFSIGNALED (sitter->status),
00421                                    WEXITSTATUS (sitter->status), WTERMSIG (sitter->status));
00422                   }
00423                 else if (what == CHILD_FORK_FAILED)
00424                   {
00425                     sitter->have_fork_errnum = TRUE;
00426                     sitter->errnum = arg;
00427                     _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum);
00428                   }
00429                 else if (what == CHILD_EXEC_FAILED)
00430                   {
00431                     sitter->have_exec_errnum = TRUE;
00432                     sitter->errnum = arg;
00433                     _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum);
00434                   }
00435               }
00436           }
00437           break;
00438         case CHILD_PID:
00439           {
00440             pid_t pid = -1;
00441 
00442             r = read_pid (fd, &pid, &error);
00443             
00444             switch (r)
00445               {
00446               case READ_STATUS_ERROR:
00447                 _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message);
00448                 dbus_error_free (&error);
00449                 return r;
00450               case READ_STATUS_EOF:
00451                 return r;
00452               case READ_STATUS_OK:
00453                 break;
00454               }
00455             
00456             sitter->grandchild_pid = pid;
00457             
00458             _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid);
00459           }
00460           break;
00461         default:
00462           _dbus_warn ("Unknown message received from babysitter process\n");
00463           break;
00464         }
00465     }
00466 
00467   return r;
00468 }
00469 
00470 static void
00471 close_socket_to_babysitter (DBusBabysitter *sitter)
00472 {
00473   _dbus_verbose ("Closing babysitter\n");
00474   _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00475   sitter->socket_to_babysitter = -1;
00476 }
00477 
00478 static void
00479 close_error_pipe_from_child (DBusBabysitter *sitter)
00480 {
00481   _dbus_verbose ("Closing child error\n");
00482   _dbus_close_socket (sitter->error_pipe_from_child, NULL);
00483   sitter->error_pipe_from_child = -1;
00484 }
00485 
00486 static void
00487 handle_babysitter_socket (DBusBabysitter *sitter,
00488                           int             revents)
00489 {
00490   /* Even if we have POLLHUP, we want to keep reading
00491    * data until POLLIN goes away; so this function only
00492    * looks at HUP/ERR if no IN is set.
00493    */
00494   if (revents & _DBUS_POLLIN)
00495     {
00496       _dbus_verbose ("Reading data from babysitter\n");
00497       if (read_data (sitter, sitter->socket_to_babysitter) != READ_STATUS_OK)
00498         close_socket_to_babysitter (sitter);
00499     }
00500   else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00501     {
00502       close_socket_to_babysitter (sitter);
00503     }
00504 }
00505 
00506 static void
00507 handle_error_pipe (DBusBabysitter *sitter,
00508                    int             revents)
00509 {
00510   if (revents & _DBUS_POLLIN)
00511     {
00512       _dbus_verbose ("Reading data from child error\n");
00513       if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK)
00514         close_error_pipe_from_child (sitter);
00515     }
00516   else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00517     {
00518       close_error_pipe_from_child (sitter);
00519     }
00520 }
00521 
00522 /* returns whether there were any poll events handled */
00523 static dbus_bool_t
00524 babysitter_iteration (DBusBabysitter *sitter,
00525                       dbus_bool_t     block)
00526 {
00527   DBusPollFD fds[2];
00528   int i;
00529   dbus_bool_t descriptors_ready;
00530 
00531   descriptors_ready = FALSE;
00532   
00533   i = 0;
00534 
00535   if (sitter->error_pipe_from_child >= 0)
00536     {
00537       fds[i].fd = sitter->error_pipe_from_child;
00538       fds[i].events = _DBUS_POLLIN;
00539       fds[i].revents = 0;
00540       ++i;
00541     }
00542   
00543   if (sitter->socket_to_babysitter >= 0)
00544     {
00545       fds[i].fd = sitter->socket_to_babysitter;
00546       fds[i].events = _DBUS_POLLIN;
00547       fds[i].revents = 0;
00548       ++i;
00549     }
00550 
00551   if (i > 0)
00552     {
00553       int ret;
00554 
00555       do
00556         {
00557           ret = _dbus_poll (fds, i, 0);
00558         }
00559       while (ret < 0 && errno == EINTR);
00560 
00561       if (ret == 0 && block)
00562         {
00563           do
00564             {
00565               ret = _dbus_poll (fds, i, -1);
00566             }
00567           while (ret < 0 && errno == EINTR);
00568         }
00569 
00570       if (ret > 0)
00571         {
00572           descriptors_ready = TRUE;
00573           
00574           while (i > 0)
00575             {
00576               --i;
00577               if (fds[i].fd == sitter->error_pipe_from_child)
00578                 handle_error_pipe (sitter, fds[i].revents);
00579               else if (fds[i].fd == sitter->socket_to_babysitter)
00580                 handle_babysitter_socket (sitter, fds[i].revents);
00581             }
00582         }
00583     }
00584 
00585   return descriptors_ready;
00586 }
00587 
00592 #define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter >= 0 || (sitter)->error_pipe_from_child >= 0)
00593 
00600 void
00601 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
00602 {
00603   /* be sure we have the PID of the child */
00604   while (LIVE_CHILDREN (sitter) &&
00605          sitter->grandchild_pid == -1)
00606     babysitter_iteration (sitter, TRUE);
00607 
00608   _dbus_verbose ("Got child PID %ld for killing\n",
00609                  (long) sitter->grandchild_pid);
00610   
00611   if (sitter->grandchild_pid == -1)
00612     return; /* child is already dead, or we're so hosed we'll never recover */
00613 
00614   kill (sitter->grandchild_pid, SIGKILL);
00615 }
00616 
00622 dbus_bool_t
00623 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
00624 {
00625 
00626   /* Be sure we're up-to-date */
00627   while (LIVE_CHILDREN (sitter) &&
00628          babysitter_iteration (sitter, FALSE))
00629     ;
00630 
00631   /* We will have exited the babysitter when the child has exited */
00632   return sitter->socket_to_babysitter < 0;
00633 }
00634 
00647 dbus_bool_t
00648 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
00649                                         int            *status)
00650 {
00651   if (!_dbus_babysitter_get_child_exited (sitter))
00652     _dbus_assert_not_reached ("Child has not exited");
00653   
00654   if (!sitter->have_child_status ||
00655       !(WIFEXITED (sitter->status)))
00656     return FALSE;
00657 
00658   *status = WEXITSTATUS (sitter->status);
00659   return TRUE;
00660 }
00661 
00671 void
00672 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
00673                                        DBusError      *error)
00674 {
00675   if (!_dbus_babysitter_get_child_exited (sitter))
00676     return;
00677 
00678   /* Note that if exec fails, we will also get a child status
00679    * from the babysitter saying the child exited,
00680    * so we need to give priority to the exec error
00681    */
00682   if (sitter->have_exec_errnum)
00683     {
00684       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00685                       "Failed to execute program %s: %s",
00686                       sitter->executable, _dbus_strerror (sitter->errnum));
00687     }
00688   else if (sitter->have_fork_errnum)
00689     {
00690       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00691                       "Failed to fork a new process %s: %s",
00692                       sitter->executable, _dbus_strerror (sitter->errnum));
00693     }
00694   else if (sitter->have_child_status)
00695     {
00696       if (WIFEXITED (sitter->status))
00697         dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00698                         "Process %s exited with status %d",
00699                         sitter->executable, WEXITSTATUS (sitter->status));
00700       else if (WIFSIGNALED (sitter->status))
00701         dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,
00702                         "Process %s received signal %d",
00703                         sitter->executable, WTERMSIG (sitter->status));
00704       else
00705         dbus_set_error (error, DBUS_ERROR_FAILED,
00706                         "Process %s exited abnormally",
00707                         sitter->executable);
00708     }
00709   else
00710     {
00711       dbus_set_error (error, DBUS_ERROR_FAILED,
00712                       "Process %s exited, reason unknown",
00713                       sitter->executable);
00714     }
00715 }
00716 
00729 dbus_bool_t
00730 _dbus_babysitter_set_watch_functions (DBusBabysitter            *sitter,
00731                                       DBusAddWatchFunction       add_function,
00732                                       DBusRemoveWatchFunction    remove_function,
00733                                       DBusWatchToggledFunction   toggled_function,
00734                                       void                      *data,
00735                                       DBusFreeFunction           free_data_function)
00736 {
00737   return _dbus_watch_list_set_functions (sitter->watches,
00738                                          add_function,
00739                                          remove_function,
00740                                          toggled_function,
00741                                          data,
00742                                          free_data_function);
00743 }
00744 
00745 static dbus_bool_t
00746 handle_watch (DBusWatch       *watch,
00747               unsigned int     condition,
00748               void            *data)
00749 {
00750   DBusBabysitter *sitter = data;
00751   int revents;
00752   int fd;
00753   
00754   revents = 0;
00755   if (condition & DBUS_WATCH_READABLE)
00756     revents |= _DBUS_POLLIN;
00757   if (condition & DBUS_WATCH_ERROR)
00758     revents |= _DBUS_POLLERR;
00759   if (condition & DBUS_WATCH_HANGUP)
00760     revents |= _DBUS_POLLHUP;
00761 
00762   fd = dbus_watch_get_socket (watch);
00763 
00764   if (fd == sitter->error_pipe_from_child)
00765     handle_error_pipe (sitter, revents);
00766   else if (fd == sitter->socket_to_babysitter)
00767     handle_babysitter_socket (sitter, revents);
00768 
00769   while (LIVE_CHILDREN (sitter) &&
00770          babysitter_iteration (sitter, FALSE))
00771     ;
00772   
00773   return TRUE;
00774 }
00775 
00777 #define READ_END 0
00778 
00779 #define WRITE_END 1
00780 
00781 
00782 /* Avoids a danger in threaded situations (calling close()
00783  * on a file descriptor twice, and another thread has
00784  * re-opened it since the first close)
00785  */
00786 static int
00787 close_and_invalidate (int *fd)
00788 {
00789   int ret;
00790 
00791   if (*fd < 0)
00792     return -1;
00793   else
00794     {
00795       ret = _dbus_close_socket (*fd, NULL);
00796       *fd = -1;
00797     }
00798 
00799   return ret;
00800 }
00801 
00802 static dbus_bool_t
00803 make_pipe (int         p[2],
00804            DBusError  *error)
00805 {
00806   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00807   
00808   if (pipe (p) < 0)
00809     {
00810       dbus_set_error (error,
00811                       DBUS_ERROR_SPAWN_FAILED,
00812                       "Failed to create pipe for communicating with child process (%s)",
00813                       _dbus_strerror (errno));
00814       return FALSE;
00815     }
00816 
00817   return TRUE;
00818 }
00819 
00820 static void
00821 do_write (int fd, const void *buf, size_t count)
00822 {
00823   size_t bytes_written;
00824   int ret;
00825   
00826   bytes_written = 0;
00827   
00828  again:
00829   
00830   ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
00831 
00832   if (ret < 0)
00833     {
00834       if (errno == EINTR)
00835         goto again;
00836       else
00837         {
00838           _dbus_warn ("Failed to write data to pipe!\n");
00839           exit (1); /* give up, we suck */
00840         }
00841     }
00842   else
00843     bytes_written += ret;
00844   
00845   if (bytes_written < count)
00846     goto again;
00847 }
00848 
00849 static void
00850 write_err_and_exit (int fd, int msg)
00851 {
00852   int en = errno;
00853 
00854   do_write (fd, &msg, sizeof (msg));
00855   do_write (fd, &en, sizeof (en));
00856   
00857   exit (1);
00858 }
00859 
00860 static void
00861 write_pid (int fd, pid_t pid)
00862 {
00863   int msg = CHILD_PID;
00864   
00865   do_write (fd, &msg, sizeof (msg));
00866   do_write (fd, &pid, sizeof (pid));
00867 }
00868 
00869 static void
00870 write_status_and_exit (int fd, int status)
00871 {
00872   int msg = CHILD_EXITED;
00873   
00874   do_write (fd, &msg, sizeof (msg));
00875   do_write (fd, &status, sizeof (status));
00876   
00877   exit (0);
00878 }
00879 
00880 static void
00881 do_exec (int                       child_err_report_fd,
00882          char                    **argv,
00883          char                    **envp,
00884          DBusSpawnChildSetupFunc   child_setup,
00885          void                     *user_data)
00886 {
00887 #ifdef DBUS_BUILD_TESTS
00888   int i, max_open;
00889 #endif
00890 
00891   _dbus_verbose_reset ();
00892   _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n",
00893                  _dbus_getpid ());
00894   
00895   if (child_setup)
00896     (* child_setup) (user_data);
00897 
00898 #ifdef DBUS_BUILD_TESTS
00899   max_open = sysconf (_SC_OPEN_MAX);
00900   
00901   for (i = 3; i < max_open; i++)
00902     {
00903       int retval;
00904 
00905       if (i == child_err_report_fd)
00906         continue;
00907       
00908       retval = fcntl (i, F_GETFD);
00909 
00910       if (retval != -1 && !(retval & FD_CLOEXEC))
00911         _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
00912     }
00913 #endif
00914 
00915   if (envp == NULL)
00916     {
00917       extern char **environ;
00918 
00919       _dbus_assert (environ != NULL);
00920 
00921       envp = environ;
00922     }
00923   
00924   execve (argv[0], argv, envp);
00925   
00926   /* Exec failed */
00927   write_err_and_exit (child_err_report_fd,
00928                       CHILD_EXEC_FAILED);
00929 }
00930 
00931 static void
00932 check_babysit_events (pid_t grandchild_pid,
00933                       int   parent_pipe,
00934                       int   revents)
00935 {
00936   pid_t ret;
00937   int status;
00938   
00939   do
00940     {
00941       ret = waitpid (grandchild_pid, &status, WNOHANG);
00942       /* The man page says EINTR can't happen with WNOHANG,
00943        * but there are reports of it (maybe only with valgrind?)
00944        */
00945     }
00946   while (ret < 0 && errno == EINTR);
00947 
00948   if (ret == 0)
00949     {
00950       _dbus_verbose ("no child exited\n");
00951       
00952       ; /* no child exited */
00953     }
00954   else if (ret < 0)
00955     {
00956       /* This isn't supposed to happen. */
00957       _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n",
00958                   _dbus_strerror (errno));
00959       exit (1);
00960     }
00961   else if (ret == grandchild_pid)
00962     {
00963       /* Child exited */
00964       _dbus_verbose ("reaped child pid %ld\n", (long) ret);
00965       
00966       write_status_and_exit (parent_pipe, status);
00967     }
00968   else
00969     {
00970       _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n",
00971                   (int) ret);
00972       exit (1);
00973     }
00974 
00975   if (revents & _DBUS_POLLIN)
00976     {
00977       _dbus_verbose ("babysitter got POLLIN from parent pipe\n");
00978     }
00979 
00980   if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00981     {
00982       /* Parent is gone, so we just exit */
00983       _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n");
00984       exit (0);
00985     }
00986 }
00987 
00988 static int babysit_sigchld_pipe = -1;
00989 
00990 static void
00991 babysit_signal_handler (int signo)
00992 {
00993   char b = '\0';
00994  again:
00995   if (write (babysit_sigchld_pipe, &b, 1) <= 0) 
00996     if (errno == EINTR)
00997       goto again;
00998 }
00999 
01000 static void
01001 babysit (pid_t grandchild_pid,
01002          int   parent_pipe)
01003 {
01004   int sigchld_pipe[2];
01005 
01006   /* We don't exec, so we keep parent state, such as the pid that
01007    * _dbus_verbose() uses. Reset the pid here.
01008    */
01009   _dbus_verbose_reset ();
01010   
01011   /* I thought SIGCHLD would just wake up the poll, but
01012    * that didn't seem to work, so added this pipe.
01013    * Probably the pipe is more likely to work on busted
01014    * operating systems anyhow.
01015    */
01016   if (pipe (sigchld_pipe) < 0)
01017     {
01018       _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n");
01019       exit (1);
01020     }
01021 
01022   babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
01023 
01024   _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
01025   
01026   write_pid (parent_pipe, grandchild_pid);
01027 
01028   check_babysit_events (grandchild_pid, parent_pipe, 0);
01029 
01030   while (TRUE)
01031     {
01032       DBusPollFD pfds[2];
01033       
01034       pfds[0].fd = parent_pipe;
01035       pfds[0].events = _DBUS_POLLIN;
01036       pfds[0].revents = 0;
01037 
01038       pfds[1].fd = sigchld_pipe[READ_END];
01039       pfds[1].events = _DBUS_POLLIN;
01040       pfds[1].revents = 0;
01041       
01042       if (_dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1) < 0 && errno != EINTR)
01043         {
01044           _dbus_warn ("_dbus_poll() error: %s\n", strerror (errno));
01045           exit (1);
01046         }
01047 
01048       if (pfds[0].revents != 0)
01049         {
01050           check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
01051         }
01052       else if (pfds[1].revents & _DBUS_POLLIN)
01053         {
01054           char b;
01055           read (sigchld_pipe[READ_END], &b, 1);
01056           /* do waitpid check */
01057           check_babysit_events (grandchild_pid, parent_pipe, 0);
01058         }
01059     }
01060   
01061   exit (1);
01062 }
01063 
01083 dbus_bool_t
01084 _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
01085                                    char                    **argv,
01086                                    char                    **env,
01087                                    DBusSpawnChildSetupFunc   child_setup,
01088                                    void                     *user_data,
01089                                    DBusError                *error)
01090 {
01091   DBusBabysitter *sitter;
01092   int child_err_report_pipe[2] = { -1, -1 };
01093   int babysitter_pipe[2] = { -1, -1 };
01094   pid_t pid;
01095   
01096   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01097 
01098   if (sitter_p != NULL)
01099     *sitter_p = NULL;
01100 
01101   sitter = NULL;
01102 
01103   sitter = _dbus_babysitter_new ();
01104   if (sitter == NULL)
01105     {
01106       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01107       return FALSE;
01108     }
01109 
01110   sitter->executable = _dbus_strdup (argv[0]);
01111   if (sitter->executable == NULL)
01112     {
01113       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01114       goto cleanup_and_fail;
01115     }
01116   
01117   if (!make_pipe (child_err_report_pipe, error))
01118     goto cleanup_and_fail;
01119 
01120   _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]);
01121   _dbus_fd_set_close_on_exec (child_err_report_pipe[WRITE_END]);
01122 
01123   if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
01124     goto cleanup_and_fail;
01125 
01126   _dbus_fd_set_close_on_exec (babysitter_pipe[0]);
01127   _dbus_fd_set_close_on_exec (babysitter_pipe[1]);
01128 
01129   /* Setting up the babysitter is only useful in the parent,
01130    * but we don't want to run out of memory and fail
01131    * after we've already forked, since then we'd leak
01132    * child processes everywhere.
01133    */
01134   sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
01135                                          DBUS_WATCH_READABLE,
01136                                          TRUE, handle_watch, sitter, NULL);
01137   if (sitter->error_watch == NULL)
01138     {
01139       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01140       goto cleanup_and_fail;
01141     }
01142         
01143   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->error_watch))
01144     {
01145       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01146       goto cleanup_and_fail;
01147     }
01148       
01149   sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
01150                                           DBUS_WATCH_READABLE,
01151                                           TRUE, handle_watch, sitter, NULL);
01152   if (sitter->sitter_watch == NULL)
01153     {
01154       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01155       goto cleanup_and_fail;
01156     }
01157       
01158   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
01159     {
01160       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01161       goto cleanup_and_fail;
01162     }
01163 
01164   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01165   
01166   pid = fork ();
01167   
01168   if (pid < 0)
01169     {
01170       dbus_set_error (error,
01171                       DBUS_ERROR_SPAWN_FORK_FAILED,
01172                       "Failed to fork (%s)",
01173                       _dbus_strerror (errno));
01174       goto cleanup_and_fail;
01175     }
01176   else if (pid == 0)
01177     {
01178       /* Immediate child, this is the babysitter process. */
01179       int grandchild_pid;
01180       
01181       /* Be sure we crash if the parent exits
01182        * and we write to the err_report_pipe
01183        */
01184       signal (SIGPIPE, SIG_DFL);
01185 
01186       /* Close the parent's end of the pipes. */
01187       close_and_invalidate (&child_err_report_pipe[READ_END]);
01188       close_and_invalidate (&babysitter_pipe[0]);
01189       
01190       /* Create the child that will exec () */
01191       grandchild_pid = fork ();
01192       
01193       if (grandchild_pid < 0)
01194         {
01195           write_err_and_exit (babysitter_pipe[1],
01196                               CHILD_FORK_FAILED);
01197           _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
01198         }
01199       else if (grandchild_pid == 0)
01200         {
01201           do_exec (child_err_report_pipe[WRITE_END],
01202                    argv,
01203                    env,
01204                    child_setup, user_data);
01205           _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
01206         }
01207       else
01208         {
01209           babysit (grandchild_pid, babysitter_pipe[1]);
01210           _dbus_assert_not_reached ("Got to code after babysit()");
01211         }
01212     }
01213   else
01214     {      
01215       /* Close the uncared-about ends of the pipes */
01216       close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01217       close_and_invalidate (&babysitter_pipe[1]);
01218 
01219       sitter->socket_to_babysitter = babysitter_pipe[0];
01220       babysitter_pipe[0] = -1;
01221       
01222       sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
01223       child_err_report_pipe[READ_END] = -1;
01224 
01225       sitter->sitter_pid = pid;
01226 
01227       if (sitter_p != NULL)
01228         *sitter_p = sitter;
01229       else
01230         _dbus_babysitter_unref (sitter);
01231 
01232       dbus_free_string_array (env);
01233 
01234       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01235       
01236       return TRUE;
01237     }
01238 
01239  cleanup_and_fail:
01240 
01241   _DBUS_ASSERT_ERROR_IS_SET (error);
01242   
01243   close_and_invalidate (&child_err_report_pipe[READ_END]);
01244   close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01245   close_and_invalidate (&babysitter_pipe[0]);
01246   close_and_invalidate (&babysitter_pipe[1]);
01247 
01248   if (sitter != NULL)
01249     _dbus_babysitter_unref (sitter);
01250   
01251   return FALSE;
01252 }
01253 
01256 #ifdef DBUS_BUILD_TESTS
01257 
01258 static void
01259 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
01260 {
01261   while (LIVE_CHILDREN (sitter))
01262     babysitter_iteration (sitter, TRUE);
01263 }
01264 
01265 static dbus_bool_t
01266 check_spawn_nonexistent (void *data)
01267 {
01268   char *argv[4] = { NULL, NULL, NULL, NULL };
01269   DBusBabysitter *sitter = NULL;
01270   DBusError error = DBUS_ERROR_INIT;
01271 
01272   /*** Test launching nonexistent binary */
01273   
01274   argv[0] = "/this/does/not/exist/32542sdgafgafdg";
01275   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01276                                          NULL, NULL, NULL,
01277                                          &error))
01278     {
01279       _dbus_babysitter_block_for_child_exit (sitter);
01280       _dbus_babysitter_set_child_exit_error (sitter, &error);
01281     }
01282 
01283   if (sitter)
01284     _dbus_babysitter_unref (sitter);
01285 
01286   if (!dbus_error_is_set (&error))
01287     {
01288       _dbus_warn ("Did not get an error launching nonexistent executable\n");
01289       return FALSE;
01290     }
01291 
01292   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01293         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
01294     {
01295       _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
01296                   error.name, error.message);
01297       dbus_error_free (&error);
01298       return FALSE;
01299     }
01300 
01301   dbus_error_free (&error);
01302   
01303   return TRUE;
01304 }
01305 
01306 static dbus_bool_t
01307 check_spawn_segfault (void *data)
01308 {
01309   char *argv[4] = { NULL, NULL, NULL, NULL };
01310   DBusBabysitter *sitter = NULL;
01311   DBusError error = DBUS_ERROR_INIT;
01312 
01313   /*** Test launching segfault binary */
01314   
01315   argv[0] = TEST_SEGFAULT_BINARY;
01316   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01317                                          NULL, NULL, NULL,
01318                                          &error))
01319     {
01320       _dbus_babysitter_block_for_child_exit (sitter);
01321       _dbus_babysitter_set_child_exit_error (sitter, &error);
01322     }
01323 
01324   if (sitter)
01325     _dbus_babysitter_unref (sitter);
01326 
01327   if (!dbus_error_is_set (&error))
01328     {
01329       _dbus_warn ("Did not get an error launching segfaulting binary\n");
01330       return FALSE;
01331     }
01332 
01333   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01334         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01335     {
01336       _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
01337                   error.name, error.message);
01338       dbus_error_free (&error);
01339       return FALSE;
01340     }
01341 
01342   dbus_error_free (&error);
01343   
01344   return TRUE;
01345 }
01346 
01347 static dbus_bool_t
01348 check_spawn_exit (void *data)
01349 {
01350   char *argv[4] = { NULL, NULL, NULL, NULL };
01351   DBusBabysitter *sitter = NULL;
01352   DBusError error = DBUS_ERROR_INIT;
01353 
01354   /*** Test launching exit failure binary */
01355   
01356   argv[0] = TEST_EXIT_BINARY;
01357   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01358                                          NULL, NULL, NULL,
01359                                          &error))
01360     {
01361       _dbus_babysitter_block_for_child_exit (sitter);
01362       _dbus_babysitter_set_child_exit_error (sitter, &error);
01363     }
01364 
01365   if (sitter)
01366     _dbus_babysitter_unref (sitter);
01367 
01368   if (!dbus_error_is_set (&error))
01369     {
01370       _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
01371       return FALSE;
01372     }
01373 
01374   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01375         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
01376     {
01377       _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
01378                   error.name, error.message);
01379       dbus_error_free (&error);
01380       return FALSE;
01381     }
01382 
01383   dbus_error_free (&error);
01384   
01385   return TRUE;
01386 }
01387 
01388 static dbus_bool_t
01389 check_spawn_and_kill (void *data)
01390 {
01391   char *argv[4] = { NULL, NULL, NULL, NULL };
01392   DBusBabysitter *sitter = NULL;
01393   DBusError error = DBUS_ERROR_INIT;
01394 
01395   /*** Test launching sleeping binary then killing it */
01396 
01397   argv[0] = TEST_SLEEP_FOREVER_BINARY;
01398   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01399                                          NULL, NULL, NULL,
01400                                          &error))
01401     {
01402       _dbus_babysitter_kill_child (sitter);
01403       
01404       _dbus_babysitter_block_for_child_exit (sitter);
01405       
01406       _dbus_babysitter_set_child_exit_error (sitter, &error);
01407     }
01408 
01409   if (sitter)
01410     _dbus_babysitter_unref (sitter);
01411 
01412   if (!dbus_error_is_set (&error))
01413     {
01414       _dbus_warn ("Did not get an error after killing spawned binary\n");
01415       return FALSE;
01416     }
01417 
01418   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01419         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01420     {
01421       _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
01422                   error.name, error.message);
01423       dbus_error_free (&error);
01424       return FALSE;
01425     }
01426 
01427   dbus_error_free (&error);
01428   
01429   return TRUE;
01430 }
01431 
01432 dbus_bool_t
01433 _dbus_spawn_test (const char *test_data_dir)
01434 {
01435   if (!_dbus_test_oom_handling ("spawn_nonexistent",
01436                                 check_spawn_nonexistent,
01437                                 NULL))
01438     return FALSE;
01439 
01440   if (!_dbus_test_oom_handling ("spawn_segfault",
01441                                 check_spawn_segfault,
01442                                 NULL))
01443     return FALSE;
01444 
01445   if (!_dbus_test_oom_handling ("spawn_exit",
01446                                 check_spawn_exit,
01447                                 NULL))
01448     return FALSE;
01449 
01450   if (!_dbus_test_oom_handling ("spawn_and_kill",
01451                                 check_spawn_and_kill,
01452                                 NULL))
01453     return FALSE;
01454   
01455   return TRUE;
01456 }
01457 #endif

Generated on Thu Jan 22 16:37:06 2009 for D-Bus by  doxygen 1.5.1