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

Generated on Fri Oct 5 11:45:35 2007 for D-Bus by  doxygen 1.5.3