diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /gpglib/fork.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'gpglib/fork.c')
| -rw-r--r-- | gpglib/fork.c | 359 | 
1 files changed, 359 insertions, 0 deletions
| diff --git a/gpglib/fork.c b/gpglib/fork.c new file mode 100644 index 0000000..b44c0ac --- /dev/null +++ b/gpglib/fork.c @@ -0,0 +1,359 @@ +/* +** Copyright 2001-2006 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + + +#include	"config.h" +#include	<stdio.h> +#include	<stdlib.h> +#include	<string.h> +#include	<unistd.h> +#include	<signal.h> +#include	<errno.h> +#include	<sys/types.h> +#include	<sys/stat.h> +#include	<sys/time.h> +#if HAVE_SYS_WAIT_H +#include	<sys/wait.h> +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +#include	"gpg.h" +#include	"gpglib.h" + +extern int libmail_gpg_stdin, libmail_gpg_stdout, libmail_gpg_stderr; +extern pid_t libmail_gpg_pid; + + +/* +** Helper function: for and run pgp, with the given file descriptors and +** options. +*/ + +pid_t libmail_gpg_fork(int *libmail_gpg_stdin, int *libmail_gpg_stdout, +		       int *libmail_gpg_stderr, +		       const char *gpgdir, +		       char **argvec) +{ +	int pipein[2], pipeout[2], pipeerr[2]; +	pid_t p; +	char *s; + +	if (libmail_gpg_stdin && pipe(pipein) < 0) +		return (-1); + +	if (libmail_gpg_stdout && pipe(pipeout) < 0) +	{ +		if (libmail_gpg_stdin) +		{ +			close(pipein[0]); +			close(pipein[1]); +		} +		return (-1); +	} + +	if (libmail_gpg_stderr && pipe(pipeerr) < 0) +	{ +		if (libmail_gpg_stdout) +		{ +			close(pipeout[0]); +			close(pipeout[1]); +		} + +		if (libmail_gpg_stdin) +		{ +			close(pipein[0]); +			close(pipein[1]); +		} +		return (-1); +	} + +	signal(SIGCHLD, SIG_DFL); +	p=libmail_gpg_pid=fork(); +	if (p < 0) +	{ +		if (libmail_gpg_stderr) +		{ +			close(pipeerr[0]); +			close(pipeerr[1]); +		} + +		if (libmail_gpg_stdout) +		{ +			close(pipeout[0]); +			close(pipeout[1]); +		} +		if (libmail_gpg_stdin) +		{ +			close(pipein[0]); +			close(pipein[1]); +		} + +		return (-1); +	} + +	if (p) +	{ +		signal(SIGPIPE, SIG_IGN); + +		if (libmail_gpg_stderr) +		{ +			close(pipeerr[1]); +			*libmail_gpg_stderr=pipeerr[0]; +		} + +		if (libmail_gpg_stdout) +		{ +			close(pipeout[1]); +			*libmail_gpg_stdout=pipeout[0]; +		} + +		if (libmail_gpg_stdin) +		{ +			close(pipein[0]); +			*libmail_gpg_stdin=pipein[1]; +		} +		return (0); +	} + +	if (libmail_gpg_stderr) +	{ +		dup2(pipeerr[1], 2); +		close(pipeerr[0]); +		close(pipeerr[1]); +	} +	else if (libmail_gpg_stdout) +	{ +		dup2(pipeout[1], 2); +	} + +	if (libmail_gpg_stdout) +	{ +		dup2(pipeout[1], 1); +		close(pipeout[0]); +		close(pipeout[1]); +	} + +	if (libmail_gpg_stdin) +	{ +		dup2(pipein[0], 0); +		close(pipein[0]); +		close(pipein[1]); +	} + +	if (gpgdir) +	{ +		s=malloc(sizeof("GNUPGHOME=")+strlen(gpgdir)); +		if (!s) +		{ +			perror("malloc"); +			exit(1); +		} +		strcat(strcpy(s, "GNUPGHOME="), gpgdir); +		if (putenv(s) < 0) +		{ +			perror("putenv"); +			exit(1); +		} +	} + +	{ +		const char *gpg=getenv("GPG"); +		if (!gpg || !*gpg) +			gpg=GPG; + +		execv(gpg, argvec); +		perror(gpg); +	} +	_exit(1); +	return (0); +} + +int libmail_gpg_write(const char *p, size_t cnt, +		      int (*stdout_func)(const char *, size_t, void *), +		      int (*stderr_func)(const char *, size_t, void *), +		      int (*timeout_func)(void *), +		      unsigned timeout, +		      void *voidarg) +{ +	char buf[BUFSIZ]; + +	fd_set fdr, fdw; +	struct timeval tv; + +	if (!timeout_func) +		timeout=0; +	while (cnt) +	{ +		int maxfd=0; +		int n; + +		FD_ZERO(&fdr); +		FD_ZERO(&fdw); + +		FD_SET(libmail_gpg_stdin, &fdw); + +		if (libmail_gpg_stdout >= 0) +		{ +			FD_SET(libmail_gpg_stdout, &fdr); +			if (libmail_gpg_stdout > maxfd) +				maxfd=libmail_gpg_stdout; +		} + +		if (libmail_gpg_stderr >= 0) +		{ +			FD_SET(libmail_gpg_stderr, &fdr); +			if (libmail_gpg_stderr > maxfd) +				maxfd=libmail_gpg_stderr; +		} + +		tv.tv_usec=0; +		tv.tv_sec=timeout; +		n=select(maxfd+1, &fdr, &fdw, NULL, timeout ? &tv:NULL); +		if (n == 0) +		{ +			n=(*timeout_func)(voidarg); +			if (n) +				return(n); +			continue; +		} +		if (n < 0) +			continue; + +		if (FD_ISSET(libmail_gpg_stdin, &fdw)) +		{ +			int n=write(libmail_gpg_stdin, p, cnt); + +			if (n <= 0) +				return (-1); + +			p += n; +			cnt -= n; +		} + +		if (libmail_gpg_stdout >= 0 && +		    FD_ISSET(libmail_gpg_stdout, &fdr)) +		{ +			int n=read(libmail_gpg_stdout, buf, sizeof(buf)); + +			if (n <= 0) +			{ +				close(libmail_gpg_stdout); +				libmail_gpg_stdout= -1; +			} +			else if (stdout_func && +				 (n=(*stdout_func)(buf, n, voidarg)) != 0) +				return (n); +		} + +		if (libmail_gpg_stderr >= 0 && +		    FD_ISSET(libmail_gpg_stderr, &fdr)) +		{ +			int n=read(libmail_gpg_stderr, buf, sizeof(buf)); + +			if (n <= 0) +			{ +				close(libmail_gpg_stderr); +				libmail_gpg_stderr= -1; +			} +			else if (stderr_func && +				 (n=(*stderr_func)(buf, n, voidarg)) != 0) +				return (n); +		} +	} +	return (0); +} + +int libmail_gpg_read(int (*stdout_func)(const char *, size_t, void *), +		     int (*stderr_func)(const char *, size_t, void *), +		     int (*timeout_func)(void *), +		     unsigned timeout, +		     void *voidarg) +{ +	char buf[BUFSIZ]; + +	fd_set fdr; +	struct timeval tv; + +	if (libmail_gpg_stdin >= 0) +	{ +		close(libmail_gpg_stdin); +		libmail_gpg_stdin= -1; +	} + +	if (!timeout_func) +		timeout=0; + +	while ( libmail_gpg_stdout >= 0 || libmail_gpg_stderr >= 0) +	{ +		int maxfd=0; +		int n; + +		FD_ZERO(&fdr); + +		if (libmail_gpg_stdout >= 0) +		{ +			FD_SET(libmail_gpg_stdout, &fdr); +			if (libmail_gpg_stdout > maxfd) +				maxfd=libmail_gpg_stdout; +		} + +		if (libmail_gpg_stderr >= 0) +		{ +			FD_SET(libmail_gpg_stderr, &fdr); +			if (libmail_gpg_stderr > maxfd) +				maxfd=libmail_gpg_stderr; +		} + +		tv.tv_usec=0; +		tv.tv_sec=timeout; +		n=select(maxfd+1, &fdr, NULL, NULL, timeout ? &tv:NULL); + +		if (n == 0) +		{ +			n=(*timeout_func)(voidarg); +			if (n) +				return(n); +			continue; +		} +		if (n < 0) +			continue; + +		if (libmail_gpg_stdout >= 0 && +		    FD_ISSET(libmail_gpg_stdout, &fdr)) +		{ +			int n=read(libmail_gpg_stdout, buf, sizeof(buf)); + +			if (n <= 0) +			{ +				close(libmail_gpg_stdout); +				libmail_gpg_stdout= -1; +			} +			else if (stdout_func && +				 (n=(*stdout_func)(buf, n, voidarg)) != 0) +				return (n); +		} + +		if (libmail_gpg_stderr >= 0 && +		    FD_ISSET(libmail_gpg_stderr, &fdr)) +		{ +			int n=read(libmail_gpg_stderr, buf, sizeof(buf)); + +			if (n <= 0) +			{ +				close(libmail_gpg_stderr); +				libmail_gpg_stderr= -1; +			} +			else if (stderr_func && +				 (n=(*stderr_func)(buf, n, voidarg)) != 0) +				return (n); +		} +	} +	return (0); +} | 
