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

Generated on Wed Oct 22 14:05:04 2003 for D-BUS by doxygen1.3-rc3