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

Generated on Tue Dec 20 14:16:42 2005 for D-BUS by  doxygen 1.4.2