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

Generated on Tue Feb 10 18:14:07 2004 for D-BUS by doxygen 1.3.5