LCOV - code coverage report
Current view: top level - common - exechelp-posix.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 79 266 29.7 %
Date: 2015-11-05 17:10:59 Functions: 5 14 35.7 %

          Line data    Source code
       1             : /* exechelp.c - Fork and exec helpers for POSIX
       2             :  * Copyright (C) 2004, 2007, 2008, 2009,
       3             :  *               2010 Free Software Foundation, Inc.
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * This file is free software; you can redistribute it and/or modify
       8             :  * it under the terms of either
       9             :  *
      10             :  *   - the GNU Lesser General Public License as published by the Free
      11             :  *     Software Foundation; either version 3 of the License, or (at
      12             :  *     your option) any later version.
      13             :  *
      14             :  * or
      15             :  *
      16             :  *   - the GNU General Public License as published by the Free
      17             :  *     Software Foundation; either version 2 of the License, or (at
      18             :  *     your option) any later version.
      19             :  *
      20             :  * or both in parallel, as here.
      21             :  *
      22             :  * This file is distributed in the hope that it will be useful,
      23             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      24             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      25             :  * GNU General Public License for more details.
      26             :  *
      27             :  * You should have received a copy of the GNU General Public License
      28             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      29             :  */
      30             : 
      31             : #include <config.h>
      32             : 
      33             : #if defined(HAVE_W32_SYSTEM) || defined (HAVE_W32CE_SYSTEM)
      34             : #error This code is only used on POSIX
      35             : #endif
      36             : 
      37             : #include <stdio.h>
      38             : #include <stdlib.h>
      39             : #ifdef HAVE_STDINT_H
      40             : # include <stdint.h>
      41             : #endif
      42             : #include <string.h>
      43             : #include <errno.h>
      44             : #include <assert.h>
      45             : #ifdef HAVE_SIGNAL_H
      46             : # include <signal.h>
      47             : #endif
      48             : #include <unistd.h>
      49             : #include <fcntl.h>
      50             : 
      51             : #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth.  */
      52             : #undef HAVE_NPTH
      53             : #undef USE_NPTH
      54             : #endif
      55             : 
      56             : #ifdef HAVE_NPTH
      57             : #include <npth.h>
      58             : #endif
      59             : #include <sys/wait.h>
      60             : 
      61             : #ifdef HAVE_GETRLIMIT
      62             : #include <sys/time.h>
      63             : #include <sys/resource.h>
      64             : #endif /*HAVE_GETRLIMIT*/
      65             : 
      66             : #ifdef HAVE_STAT
      67             : # include <sys/stat.h>
      68             : #endif
      69             : 
      70             : #include "util.h"
      71             : #include "i18n.h"
      72             : #include "sysutils.h"
      73             : #include "exechelp.h"
      74             : 
      75             : 
      76             : /* Return the maximum number of currently allowed open file
      77             :    descriptors.  Only useful on POSIX systems but returns a value on
      78             :    other systems too.  */
      79             : int
      80          18 : get_max_fds (void)
      81             : {
      82          18 :   int max_fds = -1;
      83             : #ifdef HAVE_GETRLIMIT
      84             :   struct rlimit rl;
      85             : 
      86             : # ifdef RLIMIT_NOFILE
      87          18 :   if (!getrlimit (RLIMIT_NOFILE, &rl))
      88          18 :     max_fds = rl.rlim_max;
      89             : # endif
      90             : 
      91             : # ifdef RLIMIT_OFILE
      92          18 :   if (max_fds == -1 && !getrlimit (RLIMIT_OFILE, &rl))
      93           0 :     max_fds = rl.rlim_max;
      94             : 
      95             : # endif
      96             : #endif /*HAVE_GETRLIMIT*/
      97             : 
      98             : #ifdef _SC_OPEN_MAX
      99          18 :   if (max_fds == -1)
     100             :     {
     101           0 :       long int scres = sysconf (_SC_OPEN_MAX);
     102           0 :       if (scres >= 0)
     103           0 :         max_fds = scres;
     104             :     }
     105             : #endif
     106             : 
     107             : #ifdef _POSIX_OPEN_MAX
     108             :   if (max_fds == -1)
     109             :     max_fds = _POSIX_OPEN_MAX;
     110             : #endif
     111             : 
     112             : #ifdef OPEN_MAX
     113             :   if (max_fds == -1)
     114             :     max_fds = OPEN_MAX;
     115             : #endif
     116             : 
     117          18 :   if (max_fds == -1)
     118           0 :     max_fds = 256;  /* Arbitrary limit.  */
     119             : 
     120             :   /* AIX returns INT32_MAX instead of a proper value.  We assume that
     121             :      this is always an error and use an arbitrary limit.  */
     122             : #ifdef INT32_MAX
     123          18 :   if (max_fds == INT32_MAX)
     124           0 :     max_fds = 256;
     125             : #endif
     126             : 
     127          18 :   return max_fds;
     128             : }
     129             : 
     130             : 
     131             : /* Close all file descriptors starting with descriptor FIRST.  If
     132             :    EXCEPT is not NULL, it is expected to be a list of file descriptors
     133             :    which shall not be closed.  This list shall be sorted in ascending
     134             :    order with the end marked by -1.  */
     135             : void
     136           3 : close_all_fds (int first, int *except)
     137             : {
     138           3 :   int max_fd = get_max_fds ();
     139             :   int fd, i, except_start;
     140             : 
     141           3 :   if (except)
     142             :     {
     143           1 :       except_start = 0;
     144      255998 :       for (fd=first; fd < max_fd; fd++)
     145             :         {
     146      256052 :           for (i=except_start; except[i] != -1; i++)
     147             :             {
     148          58 :               if (except[i] == fd)
     149             :                 {
     150             :                   /* If we found the descriptor in the exception list
     151             :                      we can start the next compare run at the next
     152             :                      index because the exception list is ordered.  */
     153           3 :                 except_start = i + 1;
     154           3 :                 break;
     155             :                 }
     156             :             }
     157      255997 :           if (except[i] == -1)
     158      255994 :             close (fd);
     159             :         }
     160             :     }
     161             :   else
     162             :     {
     163      511996 :       for (fd=first; fd < max_fd; fd++)
     164      511994 :         close (fd);
     165             :     }
     166             : 
     167           3 :   gpg_err_set_errno (0);
     168           3 : }
     169             : 
     170             : 
     171             : /* Returns an array with all currently open file descriptors.  The end
     172             :    of the array is marked by -1.  The caller needs to release this
     173             :    array using the *standard free* and not with xfree.  This allow the
     174             :    use of this fucntion right at startup even before libgcrypt has
     175             :    been initialized.  Returns NULL on error and sets ERRNO
     176             :    accordingly.  */
     177             : int *
     178          13 : get_all_open_fds (void)
     179             : {
     180             :   int *array;
     181             :   size_t narray;
     182             :   int fd, max_fd, idx;
     183             : #ifndef HAVE_STAT
     184             :   array = calloc (1, sizeof *array);
     185             :   if (array)
     186             :     array[0] = -1;
     187             : #else /*HAVE_STAT*/
     188             :   struct stat statbuf;
     189             : 
     190          13 :   max_fd = get_max_fds ();
     191          13 :   narray = 32;  /* If you change this change also t-exechelp.c.  */
     192          13 :   array = calloc (narray, sizeof *array);
     193          13 :   if (!array)
     194           0 :     return NULL;
     195             : 
     196             :   /* Note:  The list we return is ordered.  */
     197     3328013 :   for (idx=0, fd=0; fd < max_fd; fd++)
     198     3328000 :     if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
     199             :       {
     200         230 :         if (idx+1 >= narray)
     201             :           {
     202             :             int *tmp;
     203             : 
     204           5 :             narray += (narray < 256)? 32:256;
     205           5 :             tmp = realloc (array, narray * sizeof *array);
     206           5 :             if (!tmp)
     207             :               {
     208           0 :                 free (array);
     209           0 :                 return NULL;
     210             :               }
     211           5 :             array = tmp;
     212             :           }
     213         230 :         array[idx++] = fd;
     214             :       }
     215          13 :   array[idx] = -1;
     216             : #endif /*HAVE_STAT*/
     217          13 :   return array;
     218             : }
     219             : 
     220             : 
     221             : /* The exec core used right after the fork. This will never return. */
     222             : static void
     223           1 : do_exec (const char *pgmname, const char *argv[],
     224             :          int fd_in, int fd_out, int fd_err,
     225             :          void (*preexec)(void) )
     226             : {
     227             :   char **arg_list;
     228             :   int i, j;
     229             :   int fds[3];
     230             : 
     231           1 :   fds[0] = fd_in;
     232           1 :   fds[1] = fd_out;
     233           1 :   fds[2] = fd_err;
     234             : 
     235             :   /* Create the command line argument array.  */
     236           1 :   i = 0;
     237           1 :   if (argv)
     238           7 :     while (argv[i])
     239           5 :       i++;
     240           1 :   arg_list = xcalloc (i+2, sizeof *arg_list);
     241           1 :   arg_list[0] = strrchr (pgmname, '/');
     242           1 :   if (arg_list[0])
     243           1 :     arg_list[0]++;
     244             :   else
     245           0 :     arg_list[0] = xstrdup (pgmname);
     246           1 :   if (argv)
     247           6 :     for (i=0,j=1; argv[i]; i++, j++)
     248           5 :       arg_list[j] = (char*)argv[i];
     249             : 
     250             :   /* Assign /dev/null to unused FDs. */
     251           4 :   for (i=0; i <= 2; i++)
     252             :     {
     253           3 :       if (fds[i] == -1 )
     254             :         {
     255           3 :           fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
     256           3 :           if (fds[i] == -1)
     257           0 :             log_fatal ("failed to open '%s': %s\n",
     258           0 :                        "/dev/null", strerror (errno));
     259             :         }
     260             :     }
     261             : 
     262             :   /* Connect the standard files.  */
     263           4 :   for (i=0; i <= 2; i++)
     264             :     {
     265           3 :       if (fds[i] != i && dup2 (fds[i], i) == -1)
     266           0 :         log_fatal ("dup2 std%s failed: %s\n",
     267           0 :                    i==0?"in":i==1?"out":"err", strerror (errno));
     268             :     }
     269             : 
     270             :   /* Close all other files. */
     271           1 :   close_all_fds (3, NULL);
     272             : 
     273           1 :   if (preexec)
     274           0 :     preexec ();
     275           1 :   execv (pgmname, arg_list);
     276             :   /* No way to print anything, as we have closed all streams. */
     277           1 :   _exit (127);
     278             : }
     279             : 
     280             : 
     281             : static gpg_error_t
     282           0 : do_create_pipe (int filedes[2])
     283             : {
     284           0 :   gpg_error_t err = 0;
     285             : 
     286           0 :   if (pipe (filedes) == -1)
     287             :     {
     288           0 :       err = gpg_error_from_syserror ();
     289           0 :       filedes[0] = filedes[1] = -1;
     290             :     }
     291             : 
     292           0 :   return err;
     293             : }
     294             : 
     295             : /* Portable function to create a pipe.  Under Windows the write end is
     296             :    inheritable.  */
     297             : gpg_error_t
     298           0 : gnupg_create_inbound_pipe (int filedes[2])
     299             : {
     300           0 :   return do_create_pipe (filedes);
     301             : }
     302             : 
     303             : 
     304             : /* Portable function to create a pipe.  Under Windows the read end is
     305             :    inheritable.  */
     306             : gpg_error_t
     307           0 : gnupg_create_outbound_pipe (int filedes[2])
     308             : {
     309           0 :   return do_create_pipe (filedes);
     310             : }
     311             : 
     312             : 
     313             : 
     314             : static gpg_error_t
     315           0 : create_pipe_and_estream (int filedes[2], estream_t *r_fp,
     316             :                          int outbound, int nonblock,
     317             :                          gpg_err_source_t errsource)
     318             : {
     319             :   gpg_error_t err;
     320             : 
     321           0 :   if (pipe (filedes) == -1)
     322             :     {
     323           0 :       err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
     324           0 :       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
     325           0 :       filedes[0] = filedes[1] = -1;
     326           0 :       *r_fp = NULL;
     327           0 :       return err;
     328             :     }
     329             : 
     330           0 :   if (outbound)
     331           0 :     *r_fp = es_fdopen (filedes[0], nonblock? "r,nonblock" : "r");
     332             :   else
     333           0 :     *r_fp = es_fdopen (filedes[1], nonblock? "w,nonblock" : "w");
     334           0 :   if (!*r_fp)
     335             :     {
     336           0 :       err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
     337           0 :       log_error (_("error creating a stream for a pipe: %s\n"),
     338             :                  gpg_strerror (err));
     339           0 :       close (filedes[0]);
     340           0 :       close (filedes[1]);
     341           0 :       filedes[0] = filedes[1] = -1;
     342           0 :       return err;
     343             :     }
     344           0 :   return 0;
     345             : }
     346             : 
     347             : 
     348             : 
     349             : /* Fork and exec the PGMNAME, see exechelp.h for details.  */
     350             : gpg_error_t
     351           0 : gnupg_spawn_process (const char *pgmname, const char *argv[],
     352             :                      gpg_err_source_t errsource,
     353             :                      void (*preexec)(void), unsigned int flags,
     354             :                      estream_t *r_infp,
     355             :                      estream_t *r_outfp,
     356             :                      estream_t *r_errfp,
     357             :                      pid_t *pid)
     358             : {
     359             :   gpg_error_t err;
     360           0 :   int inpipe[2] = {-1, -1};
     361           0 :   int outpipe[2] = {-1, -1};
     362           0 :   int errpipe[2] = {-1, -1};
     363           0 :   estream_t infp = NULL;
     364           0 :   estream_t outfp = NULL;
     365           0 :   estream_t errfp = NULL;
     366           0 :   int nonblock = !!(flags & GNUPG_SPAWN_NONBLOCK);
     367             : 
     368           0 :   if (r_infp)
     369           0 :     *r_infp = NULL;
     370           0 :   if (r_outfp)
     371           0 :     *r_outfp = NULL;
     372           0 :   if (r_errfp)
     373           0 :     *r_errfp = NULL;
     374           0 :   *pid = (pid_t)(-1); /* Always required.  */
     375             : 
     376           0 :   if (r_infp)
     377             :     {
     378           0 :       err = create_pipe_and_estream (inpipe, &infp, 0, nonblock, errsource);
     379           0 :       if (err)
     380           0 :         return err;
     381             :     }
     382             : 
     383           0 :   if (r_outfp)
     384             :     {
     385           0 :       err = create_pipe_and_estream (outpipe, &outfp, 1, nonblock, errsource);
     386           0 :       if (err)
     387             :         {
     388           0 :           if (infp)
     389           0 :             es_fclose (infp);
     390           0 :           else if (inpipe[1] != -1)
     391           0 :             close (inpipe[1]);
     392           0 :           if (inpipe[0] != -1)
     393           0 :             close (inpipe[0]);
     394             : 
     395           0 :           return err;
     396             :         }
     397             :     }
     398             : 
     399           0 :   if (r_errfp)
     400             :     {
     401           0 :       err = create_pipe_and_estream (errpipe, &errfp, 1, nonblock, errsource);
     402           0 :       if (err)
     403             :         {
     404           0 :           if (infp)
     405           0 :             es_fclose (infp);
     406           0 :           else if (inpipe[1] != -1)
     407           0 :             close (inpipe[1]);
     408           0 :           if (inpipe[0] != -1)
     409           0 :             close (inpipe[0]);
     410             : 
     411           0 :           if (outfp)
     412           0 :             es_fclose (outfp);
     413           0 :           else if (outpipe[0] != -1)
     414           0 :             close (outpipe[0]);
     415           0 :           if (outpipe[1] != -1)
     416           0 :             close (outpipe[1]);
     417             : 
     418           0 :           return err;
     419             :         }
     420             :     }
     421             : 
     422             : 
     423           0 :   *pid = fork ();
     424           0 :   if (*pid == (pid_t)(-1))
     425             :     {
     426           0 :       err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
     427           0 :       log_error (_("error forking process: %s\n"), gpg_strerror (err));
     428             : 
     429           0 :       if (infp)
     430           0 :         es_fclose (infp);
     431           0 :       else if (inpipe[1] != -1)
     432           0 :         close (inpipe[1]);
     433           0 :       if (inpipe[0] != -1)
     434           0 :         close (inpipe[0]);
     435             : 
     436           0 :       if (outfp)
     437           0 :         es_fclose (outfp);
     438           0 :       else if (outpipe[0] != -1)
     439           0 :         close (outpipe[0]);
     440           0 :       if (outpipe[1] != -1)
     441           0 :         close (outpipe[1]);
     442             : 
     443           0 :       if (errfp)
     444           0 :         es_fclose (errfp);
     445           0 :       else if (errpipe[0] != -1)
     446           0 :         close (errpipe[0]);
     447           0 :       if (errpipe[1] != -1)
     448           0 :         close (errpipe[1]);
     449           0 :       return err;
     450             :     }
     451             : 
     452           0 :   if (!*pid)
     453             :     {
     454             :       /* This is the child. */
     455           0 :       gcry_control (GCRYCTL_TERM_SECMEM);
     456           0 :       es_fclose (outfp);
     457           0 :       es_fclose (errfp);
     458           0 :       do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1], preexec);
     459             :       /*NOTREACHED*/
     460             :     }
     461             : 
     462             :   /* This is the parent. */
     463           0 :   if (inpipe[0] != -1)
     464           0 :     close (inpipe[0]);
     465           0 :   if (outpipe[1] != -1)
     466           0 :     close (outpipe[1]);
     467           0 :   if (errpipe[1] != -1)
     468           0 :     close (errpipe[1]);
     469             : 
     470           0 :   if (r_infp)
     471           0 :     *r_infp = infp;
     472           0 :   if (r_outfp)
     473           0 :     *r_outfp = outfp;
     474           0 :   if (r_errfp)
     475           0 :     *r_errfp = errfp;
     476             : 
     477           0 :   return 0;
     478             : }
     479             : 
     480             : 
     481             : 
     482             : /* Simplified version of gnupg_spawn_process.  This function forks and
     483             :    then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
     484             :    and ERRFD to stderr (any of them may be -1 to connect them to
     485             :    /dev/null).  The arguments for the process are expected in the NULL
     486             :    terminated array ARGV.  The program name itself should not be
     487             :    included there.  Calling gnupg_wait_process is required.
     488             : 
     489             :    Returns 0 on success or an error code. */
     490             : gpg_error_t
     491           0 : gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
     492             :                         int infd, int outfd, int errfd, pid_t *pid)
     493             : {
     494             :   gpg_error_t err;
     495             : 
     496           0 :   *pid = fork ();
     497           0 :   if (*pid == (pid_t)(-1))
     498             :     {
     499           0 :       err = gpg_error_from_syserror ();
     500           0 :       log_error (_("error forking process: %s\n"), strerror (errno));
     501           0 :       return err;
     502             :     }
     503             : 
     504           0 :   if (!*pid)
     505             :     {
     506           0 :       gcry_control (GCRYCTL_TERM_SECMEM);
     507             :       /* Run child. */
     508           0 :       do_exec (pgmname, argv, infd, outfd, errfd, NULL);
     509             :       /*NOTREACHED*/
     510             :     }
     511             : 
     512           0 :   return 0;
     513             : }
     514             : 
     515             : 
     516             : /* See exechelp.h for the description.  */
     517             : gpg_error_t
     518           0 : gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
     519             : {
     520             :   gpg_err_code_t ec;
     521             :   int i, status;
     522             : 
     523           0 :   if (r_exitcode)
     524           0 :     *r_exitcode = -1;
     525             : 
     526           0 :   if (pid == (pid_t)(-1))
     527           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     528             : 
     529             : #ifdef USE_NPTH
     530           0 :   i = npth_waitpid (pid, &status, hang? 0:WNOHANG);
     531             : #else
     532           0 :   while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1)
     533           0 :          && errno == EINTR);
     534             : #endif
     535             : 
     536           0 :   if (i == (pid_t)(-1))
     537             :     {
     538           0 :       ec = gpg_err_code_from_errno (errno);
     539           0 :       log_error (_("waiting for process %d to terminate failed: %s\n"),
     540           0 :                  (int)pid, strerror (errno));
     541             :     }
     542           0 :   else if (!i)
     543             :     {
     544           0 :       ec = GPG_ERR_TIMEOUT; /* Still running.  */
     545             :     }
     546           0 :   else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
     547             :     {
     548           0 :       log_error (_("error running '%s': probably not installed\n"), pgmname);
     549           0 :       ec = GPG_ERR_CONFIGURATION;
     550             :     }
     551           0 :   else if (WIFEXITED (status) && WEXITSTATUS (status))
     552           0 :     {
     553           0 :       if (!r_exitcode)
     554           0 :         log_error (_("error running '%s': exit status %d\n"), pgmname,
     555           0 :                    WEXITSTATUS (status));
     556             :       else
     557           0 :         *r_exitcode = WEXITSTATUS (status);
     558           0 :       ec = GPG_ERR_GENERAL;
     559             :     }
     560           0 :   else if (!WIFEXITED (status))
     561             :     {
     562           0 :       log_error (_("error running '%s': terminated\n"), pgmname);
     563           0 :       ec = GPG_ERR_GENERAL;
     564             :     }
     565             :   else
     566             :     {
     567           0 :       if (r_exitcode)
     568           0 :         *r_exitcode = 0;
     569           0 :       ec = 0;
     570             :     }
     571             : 
     572           0 :   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
     573             : }
     574             : 
     575             : 
     576             : void
     577           0 : gnupg_release_process (pid_t pid)
     578             : {
     579             :   (void)pid;
     580           0 : }
     581             : 
     582             : 
     583             : /* Spawn a new process and immediately detach from it.  The name of
     584             :    the program to exec is PGMNAME and its arguments are in ARGV (the
     585             :    programname is automatically passed as first argument).
     586             :    Environment strings in ENVP are set.  An error is returned if
     587             :    pgmname is not executable; to make this work it is necessary to
     588             :    provide an absolute file name.  All standard file descriptors are
     589             :    connected to /dev/null. */
     590             : gpg_error_t
     591           1 : gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
     592             :                               const char *envp[] )
     593             : {
     594             :   pid_t pid;
     595             :   int i;
     596             : 
     597           1 :   if (getuid() != geteuid())
     598           0 :     return gpg_error (GPG_ERR_BUG);
     599             : 
     600           1 :   if (access (pgmname, X_OK))
     601           0 :     return gpg_error_from_syserror ();
     602             : 
     603           1 :   pid = fork ();
     604           2 :   if (pid == (pid_t)(-1))
     605             :     {
     606           0 :       log_error (_("error forking process: %s\n"), strerror (errno));
     607           0 :       return gpg_error_from_syserror ();
     608             :     }
     609           2 :   if (!pid)
     610             :     {
     611             :       pid_t pid2;
     612             : 
     613           1 :       gcry_control (GCRYCTL_TERM_SECMEM);
     614           1 :       if (setsid() == -1 || chdir ("/"))
     615           0 :         _exit (1);
     616             : 
     617           1 :       pid2 = fork (); /* Double fork to let init take over the new child. */
     618           1 :       if (pid2 == (pid_t)(-1))
     619           0 :         _exit (1);
     620           1 :       if (pid2)
     621           0 :         _exit (0);  /* Let the parent exit immediately. */
     622             : 
     623           1 :       if (envp)
     624           0 :         for (i=0; envp[i]; i++)
     625           0 :           putenv (xstrdup (envp[i]));
     626             : 
     627           1 :       do_exec (pgmname, argv, -1, -1, -1, NULL);
     628             : 
     629             :       /*NOTREACHED*/
     630             :     }
     631             : 
     632           1 :   if (waitpid (pid, NULL, 0) == -1)
     633           0 :     log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
     634           0 :                strerror (errno));
     635             : 
     636           1 :   return 0;
     637             : }
     638             : 
     639             : 
     640             : /* Kill a process; that is send an appropriate signal to the process.
     641             :    gnupg_wait_process must be called to actually remove the process
     642             :    from the system.  An invalid PID is ignored.  */
     643             : void
     644           0 : gnupg_kill_process (pid_t pid)
     645             : {
     646           0 :   if (pid != (pid_t)(-1))
     647             :     {
     648           0 :       kill (pid, SIGTERM);
     649             :     }
     650           0 : }

Generated by: LCOV version 1.11