Main Page   Modules   Data Structures   File List   Data Fields   Related Pages  

dbus-spawn.c

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

Generated on Wed Jun 9 05:01:26 2004 for D-BUS by doxygen1.2.15