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          DBusSpawnChildSetupFunc   child_setup,
00884          void                     *user_data)
00885 {
00886 #ifdef DBUS_BUILD_TESTS
00887   int i, max_open;
00888 #endif
00889 
00890   _dbus_verbose_reset ();
00891   _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n",
00892                  _dbus_getpid ());
00893   
00894   if (child_setup)
00895     (* child_setup) (user_data);
00896 
00897 #ifdef DBUS_BUILD_TESTS
00898   max_open = sysconf (_SC_OPEN_MAX);
00899   
00900   for (i = 3; i < max_open; i++)
00901     {
00902       int retval;
00903 
00904       if (i == child_err_report_fd)
00905         continue;
00906       
00907       retval = fcntl (i, F_GETFD);
00908 
00909       if (retval != -1 && !(retval & FD_CLOEXEC))
00910         _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
00911     }
00912 #endif
00913   
00914   execv (argv[0], argv);
00915   
00916   /* Exec failed */
00917   write_err_and_exit (child_err_report_fd,
00918                       CHILD_EXEC_FAILED);
00919 }
00920 
00921 static void
00922 check_babysit_events (pid_t grandchild_pid,
00923                       int   parent_pipe,
00924                       int   revents)
00925 {
00926   pid_t ret;
00927   int status;
00928   
00929   do
00930     {
00931       ret = waitpid (grandchild_pid, &status, WNOHANG);
00932       /* The man page says EINTR can't happen with WNOHANG,
00933        * but there are reports of it (maybe only with valgrind?)
00934        */
00935     }
00936   while (ret < 0 && errno == EINTR);
00937 
00938   if (ret == 0)
00939     {
00940       _dbus_verbose ("no child exited\n");
00941       
00942       ; /* no child exited */
00943     }
00944   else if (ret < 0)
00945     {
00946       /* This isn't supposed to happen. */
00947       _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n",
00948                   _dbus_strerror (errno));
00949       exit (1);
00950     }
00951   else if (ret == grandchild_pid)
00952     {
00953       /* Child exited */
00954       _dbus_verbose ("reaped child pid %ld\n", (long) ret);
00955       
00956       write_status_and_exit (parent_pipe, status);
00957     }
00958   else
00959     {
00960       _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n",
00961                   (int) ret);
00962       exit (1);
00963     }
00964 
00965   if (revents & _DBUS_POLLIN)
00966     {
00967       _dbus_verbose ("babysitter got POLLIN from parent pipe\n");
00968     }
00969 
00970   if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP))
00971     {
00972       /* Parent is gone, so we just exit */
00973       _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n");
00974       exit (0);
00975     }
00976 }
00977 
00978 static int babysit_sigchld_pipe = -1;
00979 
00980 static void
00981 babysit_signal_handler (int signo)
00982 {
00983   char b = '\0';
00984  again:
00985   if (write (babysit_sigchld_pipe, &b, 1) <= 0) 
00986     if (errno == EINTR)
00987       goto again;
00988 }
00989 
00990 static void
00991 babysit (pid_t grandchild_pid,
00992          int   parent_pipe)
00993 {
00994   int sigchld_pipe[2];
00995 
00996   /* We don't exec, so we keep parent state, such as the pid that
00997    * _dbus_verbose() uses. Reset the pid here.
00998    */
00999   _dbus_verbose_reset ();
01000   
01001   /* I thought SIGCHLD would just wake up the poll, but
01002    * that didn't seem to work, so added this pipe.
01003    * Probably the pipe is more likely to work on busted
01004    * operating systems anyhow.
01005    */
01006   if (pipe (sigchld_pipe) < 0)
01007     {
01008       _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n");
01009       exit (1);
01010     }
01011 
01012   babysit_sigchld_pipe = sigchld_pipe[WRITE_END];
01013 
01014   _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler);
01015   
01016   write_pid (parent_pipe, grandchild_pid);
01017 
01018   check_babysit_events (grandchild_pid, parent_pipe, 0);
01019 
01020   while (TRUE)
01021     {
01022       DBusPollFD pfds[2];
01023       
01024       pfds[0].fd = parent_pipe;
01025       pfds[0].events = _DBUS_POLLIN;
01026       pfds[0].revents = 0;
01027 
01028       pfds[1].fd = sigchld_pipe[READ_END];
01029       pfds[1].events = _DBUS_POLLIN;
01030       pfds[1].revents = 0;
01031       
01032       if (_dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1) < 0 && errno != EINTR)
01033         {
01034           _dbus_warn ("_dbus_poll() error: %s\n", strerror (errno));
01035           exit (1);
01036         }
01037 
01038       if (pfds[0].revents != 0)
01039         {
01040           check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents);
01041         }
01042       else if (pfds[1].revents & _DBUS_POLLIN)
01043         {
01044           char b;
01045           read (sigchld_pipe[READ_END], &b, 1);
01046           /* do waitpid check */
01047           check_babysit_events (grandchild_pid, parent_pipe, 0);
01048         }
01049     }
01050   
01051   exit (1);
01052 }
01053 
01073 dbus_bool_t
01074 _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
01075                                    char                    **argv,
01076                                    char                    **env,
01077                                    DBusSpawnChildSetupFunc   child_setup,
01078                                    void                     *user_data,
01079                                    DBusError                *error)
01080 {
01081   DBusBabysitter *sitter;
01082   int child_err_report_pipe[2] = { -1, -1 };
01083   int babysitter_pipe[2] = { -1, -1 };
01084   pid_t pid;
01085   
01086   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01087 
01088   if (sitter_p != NULL)
01089     *sitter_p = NULL;
01090 
01091   sitter = NULL;
01092 
01093   sitter = _dbus_babysitter_new ();
01094   if (sitter == NULL)
01095     {
01096       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01097       return FALSE;
01098     }
01099 
01100   sitter->executable = _dbus_strdup (argv[0]);
01101   if (sitter->executable == NULL)
01102     {
01103       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01104       goto cleanup_and_fail;
01105     }
01106   
01107   if (!make_pipe (child_err_report_pipe, error))
01108     goto cleanup_and_fail;
01109 
01110   _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]);
01111   _dbus_fd_set_close_on_exec (child_err_report_pipe[WRITE_END]);
01112 
01113   if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
01114     goto cleanup_and_fail;
01115 
01116   _dbus_fd_set_close_on_exec (babysitter_pipe[0]);
01117   _dbus_fd_set_close_on_exec (babysitter_pipe[1]);
01118 
01119   /* Setting up the babysitter is only useful in the parent,
01120    * but we don't want to run out of memory and fail
01121    * after we've already forked, since then we'd leak
01122    * child processes everywhere.
01123    */
01124   sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
01125                                          DBUS_WATCH_READABLE,
01126                                          TRUE, handle_watch, sitter, NULL);
01127   if (sitter->error_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->error_watch))
01134     {
01135       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01136       goto cleanup_and_fail;
01137     }
01138       
01139   sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
01140                                           DBUS_WATCH_READABLE,
01141                                           TRUE, handle_watch, sitter, NULL);
01142   if (sitter->sitter_watch == NULL)
01143     {
01144       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01145       goto cleanup_and_fail;
01146     }
01147       
01148   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
01149     {
01150       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01151       goto cleanup_and_fail;
01152     }
01153 
01154   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01155   
01156   pid = fork ();
01157   
01158   if (pid < 0)
01159     {
01160       dbus_set_error (error,
01161                       DBUS_ERROR_SPAWN_FORK_FAILED,
01162                       "Failed to fork (%s)",
01163                       _dbus_strerror (errno));
01164       goto cleanup_and_fail;
01165     }
01166   else if (pid == 0)
01167     {
01168       /* Immediate child, this is the babysitter process. */
01169       int grandchild_pid;
01170       
01171       /* Be sure we crash if the parent exits
01172        * and we write to the err_report_pipe
01173        */
01174       signal (SIGPIPE, SIG_DFL);
01175 
01176       /* Close the parent's end of the pipes. */
01177       close_and_invalidate (&child_err_report_pipe[READ_END]);
01178       close_and_invalidate (&babysitter_pipe[0]);
01179       
01180       /* Create the child that will exec () */
01181       grandchild_pid = fork ();
01182       
01183       if (grandchild_pid < 0)
01184         {
01185           write_err_and_exit (babysitter_pipe[1],
01186                               CHILD_FORK_FAILED);
01187           _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
01188         }
01189       else if (grandchild_pid == 0)
01190         {
01191           do_exec (child_err_report_pipe[WRITE_END],
01192                    argv,
01193                    child_setup, user_data);
01194           _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
01195         }
01196       else
01197         {
01198           babysit (grandchild_pid, babysitter_pipe[1]);
01199           _dbus_assert_not_reached ("Got to code after babysit()");
01200         }
01201     }
01202   else
01203     {      
01204       /* Close the uncared-about ends of the pipes */
01205       close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01206       close_and_invalidate (&babysitter_pipe[1]);
01207 
01208       sitter->socket_to_babysitter = babysitter_pipe[0];
01209       babysitter_pipe[0] = -1;
01210       
01211       sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
01212       child_err_report_pipe[READ_END] = -1;
01213 
01214       sitter->sitter_pid = pid;
01215 
01216       if (sitter_p != NULL)
01217         *sitter_p = sitter;
01218       else
01219         _dbus_babysitter_unref (sitter);
01220 
01221       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01222       
01223       return TRUE;
01224     }
01225 
01226  cleanup_and_fail:
01227 
01228   _DBUS_ASSERT_ERROR_IS_SET (error);
01229   
01230   close_and_invalidate (&child_err_report_pipe[READ_END]);
01231   close_and_invalidate (&child_err_report_pipe[WRITE_END]);
01232   close_and_invalidate (&babysitter_pipe[0]);
01233   close_and_invalidate (&babysitter_pipe[1]);
01234 
01235   if (sitter != NULL)
01236     _dbus_babysitter_unref (sitter);
01237   
01238   return FALSE;
01239 }
01240 
01243 #ifdef DBUS_BUILD_TESTS
01244 
01245 static void
01246 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
01247 {
01248   while (LIVE_CHILDREN (sitter))
01249     babysitter_iteration (sitter, TRUE);
01250 }
01251 
01252 static dbus_bool_t
01253 check_spawn_nonexistent (void *data)
01254 {
01255   char *argv[4] = { NULL, NULL, NULL, NULL };
01256   DBusBabysitter *sitter = NULL;
01257   DBusError error = DBUS_ERROR_INIT;
01258 
01259   /*** Test launching nonexistent binary */
01260   
01261   argv[0] = "/this/does/not/exist/32542sdgafgafdg";
01262   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01263                                          NULL, NULL, NULL,
01264                                          &error))
01265     {
01266       _dbus_babysitter_block_for_child_exit (sitter);
01267       _dbus_babysitter_set_child_exit_error (sitter, &error);
01268     }
01269 
01270   if (sitter)
01271     _dbus_babysitter_unref (sitter);
01272 
01273   if (!dbus_error_is_set (&error))
01274     {
01275       _dbus_warn ("Did not get an error launching nonexistent executable\n");
01276       return FALSE;
01277     }
01278 
01279   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01280         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
01281     {
01282       _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
01283                   error.name, error.message);
01284       dbus_error_free (&error);
01285       return FALSE;
01286     }
01287 
01288   dbus_error_free (&error);
01289   
01290   return TRUE;
01291 }
01292 
01293 static dbus_bool_t
01294 check_spawn_segfault (void *data)
01295 {
01296   char *argv[4] = { NULL, NULL, NULL, NULL };
01297   DBusBabysitter *sitter = NULL;
01298   DBusError error = DBUS_ERROR_INIT;
01299 
01300   /*** Test launching segfault binary */
01301   
01302   argv[0] = TEST_SEGFAULT_BINARY;
01303   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01304                                          NULL, NULL, NULL,
01305                                          &error))
01306     {
01307       _dbus_babysitter_block_for_child_exit (sitter);
01308       _dbus_babysitter_set_child_exit_error (sitter, &error);
01309     }
01310 
01311   if (sitter)
01312     _dbus_babysitter_unref (sitter);
01313 
01314   if (!dbus_error_is_set (&error))
01315     {
01316       _dbus_warn ("Did not get an error launching segfaulting binary\n");
01317       return FALSE;
01318     }
01319 
01320   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01321         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01322     {
01323       _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
01324                   error.name, error.message);
01325       dbus_error_free (&error);
01326       return FALSE;
01327     }
01328 
01329   dbus_error_free (&error);
01330   
01331   return TRUE;
01332 }
01333 
01334 static dbus_bool_t
01335 check_spawn_exit (void *data)
01336 {
01337   char *argv[4] = { NULL, NULL, NULL, NULL };
01338   DBusBabysitter *sitter = NULL;
01339   DBusError error = DBUS_ERROR_INIT;
01340 
01341   /*** Test launching exit failure binary */
01342   
01343   argv[0] = TEST_EXIT_BINARY;
01344   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01345                                          NULL, NULL, NULL,
01346                                          &error))
01347     {
01348       _dbus_babysitter_block_for_child_exit (sitter);
01349       _dbus_babysitter_set_child_exit_error (sitter, &error);
01350     }
01351 
01352   if (sitter)
01353     _dbus_babysitter_unref (sitter);
01354 
01355   if (!dbus_error_is_set (&error))
01356     {
01357       _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
01358       return FALSE;
01359     }
01360 
01361   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01362         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
01363     {
01364       _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
01365                   error.name, error.message);
01366       dbus_error_free (&error);
01367       return FALSE;
01368     }
01369 
01370   dbus_error_free (&error);
01371   
01372   return TRUE;
01373 }
01374 
01375 static dbus_bool_t
01376 check_spawn_and_kill (void *data)
01377 {
01378   char *argv[4] = { NULL, NULL, NULL, NULL };
01379   DBusBabysitter *sitter = NULL;
01380   DBusError error = DBUS_ERROR_INIT;
01381 
01382   /*** Test launching sleeping binary then killing it */
01383 
01384   argv[0] = TEST_SLEEP_FOREVER_BINARY;
01385   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
01386                                          NULL, NULL, NULL,
01387                                          &error))
01388     {
01389       _dbus_babysitter_kill_child (sitter);
01390       
01391       _dbus_babysitter_block_for_child_exit (sitter);
01392       
01393       _dbus_babysitter_set_child_exit_error (sitter, &error);
01394     }
01395 
01396   if (sitter)
01397     _dbus_babysitter_unref (sitter);
01398 
01399   if (!dbus_error_is_set (&error))
01400     {
01401       _dbus_warn ("Did not get an error after killing spawned binary\n");
01402       return FALSE;
01403     }
01404 
01405   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01406         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
01407     {
01408       _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
01409                   error.name, error.message);
01410       dbus_error_free (&error);
01411       return FALSE;
01412     }
01413 
01414   dbus_error_free (&error);
01415   
01416   return TRUE;
01417 }
01418 
01419 dbus_bool_t
01420 _dbus_spawn_test (const char *test_data_dir)
01421 {
01422   if (!_dbus_test_oom_handling ("spawn_nonexistent",
01423                                 check_spawn_nonexistent,
01424                                 NULL))
01425     return FALSE;
01426 
01427   if (!_dbus_test_oom_handling ("spawn_segfault",
01428                                 check_spawn_segfault,
01429                                 NULL))
01430     return FALSE;
01431 
01432   if (!_dbus_test_oom_handling ("spawn_exit",
01433                                 check_spawn_exit,
01434                                 NULL))
01435     return FALSE;
01436 
01437   if (!_dbus_test_oom_handling ("spawn_and_kill",
01438                                 check_spawn_and_kill,
01439                                 NULL))
01440     return FALSE;
01441   
01442   return TRUE;
01443 }
01444 #endif

Generated on Sat Jun 14 22:43:04 2008 for D-Bus by  doxygen 1.4.6