diff options
Diffstat (limited to 'gpgme/posix-io.c')
| -rw-r--r-- | gpgme/posix-io.c | 175 | 
1 files changed, 137 insertions, 38 deletions
| diff --git a/gpgme/posix-io.c b/gpgme/posix-io.c index f2a616d2..e6a3c676 100644 --- a/gpgme/posix-io.c +++ b/gpgme/posix-io.c @@ -34,6 +34,8 @@  #include <sys/types.h>  #include <sys/wait.h>  #include <ctype.h> +#include <sys/resource.h> +#include <unistd.h>  #include "util.h"  #include "priv-io.h" @@ -207,6 +209,72 @@ _gpgme_io_set_nonblocking (int fd)  } +static long int +get_max_fds (void) +{ +  char *source = NULL; +  long int fds = -1; +  int rc; + +#ifdef RLIMIT_NOFILE +  { +    struct rlimit rl; +    rc = getrlimit (RLIMIT_NOFILE, &rl); +    if (rc == 0) +      { +	source = "RLIMIT_NOFILE"; +	fds = rl.rlim_max; +      } +  } +#endif +#ifdef RLIMIT_OFILE +  if (fds == -1) +    { +      struct rlimit rl; +      rc = getrlimit (RLIMIT_OFILE, &rl); +      if (rc == 0) +	{ +	  source = "RLIMIT_OFILE"; +	  fds = rl.rlim_max; +	} +    } +#endif +#ifdef _SC_OPEN_MAX +  if (fds == -1) +    { +      long int scres; +      scres = sysconf (_SC_OPEN_MAX); +      if (scres >= 0) +	{ +	  source = "_SC_OPEN_MAX"; +	  return scres; +	} +    } +#endif +#ifdef OPEN_MAX +  if (fds == -1) +    { +      source = "OPEN_MAX"; +      fds = OPEN_MAX; +    } +#endif + +#if !defined(RLIMIT_NOFILE) && !defined(RLIMIT_OFILE) \ +  && !defined(_SC_OPEN_MAX) && !defined(OPEN_MAX) +#warning "No known way to get the maximum number of file descriptors." +#endif +  if (fds == -1) +    { +      source = "arbitrary"; +      /* Arbitrary limit.  */ +      fds = 1024; +    } + +  TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", NULL, "max fds=%i (%s)", fds, source); +  return fds; +} + +  static int  _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)  { @@ -234,8 +302,7 @@ _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)  /* Returns 0 on success, -1 on error.  */  int  _gpgme_io_spawn (const char *path, char **argv, -		 struct spawn_fd_item_s *fd_child_list, -		 struct spawn_fd_item_s *fd_parent_list, pid_t *r_pid) +		 struct spawn_fd_item_s *fd_list, pid_t *r_pid)  {    pid_t pid;    int i; @@ -249,52 +316,75 @@ _gpgme_io_spawn (const char *path, char **argv,        TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);        i++;      } -   +  for (i = 0; fd_list[i].fd != -1; i++) +    if (fd_list[i].dup_to == -1) +      TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd); +    else +      TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to); +    pid = fork ();    if (pid == -1)       return TRACE_SYSRES (-1); -   +    if (!pid)      {        /* Intermediate child to prevent zombie processes.  */        if ((pid = fork ()) == 0)  	{ +	  int max_fds = get_max_fds (); +	  int fd; +  	  /* Child.  */ -	  int duped_stdin = 0; -	  int duped_stderr = 0; +	  int seen_stdin = 0; +	  int seen_stderr = 0; -	  /* First close all fds which will not be duped.  */ -	  for (i=0; fd_child_list[i].fd != -1; i++) -	    if (fd_child_list[i].dup_to == -1) -	      close (fd_child_list[i].fd); +	  /* First close all fds which will not be inherited.  */ +	  for (fd = 0; fd < max_fds; fd++) +	    { +	      for (i = 0; fd_list[i].fd != -1; i++) +		if (fd_list[i].fd == fd) +		  break; +	      if (fd_list[i].fd == -1) +		close (fd); +	    } -	  /* And now dup and close the rest.  */ -	  for (i=0; fd_child_list[i].fd != -1; i++) +	  /* And now dup and close those to be duplicated.  */ +	  for (i = 0; fd_list[i].fd != -1; i++)  	    { -	      if (fd_child_list[i].dup_to != -1) +	      int child_fd; +	      int res; + +	      if (fd_list[i].dup_to != -1) +		child_fd = fd_list[i].dup_to; +	      else +		child_fd = fd_list[i].fd; + +	      if (child_fd == 0) +		seen_stdin = 1; +	      else if (child_fd == 2) +		seen_stderr = 1; + +	      if (fd_list[i].dup_to == -1) +		continue; + +	      res = dup2 (fd_list[i].fd, fd_list[i].dup_to); +	      if (res < 0)  		{ -		  if (dup2 (fd_child_list[i].fd, -			    fd_child_list[i].dup_to) == -1) -		    {  #if 0 -		      /* FIXME: The debug file descriptor is not -			 dup'ed anyway, so we can't see this.  */ -		      TRACE_LOG1 ("dup2 failed in child: %s\n", -				  strerror (errno)); +		  /* FIXME: The debug file descriptor is not +		     dup'ed anyway, so we can't see this.  */ +		  TRACE_LOG1 ("dup2 failed in child: %s\n", +			      strerror (errno));  #endif -		      _exit (8); -		    } -		  if (fd_child_list[i].dup_to == 0) -		    duped_stdin=1; -		  if (fd_child_list[i].dup_to == 2) -		    duped_stderr=1; -		  close (fd_child_list[i].fd); +		  _exit (8);  		} + +	      close (fd_list[i].fd);  	    } -	  if (!duped_stdin || !duped_stderr) +	  if (! seen_stdin || ! seen_stderr)  	    { -	      int fd = open ("/dev/null", O_RDWR); +	      fd = open ("/dev/null", O_RDWR);  	      if (fd == -1)  		{  #if 0 @@ -306,7 +396,7 @@ _gpgme_io_spawn (const char *path, char **argv,  		  _exit (8);  		}  	      /* Make sure that the process has a connected stdin.  */ -	      if (!duped_stdin) +	      if (! seen_stdin && fd != 0)  		{  		  if (dup2 (fd, 0) == -1)  		    { @@ -319,7 +409,7 @@ _gpgme_io_spawn (const char *path, char **argv,  		      _exit (8);  		    }  		} -	      if (!duped_stderr) +	      if (! seen_stderr && fd != 2)  		if (dup2 (fd, 2) == -1)  		  {  #if 0 @@ -330,10 +420,11 @@ _gpgme_io_spawn (const char *path, char **argv,  #endif  		    _exit (8);  		  } -	      close (fd); +	      if (fd != 0 && fd != 2) +		close (fd);  	    } -	  execv ( path, argv ); +	  execv (path, argv);  	  /* Hmm: in that case we could write a special status code to the  	     status-pipe.  */  #if 0 @@ -342,7 +433,8 @@ _gpgme_io_spawn (const char *path, char **argv,  	  TRACE_LOG1 ("exec of `%s' failed\n", path);  #endif  	  _exit (8); -	} /* End child.  */ +	  /* End child.  */ +	}        if (pid == -1)  	_exit (1);        else @@ -354,9 +446,12 @@ _gpgme_io_spawn (const char *path, char **argv,    if (status)      return TRACE_SYSRES (-1); -  /* .dup_to is not used in the parent list.  */ -  for (i = 0; fd_parent_list[i].fd != -1; i++) -    _gpgme_io_close (fd_parent_list[i].fd); +  for (i = 0; fd_list[i].fd != -1; i++) +    { +      _gpgme_io_close (fd_list[i].fd); +      /* No handle translation.  */ +      fd_list[i].peer_name = fd_list[i].fd; +    }    if (r_pid)      *r_pid = pid; @@ -549,5 +644,9 @@ _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)  int  _gpgme_io_dup (int fd)  { -  return dup (fd); +  int new_fd = dup (fd); + +  TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd); + +  return new_fd;  } | 
