dbus-spawn.c

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

Generated on Tue Feb 24 16:40:40 2009 for D-Bus by  doxygen 1.5.1