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

Generated on Tue Apr 15 15:54:01 2008 for D-Bus by  doxygen 1.5.1