diff --git a/configure.ac b/configure.ac index cd1a80d..755a55c 100644 --- a/configure.ac +++ b/configure.ac @@ -1,463 +1,464 @@ # configure.ac - for libassuan # Copyright (C) 2001, 2002, 2003, 2006, 2007, 2009, # 2011, 2012, 2013 Free Software Foundation, Inc. # Copyright (C) 2013, 2014, 2015 g10 Code GmbH # # This file is part of Assuan. # # Assuan is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 2.1 of # the License, or (at your option) any later version. # # Assuan is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, see . # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) min_automake_version="1.14" # To build a release you need to create a tag with the version number # (git tag -s libassuan-n.m.k) and run "./autogen.sh --force". Please # bump the version number immediately after the release and do another # commit and push so that the git magic is able to work. See below # for the LT versions. m4_define([mym4_package],[libassuan]) m4_define([mym4_major], [2]) m4_define([mym4_minor], [4]) m4_define([mym4_micro], [3]) # To start a new development series, i.e a new major or minor number # you need to mark an arbitrary commit before the first beta release # with an annotated tag. For example a 2.1 branch starts off with # the tag "foo-2.1-base". This is used as the base for counting # beta numbers before the first release of a series. # Below is m4 magic to extract and compute the git revision number, # the decimalized short revision number, a beta version string and a # flag indicating a development version (mym4_isbeta). Note that the # m4 processing is done by autoconf and not during the configure run. m4_define([mym4_verslist], m4_split(m4_esyscmd([./autogen.sh --find-version] \ mym4_package mym4_major mym4_minor mym4_micro),[:])) m4_define([mym4_isbeta], m4_argn(2, mym4_verslist)) m4_define([mym4_version], m4_argn(4, mym4_verslist)) m4_define([mym4_revision], m4_argn(7, mym4_verslist)) m4_define([mym4_revision_dec], m4_argn(8, mym4_verslist)) AC_INIT([mym4_package],[mym4_version], [http://bugs.gnupg.org]) # LT Version numbers, remember to change them just *before* a release. # (Code changed: REVISION++) # (Interfaces added/removed/changed: CURRENT++, REVISION=0) # (Interfaces added: AGE++) # (Interfaces removed/changed: AGE=0) # LIBASSUAN_LT_CURRENT=7 LIBASSUAN_LT_AGE=7 LIBASSUAN_LT_REVISION=2 # If the API is changed in an incompatible way: increment the next counter. LIBASSUAN_CONFIG_API_VERSION=2 ############################################## AC_SUBST(LIBASSUAN_LT_CURRENT) AC_SUBST(LIBASSUAN_LT_AGE) AC_SUBST(LIBASSUAN_LT_REVISION) PACKAGE=$PACKAGE_NAME VERSION=$PACKAGE_VERSION AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([serial-tests dist-bzip2 no-dist-gzip]) AM_MAINTAINER_MODE AC_CONFIG_SRCDIR(src/assuan.h.in) AC_CONFIG_MACRO_DIR(m4) AM_CONFIG_HEADER(config.h) AC_CANONICAL_HOST AM_SILENT_RULES AB_INIT AC_GNU_SOURCE AC_SUBST(PACKAGE) AC_SUBST(VERSION) AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of this package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version of this package]) AC_DEFINE_UNQUOTED(PACKAGE_BUGREPORT, "$PACKAGE_BUGREPORT",[Bug report address]) VERSION_NUMBER=m4_esyscmd(printf "0x%02x%02x%02x" mym4_major \ mym4_minor mym4_micro) AC_SUBST(VERSION_NUMBER) # Don't default to build static libs. LT_PREREQ([2.2.6]) LT_INIT([win32-dll disable-static]) LT_LANG([Windows Resource]) # For now we hardcode the use of version scripts. It would be better # to write a test for this or even implement this within libtool. have_ld_version_script=no case "${host}" in *-*-linux*) have_ld_version_script=yes ;; *-*-gnu*) have_ld_version_script=yes ;; *-apple-darwin*) AC_DEFINE(_XOPEN_SOURCE, 500, Activate POSIX interface on MacOS X) AC_DEFINE(_DARWIN_C_SOURCE, 1, Activate CMSG_LEN/CMSG_SPACE on MacOS X) ;; esac AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes") AH_TOP([ #ifndef _ASSUAN_CONFIG_H_INCLUDED #define _ASSUAN_CONFIG_H_INCLUDED /* Enable gpg-error's strerror macro under W32CE. */ #define GPG_ERR_ENABLE_ERRNO_MACROS 1 /* Provide the es_ macro for estream. */ #define GPGRT_ENABLE_ES_MACROS 1 ]) AH_BOTTOM([ #endif /*_ASSUAN_CONFIG_H_INCLUDED*/ ]) # Checks for programs. missing_dir=`cd $ac_aux_dir && pwd` AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) AC_PROG_AWK AC_PROG_CC AC_PROG_CPP AM_PROG_CC_C_O if test "x$ac_cv_prog_cc_c89" = "xno" ; then AC_MSG_ERROR([[No C-89 compiler found]]) fi AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET #AC_ARG_PROGRAM # We need to compile and run a program on the build machine. A # comment in libgpg-error says that the AC_PROG_CC_FOR_BUILD macro in # the AC archive is broken for autoconf 2.57. Given that there is no # newer version of that macro, we assume that it is also broken for # autoconf 2.61 and thus we use a simple but usually sufficient # approach. AC_MSG_CHECKING(for cc for build) if test "$cross_compiling" = "yes"; then CC_FOR_BUILD="${CC_FOR_BUILD-cc}" else CC_FOR_BUILD="${CC_FOR_BUILD-$CC}" fi AC_MSG_RESULT($CC_FOR_BUILD) AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler]) if test "$GCC" = yes; then CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes" AC_MSG_CHECKING([if gcc supports -Wpointer-arith]) _gcc_cflags_save=$CFLAGS CFLAGS="-Wpointer-arith" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],_gcc_wopt=yes,_gcc_wopt=no) AC_MSG_RESULT($_gcc_wopt) CFLAGS=$_gcc_cflags_save; if test x"$_gcc_wopt" = xyes ; then CFLAGS="$CFLAGS -Wpointer-arith" fi fi # # Options depending on the host OS. # have_dosish_system=no have_w32_system=no have_w64_system=no have_w32ce_system=no case "${host}" in *-linux*) if test "$GCC" = yes; then CFLAGS="$CFLAGS -fPIC -DPIC" fi ;; x86_64-*mingw32*) have_dosish_system=yes have_w32_system=yes have_w64_system=yes ;; *-mingw32ce*) have_dosish_system=yes have_w32_system=yes have_w32ce_system=yes ;; *-mingw32*) have_dosish_system=yes have_w32_system=yes ;; *-solaris*) AC_DEFINE(_XOPEN_SOURCE, 500, Activate extensions on Solaris) AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, Activate extensions on Solaris) AC_DEFINE(__EXTENSIONS__, 1, Activate extensions on Solaris) ;; esac if test "$have_dosish_system" = yes; then AC_DEFINE(HAVE_DOSISH_SYSTEM,1, [Defined if we run on some of the PCDOS like systems (DOS, Windoze. OS/2) with special properties like no file modes]) fi if test "$have_w32_system" = yes; then AC_DEFINE(HAVE_W32_SYSTEM,1,[Defined if we run on a W32 API based system]) if test "$have_w64_system" = yes; then AC_DEFINE(HAVE_W64_SYSTEM,1, [Defined if we run on a 64 bit W32 API based system]) fi if test "$have_w32ce_system" = yes; then AC_DEFINE(HAVE_W32CE_SYSTEM,1,[Defined if we run on WindowsCE]) fi fi AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes) AM_CONDITIONAL(HAVE_W32CE_SYSTEM, test "$have_w32ce_system" = yes) AM_CONDITIONAL(HAVE_W64_SYSTEM, test "$have_w64_system" = yes) # # Provide information about the build. # BUILD_REVISION="mym4_revision" AC_SUBST(BUILD_REVISION) AC_DEFINE_UNQUOTED(BUILD_REVISION, "$BUILD_REVISION", [GIT commit id revision used to build this package]) changequote(,)dnl BUILD_FILEVERSION=`echo "$VERSION" | sed 's/\([0-9.]*\).*/\1./;s/\./,/g'` changequote([,])dnl BUILD_FILEVERSION="${BUILD_FILEVERSION}mym4_revision_dec" AC_SUBST(BUILD_FILEVERSION) AC_ARG_ENABLE([build-timestamp], AC_HELP_STRING([--enable-build-timestamp], [set an explicit build timestamp for reproducibility. (default is the current time in ISO-8601 format)]), [if test "$enableval" = "yes"; then BUILD_TIMESTAMP=`date -u +%Y-%m-%dT%H:%M+0000 2>/dev/null || date` else BUILD_TIMESTAMP="$enableval" fi], [BUILD_TIMESTAMP=""]) AC_SUBST(BUILD_TIMESTAMP) AC_DEFINE_UNQUOTED(BUILD_TIMESTAMP, "$BUILD_TIMESTAMP", [The time this package was configured for a build]) # # Check for network libraries. They are needed for tests. # AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt, [NETLIBS="-lsocket $NETLIBS"])) AC_SUBST(NETLIBS) if test "$have_w32_system" = yes; then if test "$have_w32ce_system" = yes; then NETLIBS="-lws2 $NETLIBS" else # FIXME: Check why we need to use ws2_32 and document that. NETLIBS="-lws2_32 $NETLIBS" fi fi # # Provide info for src/libassuan-config.in # LIBASSUAN_CONFIG_LIB="-lassuan" LIBASSUAN_CONFIG_CFLAGS="" LIBASSUAN_CONFIG_HOST="$host" LIBASSUAN_CONFIG_EXTRA_LIBS= if test x"$NETLIBS" != x; then LIBASSUAN_CONFIG_EXTRA_LIBS="$LIBASSUAN_CONFIG_EXTRA_LIBS $NETLIBS" fi AC_SUBST(LIBASSUAN_CONFIG_LIB) AC_SUBST(LIBASSUAN_CONFIG_CFLAGS) AC_SUBST(LIBASSUAN_CONFIG_HOST) AC_SUBST(LIBASSUAN_CONFIG_API_VERSION) AC_SUBST(LIBASSUAN_CONFIG_EXTRA_LIBS) # # Checks for header files. # AC_HEADER_STDC AC_CHECK_HEADERS([string.h locale.h sys/uio.h stdint.h inttypes.h \ sys/types.h sys/stat.h unistd.h sys/time.h fcntl.h \ sys/select.h ]) AC_TYPE_UINTPTR_T AC_TYPE_UINT16_T # # Checks for typedefs, structures, and compiler characteristics. # AC_C_CONST AC_C_INLINE AC_TYPE_SIZE_T AC_TYPE_SIGNAL AC_DECL_SYS_SIGLIST gl_HEADER_SYS_SOCKET gl_TYPE_SOCKLEN_T AC_CHECK_MEMBER(struct cmsghdr.cmsg_len, [use_descriptor_passing=yes], [use_descriptor_passing=no AC_MSG_WARN([ *** *** Data structure for sending ancillary data missing. *** Descriptor passing won't work. ***])],[ #include #include #include #include #include #include #if HAVE_SYS_UIO_H #include #endif #include ]) if test "$use_descriptor_passing" = "yes"; then AC_DEFINE(USE_DESCRIPTOR_PASSING, 1, [Defined if descriptor passing is supported]) fi AM_CONDITIONAL(USE_DESCRIPTOR_PASSING, test "$use_descriptor_passing" = "yes") # Checking for libgpg-error. AM_PATH_GPG_ERROR(1.17,, AC_MSG_ERROR([libgpg-error was not found])) # # Checks for library functions. # -AC_CHECK_FUNCS([flockfile funlockfile inet_pton stat getaddrinfo]) +AC_CHECK_FUNCS([flockfile funlockfile inet_pton stat getaddrinfo \ + getrlimit ]) # On some systems (e.g. Solaris) nanosleep requires linking to librl. # Given that we use nanosleep only as an optimization over a select # based wait function we want it only if it is available in libc. _save_libs="$LIBS" AC_SEARCH_LIBS([nanosleep], [], [AC_DEFINE(HAVE_NANOSLEEP,1, [Define to 1 if you have the `nanosleep' function in libc.])]) LIBS="$_save_libs" # Check for funopen AC_CHECK_FUNCS(funopen) if test $ac_cv_func_funopen != yes; then # No funopen but we can implement that in terms of fopencookie. AC_CHECK_FUNCS(fopencookie) if test $ac_cv_func_fopencookie = yes; then AC_LIBOBJ([funopen]) else AC_MSG_WARN([ *** *** No implementation of fopencookie or funopen available. *** The assuan_get_data_fp function won't work; see the *** manual for details. GnuPG does not require this feature. ***]) fi fi AC_REPLACE_FUNCS(isascii) AC_REPLACE_FUNCS(putc_unlocked) AC_REPLACE_FUNCS(memrchr) AC_REPLACE_FUNCS(stpcpy) AC_CHECK_HEADERS(unistd.h) AC_REPLACE_FUNCS(setenv) # # Check for the getsockopt SO_PEERCRED # AC_MSG_CHECKING(for SO_PEERCRED) AC_CACHE_VAL(assuan_cv_sys_so_peercred, [AC_TRY_COMPILE([#include ], [struct ucred cr; int cl = sizeof cr; getsockopt (1, SOL_SOCKET, SO_PEERCRED, &cr, &cl);], assuan_cv_sys_so_peercred=yes, assuan_cv_sys_so_peercred=no) ]) AC_MSG_RESULT($assuan_cv_sys_so_peercred) if test $assuan_cv_sys_so_peercred = yes; then AC_DEFINE(HAVE_SO_PEERCRED, 1, [Defined if SO_PEERCRED is supported (Linux specific)]) else # Check for the getsockopt LOCAL_PEEREID (NetBSD) AC_MSG_CHECKING(for LOCAL_PEEREID) AC_CACHE_VAL(assuan_cv_sys_so_local_peereid, [AC_TRY_COMPILE([#include #include ], [struct unpcbid unp; int unpl = sizeof unp; getsockopt (1, SOL_SOCKET, LOCAL_PEEREID, &unp, &unpl);], assuan_cv_sys_so_local_peereid=yes, assuan_cv_sys_so_local_peereid=no) ]) AC_MSG_RESULT($assuan_cv_sys_so_local_peereid) if test $assuan_cv_sys_so_local_peereid = yes; then AC_DEFINE(HAVE_LOCAL_PEEREID, 1, [Defined if LOCAL_PEEREID is supported (NetBSD specific)]) else # (Open)Solaris AC_CHECK_FUNCS([getpeerucred], AC_CHECK_HEADERS([ucred.h])) if test $ac_cv_func_getpeerucred != yes; then # FreeBSD AC_CHECK_FUNCS([getpeereid]) fi fi fi # # Create the config files. # AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([m4/Makefile]) AC_CONFIG_FILES([src/Makefile]) AC_CONFIG_FILES([doc/Makefile]) AC_CONFIG_FILES([tests/Makefile]) AC_CONFIG_FILES([src/libassuan-config], [chmod +x src/libassuan-config]) AC_CONFIG_FILES([src/versioninfo.rc]) AC_OUTPUT echo " Libassuan v${VERSION} has been configured as follows: Revision: mym4_revision (mym4_revision_dec) Platform: $host " diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c index edc8dbb..e5d2a38 100644 --- a/src/assuan-pipe-connect.c +++ b/src/assuan-pipe-connect.c @@ -1,434 +1,427 @@ /* assuan-pipe-connect.c - Establish a pipe connection (client) Copyright (C) 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc. This file is part of Assuan. Assuan is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. Assuan is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include /* On Windows systems signal.h is not needed and even not supported on WindowsCE. */ #ifndef HAVE_DOSISH_SYSTEM # include #endif #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifndef HAVE_W32_SYSTEM # include #else # ifdef HAVE_WINSOCK2_H # include # endif # include #endif #include "assuan-defs.h" #include "debug.h" /* Hacks for Slowaris. */ #ifndef PF_LOCAL # ifdef PF_UNIX # define PF_LOCAL PF_UNIX # else # define PF_LOCAL AF_UNIX # endif #endif #ifndef AF_LOCAL # define AF_LOCAL AF_UNIX #endif -#ifdef _POSIX_OPEN_MAX -#define MAX_OPEN_FDS _POSIX_OPEN_MAX -#else -#define MAX_OPEN_FDS 20 -#endif - - /* This should be called to make sure that SIGPIPE gets ignored. */ static void fix_signals (void) { #ifndef HAVE_DOSISH_SYSTEM /* No SIGPIPE for these systems. */ static int fixed_signals; if (!fixed_signals) { struct sigaction act; sigaction (SIGPIPE, NULL, &act); if (act.sa_handler == SIG_DFL) { act.sa_handler = SIG_IGN; sigemptyset (&act.sa_mask); act.sa_flags = 0; sigaction (SIGPIPE, &act, NULL); } fixed_signals = 1; /* FIXME: This is not MT safe */ } #endif /*HAVE_DOSISH_SYSTEM*/ } /* Helper for pipe_connect. */ static gpg_error_t initial_handshake (assuan_context_t ctx) { assuan_response_t response; int off; gpg_error_t err; err = _assuan_read_from_server (ctx, &response, &off, 0); if (err) TRACE1 (ctx, ASSUAN_LOG_SYSIO, "initial_handshake", ctx, "can't connect server: %s", gpg_strerror (err)); else if (response != ASSUAN_RESPONSE_OK) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "initial_handshake", ctx, "can't connect server: `%s'", ctx->inbound.line); err = _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED); } return err; } struct at_pipe_fork { void (*user_atfork) (void *opaque, int reserved); void *user_atforkvalue; pid_t parent_pid; }; static void at_pipe_fork_cb (void *opaque, int reserved) { struct at_pipe_fork *atp = opaque; if (atp->user_atfork) atp->user_atfork (atp->user_atforkvalue, reserved); #ifndef HAVE_W32_SYSTEM { char mypidstr[50]; /* We store our parents pid in the environment so that the execed assuan server is able to read the actual pid of the client. The server can't use getppid because it might have been double forked before the assuan server has been initialized. */ sprintf (mypidstr, "%lu", (unsigned long) atp->parent_pid); setenv ("_assuan_pipe_connect_pid", mypidstr, 1); /* Make sure that we never pass a connection fd variable when using a simple pipe. */ unsetenv ("_assuan_connection_fd"); } #endif } static gpg_error_t pipe_connect (assuan_context_t ctx, const char *name, const char **argv, assuan_fd_t *fd_child_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue, unsigned int flags) { gpg_error_t rc; assuan_fd_t rp[2]; assuan_fd_t wp[2]; pid_t pid; int res; struct at_pipe_fork atp; unsigned int spawn_flags; atp.user_atfork = atfork; atp.user_atforkvalue = atforkvalue; atp.parent_pid = getpid (); if (!ctx || !name || !argv || !argv[0]) return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (! ctx->flags.no_fixsignals) fix_signals (); if (_assuan_pipe (ctx, rp, 1) < 0) return _assuan_error (ctx, gpg_err_code_from_syserror ()); if (_assuan_pipe (ctx, wp, 0) < 0) { _assuan_close (ctx, rp[0]); _assuan_close_inheritable (ctx, rp[1]); return _assuan_error (ctx, gpg_err_code_from_syserror ()); } spawn_flags = 0; if (flags & ASSUAN_PIPE_CONNECT_DETACHED) spawn_flags |= ASSUAN_SPAWN_DETACHED; /* FIXME: Use atfork handler that closes child fds on Unix. */ res = _assuan_spawn (ctx, &pid, name, argv, wp[0], rp[1], fd_child_list, at_pipe_fork_cb, &atp, spawn_flags); if (res < 0) { rc = gpg_err_code_from_syserror (); _assuan_close (ctx, rp[0]); _assuan_close_inheritable (ctx, rp[1]); _assuan_close_inheritable (ctx, wp[0]); _assuan_close (ctx, wp[1]); return _assuan_error (ctx, rc); } /* Close the stdin/stdout child fds in the parent. */ _assuan_close_inheritable (ctx, rp[1]); _assuan_close_inheritable (ctx, wp[0]); ctx->engine.release = _assuan_client_release; ctx->engine.readfnc = _assuan_simple_read; ctx->engine.writefnc = _assuan_simple_write; ctx->engine.sendfd = NULL; ctx->engine.receivefd = NULL; ctx->finish_handler = _assuan_client_finish; ctx->max_accepts = 1; ctx->accept_handler = NULL; ctx->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */ ctx->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */ ctx->pid = pid; rc = initial_handshake (ctx); if (rc) _assuan_reset (ctx); return rc; } /* FIXME: For socketpair_connect, use spawn function and add atfork handler to do the right thing. Instead of stdin and stdout, we extend the fd_child_list by fds[1]. */ #ifndef HAVE_W32_SYSTEM struct at_socketpair_fork { assuan_fd_t peer_fd; void (*user_atfork) (void *opaque, int reserved); void *user_atforkvalue; pid_t parent_pid; }; static void at_socketpair_fork_cb (void *opaque, int reserved) { struct at_socketpair_fork *atp = opaque; if (atp->user_atfork) atp->user_atfork (atp->user_atforkvalue, reserved); #ifndef HAVE_W32_SYSTEM { char mypidstr[50]; /* We store our parents pid in the environment so that the execed assuan server is able to read the actual pid of the client. The server can't use getppid because it might have been double forked before the assuan server has been initialized. */ sprintf (mypidstr, "%lu", (unsigned long) atp->parent_pid); setenv ("_assuan_pipe_connect_pid", mypidstr, 1); /* Now set the environment variable used to convey the connection's file descriptor. */ sprintf (mypidstr, "%d", atp->peer_fd); if (setenv ("_assuan_connection_fd", mypidstr, 1)) _exit (4); } #endif } /* This function is similar to pipe_connect but uses a socketpair and sets the I/O up to use sendmsg/recvmsg. */ static gpg_error_t socketpair_connect (assuan_context_t ctx, const char *name, const char **argv, assuan_fd_t *fd_child_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue) { gpg_error_t err; int idx; int fds[2]; char mypidstr[50]; pid_t pid; int *child_fds = NULL; int child_fds_cnt = 0; struct at_socketpair_fork atp; int rc; TRACE_BEG3 (ctx, ASSUAN_LOG_CTX, "socketpair_connect", ctx, "name=%s,atfork=%p,atforkvalue=%p", name ? name : "(null)", atfork, atforkvalue); atp.user_atfork = atfork; atp.user_atforkvalue = atforkvalue; atp.parent_pid = getpid (); if (!ctx || (name && (!argv || !argv[0])) || (!name && !argv)) return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (! ctx->flags.no_fixsignals) fix_signals (); sprintf (mypidstr, "%lu", (unsigned long)getpid ()); if (fd_child_list) while (fd_child_list[child_fds_cnt] != ASSUAN_INVALID_FD) child_fds_cnt++; child_fds = _assuan_malloc (ctx, (child_fds_cnt + 2) * sizeof (int)); if (! child_fds) return TRACE_ERR (gpg_err_code_from_syserror ()); child_fds[1] = ASSUAN_INVALID_FD; if (fd_child_list) memcpy (&child_fds[1], fd_child_list, (child_fds_cnt + 1) * sizeof (int)); if (_assuan_socketpair (ctx, AF_LOCAL, SOCK_STREAM, 0, fds)) { TRACE_LOG1 ("socketpair failed: %s", strerror (errno)); _assuan_free (ctx, child_fds); return TRACE_ERR (GPG_ERR_ASS_GENERAL); } atp.peer_fd = fds[1]; child_fds[0] = fds[1]; rc = _assuan_spawn (ctx, &pid, name, argv, ASSUAN_INVALID_FD, ASSUAN_INVALID_FD, child_fds, at_socketpair_fork_cb, &atp, 0); if (rc < 0) { err = gpg_err_code_from_syserror (); _assuan_close (ctx, fds[0]); _assuan_close (ctx, fds[1]); _assuan_free (ctx, child_fds); return TRACE_ERR (err); } /* For W32, the user needs to know the server-local names of the inherited handles. Return them here. Note that the translation of the peer socketpair fd (fd_child_list[0]) must be done by the wrapper program based on the environment variable _assuan_connection_fd. */ if (fd_child_list) { for (idx = 0; fd_child_list[idx] != -1; idx++) /* We add 1 to skip over the socketpair end. */ fd_child_list[idx] = child_fds[idx + 1]; } /* If this is the server child process, exit early. */ if (! name && (*argv)[0] == 's') { _assuan_free (ctx, child_fds); _assuan_close (ctx, fds[0]); return 0; } _assuan_close (ctx, fds[1]); ctx->engine.release = _assuan_client_release; ctx->finish_handler = _assuan_client_finish; ctx->max_accepts = 1; ctx->inbound.fd = fds[0]; ctx->outbound.fd = fds[0]; _assuan_init_uds_io (ctx); err = initial_handshake (ctx); if (err) _assuan_reset (ctx); return err; } #endif /*!HAVE_W32_SYSTEM*/ /* Connect to a server over a full-duplex socket (i.e. created by socketpair), creating the assuan context and returning it in CTX. The server filename is NAME, the argument vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file descriptors not to close in the child. ATFORK is called in the child right after the fork; ATFORKVALUE is passed as the first argument and 0 is passed as the second argument. The ATFORK function should only act if the second value is 0. FLAGS is a bit vector and controls how the function acts: Bit 0: If cleared a simple pipe based server is expected and the function behaves similar to `assuan_pipe_connect'. If set a server based on full-duplex pipes is expected. Such pipes are usually created using the `socketpair' function. It also enables features only available with such servers. Bit 7: If set and there is a need to start the server it will be started as a background process. This flag is useful under W32 systems, so that no new console is created and pops up a console window when starting the server If NAME is NULL, no exec is done but the same process is continued. However all file descriptors are closed and some special environment variables are set. To let the caller detect whether the child or the parent continues, the child returns "client" or "server" in *ARGV (but it is sufficient to check only the first character). This feature is only available on POSIX platforms. */ gpg_error_t assuan_pipe_connect (assuan_context_t ctx, const char *name, const char *argv[], assuan_fd_t *fd_child_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue, unsigned int flags) { TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_pipe_connect", ctx, "name=%s, flags=0x%x", name ? name : "(null)", flags); if (flags & ASSUAN_PIPE_CONNECT_FDPASSING) { #ifdef HAVE_W32_SYSTEM return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED); #else return socketpair_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue); #endif } else return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue, flags); } diff --git a/src/system-posix.c b/src/system-posix.c index 5bdc676..8ca27e6 100644 --- a/src/system-posix.c +++ b/src/system-posix.c @@ -1,356 +1,411 @@ /* system-posix.c - System support functions. Copyright (C) 2009, 2010 Free Software Foundation, Inc. This file is part of Assuan. Assuan is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. Assuan is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include +#ifdef HAVE_STDINT_H +# include +#endif /* Solaris 8 needs sys/types.h before time.h. */ #include #include #include #include +#ifdef HAVE_GETRLIMIT +# include +# include +#endif /*HAVE_GETRLIMIT*/ + #include "assuan-defs.h" #include "debug.h" -#ifdef _POSIX_OPEN_MAX -#define MAX_OPEN_FDS _POSIX_OPEN_MAX -#else -#define MAX_OPEN_FDS 20 -#endif - assuan_fd_t assuan_fdopen (int fd) { return dup (fd); } /* Sleep for the given number of microseconds. Default implementation. */ void __assuan_usleep (assuan_context_t ctx, unsigned int usec) { if (! usec) return; #ifdef HAVE_NANOSLEEP { struct timespec req; struct timespec rem; req.tv_sec = 0; req.tv_nsec = usec * 1000; while (nanosleep (&req, &rem) < 0 && errno == EINTR) req = rem; } #else { struct timeval tv; tv.tv_sec = usec / 1000000; tv.tv_usec = usec % 1000000; select (0, NULL, NULL, NULL, &tv); } #endif } /* Create a pipe with one inheritable end. Easy for Posix. */ int __assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx) { return pipe (fd); } /* Close the given file descriptor, created with _assuan_pipe or one of the socket functions. Easy for Posix. */ int __assuan_close (assuan_context_t ctx, assuan_fd_t fd) { return close (fd); } ssize_t __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) { return read (fd, buffer, size); } ssize_t __assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size) { return write (fd, buffer, size); } int __assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, int flags) { int ret; do ret = recvmsg (fd, msg, flags); while (ret == -1 && errno == EINTR); return ret; } int __assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, int flags) { int ret; do ret = sendmsg (fd, msg, flags); while (ret == -1 && errno == EINTR); return ret; } static int writen (int fd, const char *buffer, size_t length) { while (length) { int nwritten = write (fd, buffer, length); if (nwritten < 0) { if (errno == EINTR) continue; return -1; /* write error */ } length -= nwritten; buffer += nwritten; } return 0; /* okay */ } +/* Return the maximum number of currently allowed open file + * descriptors. */ +static int +get_max_fds (void) +{ + int max_fds = -1; + +#ifdef HAVE_GETRLIMIT + struct rlimit rl; + +# ifdef RLIMIT_NOFILE + if (!getrlimit (RLIMIT_NOFILE, &rl)) + max_fds = rl.rlim_max; +# endif + +# ifdef RLIMIT_OFILE + if (max_fds == -1 && !getrlimit (RLIMIT_OFILE, &rl)) + max_fds = rl.rlim_max; + +# endif +#endif /*HAVE_GETRLIMIT*/ + +#ifdef _SC_OPEN_MAX + if (max_fds == -1) + { + long int scres = sysconf (_SC_OPEN_MAX); + if (scres >= 0) + max_fds = scres; + } +#endif + +#ifdef _POSIX_OPEN_MAX + if (max_fds == -1) + max_fds = _POSIX_OPEN_MAX; +#endif + +#ifdef OPEN_MAX + if (max_fds == -1) + max_fds = OPEN_MAX; +#endif + + if (max_fds == -1) + max_fds = 256; /* Arbitrary limit. */ + + /* AIX returns INT32_MAX instead of a proper value. We assume that + this is always an error and use a more reasonable limit. */ +#ifdef INT32_MAX + if (max_fds == INT32_MAX) + max_fds = 256; +#endif + + return max_fds; +} + + int __assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name, const char **argv, assuan_fd_t fd_in, assuan_fd_t fd_out, assuan_fd_t *fd_child_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue, unsigned int flags) { int pid; pid = fork (); if (pid < 0) return -1; if (pid == 0) { /* Child process (server side). */ int i; int n; char errbuf[512]; int *fdp; int fdnul; if (atfork) atfork (atforkvalue, 0); fdnul = open ("/dev/null", O_WRONLY); if (fdnul == -1) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, "can't open `/dev/null': %s", strerror (errno)); _exit (4); } /* Dup handles to stdin/stdout. */ if (fd_out != STDOUT_FILENO) { if (dup2 (fd_out == ASSUAN_INVALID_FD ? fdnul : fd_out, STDOUT_FILENO) == -1) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, "dup2 failed in child: %s", strerror (errno)); _exit (4); } } if (fd_in != STDIN_FILENO) { if (dup2 (fd_in == ASSUAN_INVALID_FD ? fdnul : fd_in, STDIN_FILENO) == -1) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx, "dup2 failed in child: %s", strerror (errno)); _exit (4); } } /* Dup stderr to /dev/null unless it is in the list of FDs to be passed to the child. */ fdp = fd_child_list; if (fdp) { for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++) ; } if (!fdp || *fdp == -1) { if (dup2 (fdnul, STDERR_FILENO) == -1) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx, "dup2(dev/null, 2) failed: %s", strerror (errno)); _exit (4); } } close (fdnul); /* Close all files which will not be duped and are not in the fd_child_list. */ - n = sysconf (_SC_OPEN_MAX); - if (n < 0) - n = MAX_OPEN_FDS; + n = get_max_fds (); for (i = 0; i < n; i++) { if (i == STDIN_FILENO || i == STDOUT_FILENO || i == STDERR_FILENO) continue; fdp = fd_child_list; if (fdp) { while (*fdp != -1 && *fdp != i) fdp++; } if (!(fdp && *fdp != -1)) close (i); } gpg_err_set_errno (0); if (! name) { /* No name and no args given, thus we don't do an exec but continue the forked process. */ *argv = "server"; /* FIXME: Cleanup. */ return 0; } execv (name, (char *const *) argv); /* oops - use the pipe to tell the parent about it */ snprintf (errbuf, sizeof(errbuf)-1, "ERR %d can't exec `%s': %.50s\n", _assuan_error (ctx, GPG_ERR_ASS_SERVER_START), name, strerror (errno)); errbuf[sizeof(errbuf)-1] = 0; writen (1, errbuf, strlen (errbuf)); _exit (4); } if (! name) *argv = "client"; *r_pid = pid; return 0; } /* FIXME: Add some sort of waitpid function that covers GPGME and gpg-agent's use of assuan. */ pid_t __assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait, int *status, int options) { /* We can't just release the PID, a waitpid is mandatory. But NOWAIT in POSIX systems just means the caller already did the waitpid for this child. */ if (! nowait) return waitpid (pid, NULL, 0); return 0; } int __assuan_socketpair (assuan_context_t ctx, int namespace, int style, int protocol, assuan_fd_t filedes[2]) { return socketpair (namespace, style, protocol, filedes); } int __assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol) { return socket (namespace, style, protocol); } int __assuan_connect (assuan_context_t ctx, int sock, struct sockaddr *addr, socklen_t length) { return connect (sock, addr, length); } /* The default system hooks for assuan contexts. */ struct assuan_system_hooks _assuan_system_hooks = { ASSUAN_SYSTEM_HOOKS_VERSION, __assuan_usleep, __assuan_pipe, __assuan_close, __assuan_read, __assuan_write, __assuan_recvmsg, __assuan_sendmsg, __assuan_spawn, __assuan_waitpid, __assuan_socketpair, __assuan_socket, __assuan_connect }; diff --git a/src/system.c b/src/system.c index 1fca056..ddb99fb 100644 --- a/src/system.c +++ b/src/system.c @@ -1,420 +1,414 @@ /* system.c - System support functions. Copyright (C) 2009 Free Software Foundation, Inc. This file is part of Assuan. Assuan is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. Assuan is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #ifdef HAVE_SYS_TYPES_H /* Solaris 8 needs sys/types.h before time.h. */ # include #endif #include #ifdef HAVE_FCNTL_H #include #endif #include "assuan-defs.h" #include "debug.h" -#ifdef _POSIX_OPEN_MAX -#define MAX_OPEN_FDS _POSIX_OPEN_MAX -#else -#define MAX_OPEN_FDS 20 -#endif - #define DEBUG_SYSIO 0 /* Manage memory specific to a context. */ void * _assuan_malloc (assuan_context_t ctx, size_t cnt) { return ctx->malloc_hooks.malloc (cnt); } void * _assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt) { return ctx->malloc_hooks.realloc (ptr, cnt); } void * _assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize) { void *ptr; size_t nbytes; - + nbytes = cnt * elsize; /* Check for overflow. */ - if (elsize && nbytes / elsize != cnt) + if (elsize && nbytes / elsize != cnt) { gpg_err_set_errno (ENOMEM); return NULL; } ptr = ctx->malloc_hooks.malloc (nbytes); if (ptr) memset (ptr, 0, nbytes); return ptr; } void _assuan_free (assuan_context_t ctx, void *ptr) { if (ptr) ctx->malloc_hooks.free (ptr); } /* Release the memory at PTR using the allocation handler of the context CTX. This is a convenience function. */ void assuan_free (assuan_context_t ctx, void *ptr) { _assuan_free (ctx, ptr); } /* Copy the system hooks struct, paying attention to version differences. SRC is usually from the user, DST MUST be from the library. */ void _assuan_system_hooks_copy (assuan_system_hooks_t dst, assuan_system_hooks_t src) { /* Reset the defaults. */ if (dst != &_assuan_system_hooks) memcpy (dst, &_assuan_system_hooks, sizeof (*dst)); - + dst->version = ASSUAN_SYSTEM_HOOKS_VERSION; if (src->version >= 1) { dst->usleep = src->usleep; dst->pipe = src->pipe; dst->close = src->close; dst->read = src->read; dst->write = src->write; dst->sendmsg = src->sendmsg; dst->recvmsg = src->recvmsg; dst->spawn = src->spawn; dst->waitpid = src->waitpid; dst->socketpair = src->socketpair; } if (src->version >= 2) { dst->socket = src->socket; dst->connect = src->connect; } if (src->version > 2) /* FIXME. Application uses newer version of the library. What to do? */ ; } /* Sleep for the given number of microseconds. */ void _assuan_usleep (assuan_context_t ctx, unsigned int usec) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_usleep", ctx, "usec=%u", usec); (ctx->system.usleep) (ctx, usec); } /* Create a pipe with one inheritable end. */ int _assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx) { int err; TRACE_BEG2 (ctx, ASSUAN_LOG_SYSIO, "_assuan_pipe", ctx, "inherit_idx=%i (Assuan uses it for %s)", inherit_idx, inherit_idx ? "reading" : "writing"); err = (ctx->system.pipe) (ctx, fd, inherit_idx); if (err) return TRACE_SYSRES (err); - return TRACE_SUC2 ("read=0x%x, write=0x%x", fd[0], fd[1]); + return TRACE_SUC2 ("read=0x%x, write=0x%x", fd[0], fd[1]); } /* Close the given file descriptor, created with _assuan_pipe or one of the socket functions. */ int _assuan_close (assuan_context_t ctx, assuan_fd_t fd) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close", ctx, "fd=0x%x", fd); return (ctx->system.close) (ctx, fd); } /* Same as assuan_close but used for the inheritable end of a pipe. */ int _assuan_close_inheritable (assuan_context_t ctx, assuan_fd_t fd) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close_inheritable", ctx, "fd=0x%x", fd); #ifdef HAVE_W32CE_SYSTEM return 0; /* Nothing to do because it is a rendezvous id. */ #else return (ctx->system.close) (ctx, fd); #endif } ssize_t _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) { #if DEBUG_SYSIO ssize_t res; TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_read", ctx, "fd=0x%x, buffer=%p, size=%i", fd, buffer, size); res = (ctx->system.read) (ctx, fd, buffer, size); return TRACE_SYSRES (res); #else return (ctx->system.read) (ctx, fd, buffer, size); #endif } ssize_t _assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size) { #if DEBUG_SYSIO ssize_t res; TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_write", ctx, "fd=0x%x, buffer=%p, size=%i", fd, buffer, size); res = (ctx->system.write) (ctx, fd, buffer, size); return TRACE_SYSRES (res); #else return (ctx->system.write) (ctx, fd, buffer, size); #endif } int _assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, int flags) { #if DEBUG_SYSIO ssize_t res; TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_recvmsg", ctx, "fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags); res = (ctx->system.recvmsg) (ctx, fd, msg, flags); if (res > 0) { struct cmsghdr *cmptr; TRACE_LOG2 ("msg->msg_iov[0] = { iov_base=%p, iov_len=%i }", msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len); TRACE_LOGBUF (msg->msg_iov[0].iov_base, res); cmptr = CMSG_FIRSTHDR (msg); if (cmptr) { void *data = CMSG_DATA (cmptr); TRACE_LOG5 ("cmsg_len=0x%x (0x%x data), cmsg_level=0x%x, " "cmsg_type=0x%x, first data int=0x%x", cmptr->cmsg_len, cmptr->cmsg_len - (((char *)data) - ((char *)cmptr)), cmptr->cmsg_level, cmptr->cmsg_type, *(int *)data); } - } + } return TRACE_SYSRES (res); #else return (ctx->system.recvmsg) (ctx, fd, msg, flags); #endif } int _assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, int flags) { #if DEBUG_SYSIO ssize_t res; TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_sendmsg", ctx, "fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags); { struct cmsghdr *cmptr; TRACE_LOG2 ("msg->iov[0] = { iov_base=%p, iov_len=%i }", msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len); TRACE_LOGBUF (msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len); - + cmptr = CMSG_FIRSTHDR (msg); if (cmptr) { void *data = CMSG_DATA (cmptr); TRACE_LOG5 ("cmsg_len=0x%x (0x%x data), cmsg_level=0x%x, " "cmsg_type=0x%x, first data int=0x%x", cmptr->cmsg_len, cmptr->cmsg_len - (((char *)data) - ((char *)cmptr)), cmptr->cmsg_level, cmptr->cmsg_type, *(int *)data); } } res = (ctx->system.sendmsg) (ctx, fd, msg, flags); return TRACE_SYSRES (res); #else return (ctx->system.sendmsg) (ctx, fd, msg, flags); #endif } /* Create a new process from NAME and ARGV. Provide FD_IN and FD_OUT as stdin and stdout. Inherit the ASSUAN_INVALID_FD-terminated FD_CHILD_LIST as given (no remapping), which must be inheritable. On Unix, call ATFORK with ATFORKVALUE after fork and before exec. */ int _assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name, const char **argv, assuan_fd_t fd_in, assuan_fd_t fd_out, assuan_fd_t *fd_child_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue, unsigned int flags) { int res; int i; TRACE_BEG6 (ctx, ASSUAN_LOG_CTX, "_assuan_spawn", ctx, "name=%s,fd_in=0x%x,fd_out=0x%x," "atfork=%p,atforkvalue=%p,flags=%i", name ? name : "(null)", fd_in, fd_out, atfork, atforkvalue, flags); if (name) { i = 0; while (argv[i]) { TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]); i++; } } i = 0; if (fd_child_list) { while (fd_child_list[i] != ASSUAN_INVALID_FD) { TRACE_LOG2 ("fd_child_list[%2i] = 0x%x", i, fd_child_list[i]); i++; } } res = (ctx->system.spawn) (ctx, r_pid, name, argv, fd_in, fd_out, fd_child_list, atfork, atforkvalue, flags); if (name) { TRACE_LOG1 ("pid = 0x%x", *r_pid); } else { TRACE_LOG2 ("pid = 0x%x (%s)", *r_pid, *argv); } return TRACE_SYSERR (res); } /* FIXME: Add some sort of waitpid function that covers GPGME and gpg-agent's use of assuan. */ -pid_t +pid_t _assuan_waitpid (assuan_context_t ctx, pid_t pid, int action, int *status, int options) { #if DEBUG_SYSIO ssize_t res; TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_waitpid", ctx, "pid=%i, action=%i, status=%p, options=%i", pid, action, status, options); res = (ctx->system.waitpid) (ctx, pid, action, status, options); return TRACE_SYSRES (res); #else return (ctx->system.waitpid) (ctx, pid, action, status, options); #endif } int _assuan_socketpair (assuan_context_t ctx, int namespace, int style, int protocol, assuan_fd_t filedes[2]) { int res; TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socketpair", ctx, "namespace=%i,style=%i,protocol=%i,filedes=%p", namespace, style, protocol, filedes); - + res = (ctx->system.socketpair) (ctx, namespace, style, protocol, filedes); if (res == 0) TRACE_LOG2 ("filedes = { 0x%x, 0x%x }", filedes[0], filedes[1]); return TRACE_SYSERR (res); } int _assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol) { int res; TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socket", ctx, "namespace=%i,style=%i,protocol=%i", namespace, style, protocol); - + res = (ctx->system.socket) (ctx, namespace, style, protocol); return TRACE_SYSRES (res); } int _assuan_connect (assuan_context_t ctx, int sock, struct sockaddr *addr, socklen_t length) { int res; TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_connect", ctx, "socket=%i,addr=%p,length=%i", sock, addr, length); - + res = (ctx->system.connect) (ctx, sock, addr, length); return TRACE_SYSRES (res); }