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

Generated on Sat Sep 25 19:17:12 2004 for D-BUS by  doxygen 1.3.8-20040913