LCOV - code coverage report
Current view: top level - src - system-posix.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 59 98 60.2 %
Date: 2015-11-05 17:06:03 Functions: 9 14 64.3 %

          Line data    Source code
       1             : /* system-posix.c - System support functions.
       2             :    Copyright (C) 2009, 2010 Free Software Foundation, Inc.
       3             : 
       4             :    This file is part of Assuan.
       5             : 
       6             :    Assuan is free software; you can redistribute it and/or modify it
       7             :    under the terms of the GNU Lesser General Public License as
       8             :    published by the Free Software Foundation; either version 2.1 of
       9             :    the License, or (at your option) any later version.
      10             : 
      11             :    Assuan is distributed in the hope that it will be useful, but
      12             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :    Lesser General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU Lesser General Public
      17             :    License along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : 
      21             : #ifdef HAVE_CONFIG_H
      22             : #include <config.h>
      23             : #endif
      24             : 
      25             : #include <stdlib.h>
      26             : #include <errno.h>
      27             : /* Solaris 8 needs sys/types.h before time.h.  */
      28             : #include <sys/types.h>
      29             : #include <time.h>
      30             : #include <fcntl.h>
      31             : #include <sys/wait.h>
      32             : 
      33             : #include "assuan-defs.h"
      34             : #include "debug.h"
      35             : 
      36             : #ifdef _POSIX_OPEN_MAX
      37             : #define MAX_OPEN_FDS _POSIX_OPEN_MAX
      38             : #else
      39             : #define MAX_OPEN_FDS 20
      40             : #endif
      41             : 
      42             : 
      43             : 
      44             : 
      45             : assuan_fd_t
      46           0 : assuan_fdopen (int fd)
      47             : {
      48           0 :   return dup (fd);
      49             : }
      50             : 
      51             : 
      52             : 
      53             : /* Sleep for the given number of microseconds.  Default
      54             :    implementation.  */
      55             : void
      56           0 : __assuan_usleep (assuan_context_t ctx, unsigned int usec)
      57             : {
      58           0 :   if (! usec)
      59           0 :     return;
      60             : 
      61             : #ifdef HAVE_NANOSLEEP
      62             :   {
      63             :     struct timespec req;
      64             :     struct timespec rem;
      65             : 
      66           0 :     req.tv_sec = 0;
      67           0 :     req.tv_nsec = usec * 1000;
      68             : 
      69           0 :     while (nanosleep (&req, &rem) < 0 && errno == EINTR)
      70           0 :       req = rem;
      71             :   }
      72             : #else
      73             :   {
      74             :     struct timeval tv;
      75             : 
      76             :     tv.tv_sec  = usec / 1000000;
      77             :     tv.tv_usec = usec % 1000000;
      78             :     select (0, NULL, NULL, NULL, &tv);
      79             :   }
      80             : #endif
      81             : }
      82             : 
      83             : 
      84             : 
      85             : /* Create a pipe with one inheritable end.  Easy for Posix.  */
      86             : int
      87           2 : __assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
      88             : {
      89           2 :   return pipe (fd);
      90             : }
      91             : 
      92             : 
      93             : 
      94             : /* Close the given file descriptor, created with _assuan_pipe or one
      95             :    of the socket functions.  Easy for Posix.  */
      96             : int
      97          11 : __assuan_close (assuan_context_t ctx, assuan_fd_t fd)
      98             : {
      99          11 :   return close (fd);
     100             : }
     101             : 
     102             : 
     103             : 
     104             : ssize_t
     105           5 : __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
     106             : {
     107           5 :   return read (fd, buffer, size);
     108             : }
     109             : 
     110             : 
     111             : 
     112             : ssize_t
     113          12 : __assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
     114             :                 size_t size)
     115             : {
     116          12 :   return write (fd, buffer, size);
     117             : }
     118             : 
     119             : 
     120             : 
     121             : int
     122          32 : __assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
     123             :                   int flags)
     124             : {
     125             :   int ret;
     126             : 
     127             :   do
     128          32 :     ret = recvmsg (fd, msg, flags);
     129          32 :   while (ret == -1 && errno == EINTR);
     130             : 
     131          32 :   return ret;
     132             : }
     133             : 
     134             : 
     135             : 
     136             : int
     137          59 : __assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
     138             :                   int flags)
     139             : {
     140             :   int ret;
     141             : 
     142             :   do
     143          59 :     ret = sendmsg (fd, msg, flags);
     144          59 :   while (ret == -1 && errno == EINTR);
     145             : 
     146          59 :   return ret;
     147             : }
     148             : 
     149             : 
     150             : 
     151             : static int
     152           0 : writen (int fd, const char *buffer, size_t length)
     153             : {
     154           0 :   while (length)
     155             :     {
     156           0 :       int nwritten = write (fd, buffer, length);
     157             : 
     158           0 :       if (nwritten < 0)
     159             :         {
     160           0 :           if (errno == EINTR)
     161           0 :             continue;
     162           0 :           return -1; /* write error */
     163             :         }
     164           0 :       length -= nwritten;
     165           0 :       buffer += nwritten;
     166             :     }
     167           0 :   return 0;  /* okay */
     168             : }
     169             : 
     170             : 
     171             : int
     172           2 : __assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
     173             :                 const char **argv,
     174             :                 assuan_fd_t fd_in, assuan_fd_t fd_out,
     175             :                 assuan_fd_t *fd_child_list,
     176             :                 void (*atfork) (void *opaque, int reserved),
     177             :                 void *atforkvalue, unsigned int flags)
     178             : {
     179             :   int pid;
     180             : 
     181           2 :   pid = fork ();
     182           4 :   if (pid < 0)
     183           0 :     return -1;
     184             : 
     185           4 :   if (pid == 0)
     186             :     {
     187             :       /* Child process (server side).  */
     188             :       int i;
     189             :       int n;
     190             :       char errbuf[512];
     191             :       int *fdp;
     192             :       int fdnul;
     193             : 
     194           2 :       if (atfork)
     195           2 :         atfork (atforkvalue, 0);
     196             : 
     197           2 :       fdnul = open ("/dev/null", O_WRONLY);
     198           2 :       if (fdnul == -1)
     199             :         {
     200           0 :           TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
     201             :                   "can't open `/dev/null': %s", strerror (errno));
     202           0 :           _exit (4);
     203             :         }
     204             : 
     205             :       /* Dup handles to stdin/stdout. */
     206           2 :       if (fd_out != STDOUT_FILENO)
     207             :         {
     208           2 :           if (dup2 (fd_out == ASSUAN_INVALID_FD ? fdnul : fd_out,
     209             :                     STDOUT_FILENO) == -1)
     210             :             {
     211           0 :               TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
     212             :                       "dup2 failed in child: %s", strerror (errno));
     213           0 :               _exit (4);
     214             :             }
     215             :         }
     216             : 
     217           2 :       if (fd_in != STDIN_FILENO)
     218             :         {
     219           2 :           if (dup2 (fd_in == ASSUAN_INVALID_FD ? fdnul : fd_in,
     220             :                     STDIN_FILENO) == -1)
     221             :             {
     222           0 :               TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
     223             :                       "dup2 failed in child: %s", strerror (errno));
     224           0 :               _exit (4);
     225             :             }
     226             :         }
     227             : 
     228             :       /* Dup stderr to /dev/null unless it is in the list of FDs to be
     229             :          passed to the child. */
     230           2 :       fdp = fd_child_list;
     231           2 :       if (fdp)
     232             :         {
     233           2 :           for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
     234             :             ;
     235             :         }
     236           2 :       if (!fdp || *fdp == -1)
     237             :         {
     238           0 :           if (dup2 (fdnul, STDERR_FILENO) == -1)
     239             :             {
     240           0 :               TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx,
     241             :                       "dup2(dev/null, 2) failed: %s", strerror (errno));
     242           0 :               _exit (4);
     243             :             }
     244             :         }
     245           2 :       close (fdnul);
     246             : 
     247             :       /* Close all files which will not be duped and are not in the
     248             :          fd_child_list. */
     249           2 :       n = sysconf (_SC_OPEN_MAX);
     250           2 :       if (n < 0)
     251           0 :         n = MAX_OPEN_FDS;
     252      512002 :       for (i = 0; i < n; i++)
     253             :         {
     254      512000 :           if (i == STDIN_FILENO || i == STDOUT_FILENO || i == STDERR_FILENO)
     255           6 :             continue;
     256      511994 :           fdp = fd_child_list;
     257      511994 :           if (fdp)
     258             :             {
     259     1791977 :               while (*fdp != -1 && *fdp != i)
     260      767989 :                 fdp++;
     261             :             }
     262             : 
     263      511994 :           if (!(fdp && *fdp != -1))
     264      511993 :             close (i);
     265             :         }
     266           2 :       gpg_err_set_errno (0);
     267             : 
     268           2 :       if (! name)
     269             :         {
     270             :           /* No name and no args given, thus we don't do an exec
     271             :              but continue the forked process.  */
     272           1 :           *argv = "server";
     273             : 
     274             :           /* FIXME: Cleanup.  */
     275           1 :           return 0;
     276             :         }
     277             : 
     278           1 :       execv (name, (char *const *) argv);
     279             : 
     280             :       /* oops - use the pipe to tell the parent about it */
     281           0 :       snprintf (errbuf, sizeof(errbuf)-1,
     282             :                 "ERR %d can't exec `%s': %.50s\n",
     283             :                 _assuan_error (ctx, GPG_ERR_ASS_SERVER_START),
     284           1 :                 name, strerror (errno));
     285           0 :       errbuf[sizeof(errbuf)-1] = 0;
     286           0 :       writen (1, errbuf, strlen (errbuf));
     287           0 :       _exit (4);
     288             :     }
     289             : 
     290           2 :   if (! name)
     291           1 :     *argv = "client";
     292             : 
     293           2 :   *r_pid = pid;
     294             : 
     295           2 :   return 0;
     296             : }
     297             : 
     298             : 
     299             : 
     300             : /* FIXME: Add some sort of waitpid function that covers GPGME and
     301             :    gpg-agent's use of assuan.  */
     302             : pid_t
     303           3 : __assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
     304             :                   int *status, int options)
     305             : {
     306             :   /* We can't just release the PID, a waitpid is mandatory.  But
     307             :      NOWAIT in POSIX systems just means the caller already did the
     308             :      waitpid for this child.  */
     309           3 :   if (! nowait)
     310           3 :     return waitpid (pid, NULL, 0);
     311           0 :   return 0;
     312             : }
     313             : 
     314             : 
     315             : 
     316             : int
     317           1 : __assuan_socketpair (assuan_context_t ctx, int namespace, int style,
     318             :                      int protocol, assuan_fd_t filedes[2])
     319             : {
     320           1 :   return socketpair (namespace, style, protocol, filedes);
     321             : }
     322             : 
     323             : 
     324             : int
     325           0 : __assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol)
     326             : {
     327           0 :   return socket (namespace, style, protocol);
     328             : }
     329             : 
     330             : 
     331             : int
     332           0 : __assuan_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
     333             :                   socklen_t length)
     334             : {
     335           0 :   return connect (sock, addr, length);
     336             : }
     337             : 
     338             : 
     339             : 
     340             : /* The default system hooks for assuan contexts.  */
     341             : struct assuan_system_hooks _assuan_system_hooks =
     342             :   {
     343             :     ASSUAN_SYSTEM_HOOKS_VERSION,
     344             :     __assuan_usleep,
     345             :     __assuan_pipe,
     346             :     __assuan_close,
     347             :     __assuan_read,
     348             :     __assuan_write,
     349             :     __assuan_recvmsg,
     350             :     __assuan_sendmsg,
     351             :     __assuan_spawn,
     352             :     __assuan_waitpid,
     353             :     __assuan_socketpair,
     354             :     __assuan_socket,
     355             :     __assuan_connect
     356             :   };

Generated by: LCOV version 1.11