]> git.sur5r.net Git - openldap/commitdiff
Patch: Implement surrogate parent for back-shell (ITS#1815)
authorKurt Zeilenga <kurt@openldap.org>
Wed, 15 May 2002 06:18:14 +0000 (06:18 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Wed, 15 May 2002 06:18:14 +0000 (06:18 +0000)
================
Written by Hallvard B. Furuseth and placed into the public domain.
This software is not subject to any license of the University of Oslo.
================

A surrogate parent is supposed to keep back-shell children from
deadlocking due to resources locked by a threading parent.

Implementation note: The surrogate parent closes all unused file
descriptors, so it logs errors to stderr instead of via Debug() and
uses relloc() instead of ch_realloc().

Also close a file descriptor leak if fork() fails in fork.c.

Hallvard B. Furuseth <h.b.furuseth@usit.uio.no>, May 2002.

17 files changed:
configure
configure.in
include/portable.h.in
include/portable.nt
servers/slapd/back-shell/abandon.c
servers/slapd/back-shell/add.c
servers/slapd/back-shell/bind.c
servers/slapd/back-shell/compare.c
servers/slapd/back-shell/config.c
servers/slapd/back-shell/delete.c
servers/slapd/back-shell/fork.c
servers/slapd/back-shell/init.c
servers/slapd/back-shell/modify.c
servers/slapd/back-shell/modrdn.c
servers/slapd/back-shell/search.c
servers/slapd/back-shell/shell.h
servers/slapd/back-shell/unbind.c

index 60fddea76e52cd338048d3f16bfd94df7a10aa9c..e7dd17ebd4d9bd0917f9575c9ee79d97da186ad0 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # $OpenLDAP$
-# from OpenLDAP: pkg/ldap/configure.in,v 1.417 2002/05/13 16:48:37 kurt Exp  
+# from OpenLDAP: pkg/ldap/configure.in,v 1.418 2002/05/13 18:16:47 kurt Exp  
 
 # Copyright 1998-2002 The OpenLDAP Foundation.  All Rights Reserved.
 # 
@@ -19622,7 +19622,7 @@ else
 #if SASL_VERSION_MAJOR == 1  && SASL_VERSION_MINOR >= 5
        char *__sasl_compat = "1.5.x okay";
 #elif SASL_VERSION_MAJOR == 2  && SASL_VERSION_MINOR > 1
-       __sasl_compat "2.2+ or better okay";
+       __sasl_compat "2.2+ or better okay (we guess)";
 #elif SASL_VERSION_MAJOR == 2  && SASL_VERSION_MINOR == 1 \
        && SASL_VERSION_STEP >=3
        __sasl_compat = "2.1.3+ or better okay";
@@ -21790,6 +21790,7 @@ for ac_func in \
        read                    \
        recv                    \
        recvfrom                \
+       recvmsg                 \
        setpwfile               \
        setgid                  \
        setegid                 \
@@ -21818,12 +21819,12 @@ for ac_func in \
 
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:21822: checking for $ac_func" >&5
+echo "configure:21823: checking for $ac_func" >&5
 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 21827 "configure"
+#line 21828 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -21847,7 +21848,7 @@ f = $ac_func;
 
 ; return 0; }
 EOF
-if { (eval echo configure:21851: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:21852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -21875,12 +21876,12 @@ done
 for ac_func in getopt
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:21879: checking for $ac_func" >&5
+echo "configure:21880: checking for $ac_func" >&5
 if eval "test \"\${ac_cv_func_$ac_func+set}\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 21884 "configure"
+#line 21885 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -21904,7 +21905,7 @@ f = $ac_func;
 
 ; return 0; }
 EOF
-if { (eval echo configure:21908: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:21909: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
 
 # Check Configuration
 echo $ac_n "checking declaration of sys_errlist""... $ac_c" 1>&6
-echo "configure:21941: checking declaration of sys_errlist" >&5
+echo "configure:21942: checking declaration of sys_errlist" >&5
 if eval "test \"\${ol_cv_dcl_sys_errlist+set}\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   
        cat > conftest.$ac_ext <<EOF
-#line 21947 "configure"
+#line 21948 "configure"
 #include "confdefs.h"
 
 #include <stdio.h>
@@ -21956,7 +21957,7 @@ int main() {
 char *c = (char *) *sys_errlist
 ; return 0; }
 EOF
-if { (eval echo configure:21960: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:21961: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ol_cv_dcl_sys_errlist=yes
        ol_cv_have_sys_errlist=yes
@@ -21979,20 +21980,20 @@ EOF
 
 
        echo $ac_n "checking existence of sys_errlist""... $ac_c" 1>&6
-echo "configure:21983: checking existence of sys_errlist" >&5
+echo "configure:21984: checking existence of sys_errlist" >&5
 if eval "test \"\${ol_cv_have_sys_errlist+set}\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   
                cat > conftest.$ac_ext <<EOF
-#line 21989 "configure"
+#line 21990 "configure"
 #include "confdefs.h"
 #include <errno.h>
 int main() {
 char *c = (char *) *sys_errlist
 ; return 0; }
 EOF
-if { (eval echo configure:21996: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:21997: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ol_cv_have_sys_errlist=yes
 else
index c5c7003192b6343231b352a20aa437afa88e2b9d..1b37a051c49628c55a0772ac9bf2e34075fdc7d9 100644 (file)
@@ -2426,6 +2426,7 @@ AC_CHECK_FUNCS(           \
        read                    \
        recv                    \
        recvfrom                \
+       recvmsg                 \
        setpwfile               \
        setgid                  \
        setegid                 \
index 2e2d7a9c7bd66a670cc02a2c6db2c82d801c5e4b..45964ed8ba88805ad0c24c2ec20be1489c06ac4a 100644 (file)
 /* Define if you have the recvfrom function.  */
 #undef HAVE_RECVFROM
 
+/* Define if you have the recvmsg function.  */
+#undef HAVE_RECVMSG
+
 /* Define if you have the sched_yield function.  */
 #undef HAVE_SCHED_YIELD
 
index 921b3dd20e657737505a4531217c8f11b0be0765..8715d81a97f66f2b8be15467c35b90b0f8b6c8af 100644 (file)
 /* Define if you have the recvfrom function.  */
 /* #undef HAVE_RECVFROM */
 
+/* Define if you have the recvmsg function.  */
+/* #undef HAVE_RECVMSG */
+
 /* Define if you have the sched_yield function.  */
 /* #undef HAVE_SCHED_YIELD */
 
index 1f5f3f092a0114e3374014be55c6d238e8309f2b..cae990af5bd83f4bcfeb3cb6d949dbe6ebdf770a 100644 (file)
@@ -29,7 +29,7 @@ shell_back_abandon(
        Operation               *o;
 
        /* no abandon command defined - just kill the process handling it */
-       if ( si->si_abandon == NULL ) {
+       if ( IS_NULLCMD( si->si_abandon ) ) {
                ldap_pvt_thread_mutex_lock( &conn->c_mutex );
                pid = -1;
                LDAP_STAILQ_FOREACH( o, &conn->c_ops, o_next ) {
index 528d3993e5a799e4e6b5ad5b99abfd50e163805c..134416866b6cdeb547e72fd76b857708dfb3bb20 100644 (file)
@@ -27,7 +27,7 @@ shell_back_add(
        FILE                    *rfp, *wfp;
        int                     len;
 
-       if ( si->si_add == NULL ) {
+       if ( IS_NULLCMD( si->si_add ) ) {
                send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
                    "add not implemented", NULL, NULL );
                return( -1 );
index 024c41f6635af6a60590e482283fbf969d1ab377..fe36059215e8317cc303aa4fcfa248a03a3bfcad 100644 (file)
@@ -31,7 +31,7 @@ shell_back_bind(
        FILE                    *rfp, *wfp;
        int                     rc;
 
-       if ( si->si_bind == NULL ) {
+       if ( IS_NULLCMD( si->si_bind ) ) {
                send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
                    "bind not implemented", NULL, NULL );
                return( -1 );
index 9ef16c5bc31e9f38ae296f12839b674f45d5ee11..b5ef2d24eb83fe2719344162f97d7aa1cc4e9c32 100644 (file)
@@ -28,7 +28,7 @@ shell_back_compare(
        struct shellinfo        *si = (struct shellinfo *) be->be_private;
        FILE                    *rfp, *wfp;
 
-       if ( si->si_compare == NULL ) {
+       if ( IS_NULLCMD( si->si_compare ) ) {
                send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
                    "compare not implemented", NULL, NULL );
                return( -1 );
index df730a9bd85503cceb85badb0e9a99c8544cd8b0..7c1e14e7ff8b1029eb4198c75c321fb89e928303 100644 (file)
 #include "slap.h"
 #include "shell.h"
 
+#ifdef SHELL_SURROGATE_PARENT
+
+static struct berval make_cmd_info(
+       char **args
+)
+{
+       struct berval ret = { 0, 0 };
+       int i;
+       ber_len_t offset;
+       for( i = 0; args[i] != NULL; i++ )
+               ret.bv_len += strlen( args[i] ) + 1;
+       ret.bv_val = ch_malloc( ret.bv_len );
+       offset = 0;
+       for( i = 0; args[i] != NULL; i++ ) {
+               strcpy( ret.bv_val + offset, args[i] );
+               offset += strlen( args[i] ) + 1;
+       }
+       return ret;
+}
+
+#endif /* SHELL_SURROGATE_PARENT */
+
 int
 shell_back_db_config(
     BackendDB  *be,
@@ -40,7 +62,7 @@ shell_back_db_config(
                            fname, lineno );
                        return( 1 );
                }
-               si->si_bind = charray_dup( &argv[1] );
+               si->si_bind = MAKE_CMD_INFO( &argv[1] );
 
        /* command + args to exec for unbinds */
        } else if ( strcasecmp( argv[0], "unbind" ) == 0 ) {
@@ -50,7 +72,7 @@ shell_back_db_config(
                            fname, lineno );
                        return( 1 );
                }
-               si->si_unbind = charray_dup( &argv[1] );
+               si->si_unbind = MAKE_CMD_INFO( &argv[1] );
 
        /* command + args to exec for searches */
        } else if ( strcasecmp( argv[0], "search" ) == 0 ) {
@@ -60,7 +82,7 @@ shell_back_db_config(
                            fname, lineno );
                        return( 1 );
                }
-               si->si_search = charray_dup( &argv[1] );
+               si->si_search = MAKE_CMD_INFO( &argv[1] );
 
        /* command + args to exec for compares */
        } else if ( strcasecmp( argv[0], "compare" ) == 0 ) {
@@ -70,7 +92,7 @@ shell_back_db_config(
                            fname, lineno );
                        return( 1 );
                }
-               si->si_compare = charray_dup( &argv[1] );
+               si->si_compare = MAKE_CMD_INFO( &argv[1] );
 
        /* command + args to exec for modifies */
        } else if ( strcasecmp( argv[0], "modify" ) == 0 ) {
@@ -80,7 +102,7 @@ shell_back_db_config(
                            fname, lineno );
                        return( 1 );
                }
-               si->si_modify = charray_dup( &argv[1] );
+               si->si_modify = MAKE_CMD_INFO( &argv[1] );
 
        /* command + args to exec for modrdn */
        } else if ( strcasecmp( argv[0], "modrdn" ) == 0 ) {
@@ -90,7 +112,7 @@ shell_back_db_config(
                            fname, lineno );
                        return( 1 );
                }
-               si->si_modrdn = charray_dup( &argv[1] );
+               si->si_modrdn = MAKE_CMD_INFO( &argv[1] );
 
        /* command + args to exec for add */
        } else if ( strcasecmp( argv[0], "add" ) == 0 ) {
@@ -100,7 +122,7 @@ shell_back_db_config(
                            fname, lineno );
                        return( 1 );
                }
-               si->si_add = charray_dup( &argv[1] );
+               si->si_add = MAKE_CMD_INFO( &argv[1] );
 
        /* command + args to exec for delete */
        } else if ( strcasecmp( argv[0], "delete" ) == 0 ) {
@@ -110,7 +132,7 @@ shell_back_db_config(
                            fname, lineno );
                        return( 1 );
                }
-               si->si_delete = charray_dup( &argv[1] );
+               si->si_delete = MAKE_CMD_INFO( &argv[1] );
 
        /* command + args to exec for abandon */
        } else if ( strcasecmp( argv[0], "abandon" ) == 0 ) {
@@ -120,7 +142,7 @@ shell_back_db_config(
                            fname, lineno );
                        return( 1 );
                }
-               si->si_abandon = charray_dup( &argv[1] );
+               si->si_abandon = MAKE_CMD_INFO( &argv[1] );
 
        /* anything else */
        } else {
index 5902dbeb138f73c15e538e2811754f852bd6c69c..e675f8062e0110289ca75bd66aed1d2f344433d6 100644 (file)
@@ -27,7 +27,7 @@ shell_back_delete(
        struct shellinfo        *si = (struct shellinfo *) be->be_private;
        FILE                    *rfp, *wfp;
 
-       if ( si->si_delete == NULL ) {
+       if ( IS_NULLCMD( si->si_delete ) ) {
                send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
                    "delete not implemented", NULL, NULL );
                return( -1 );
index 5a7bb396c7e5945697c2b29cce089d6a2db2009e..fc1c0768c356f39d9ce2fd8b38409050db2429be 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <stdio.h>
 
+#include <ac/errno.h>
 #include <ac/string.h>
 #include <ac/socket.h>
 #include <ac/unistd.h>
 #include "slap.h"
 #include "shell.h"
 
+#ifdef SHELL_SURROGATE_PARENT
+
+#include <sys/uio.h>
+
+/* Use several socketpairs to the surrogate parent, because   *
+ * a single communication channel to it could be a bottleneck */
+ldap_pvt_thread_mutex_t shell_surrogate_fd_mutex[2];
+int                     shell_surrogate_fd[2] = { -1, -1 };
+/* Index to shell_surrogate_fd, and its mutex */
+ldap_pvt_thread_mutex_t shell_surrogate_index_mutex;
+static int              shell_surrogate_index = 1;
+
+pid_t                   shell_surrogate_pid = -1;
+
+#define  nread( fd, buf, len ) n_rw( 0, fd, buf, len )
+#define nwrite( fd, buf, len ) n_rw( 1, fd, buf, len )
+
+static int
+n_rw(
+       int do_write,
+       int fd,
+       void *buf,
+       int len
+)
+{
+       int ret = 0, i;
+       while( len ) {
+               for(;;) {
+                       i = (do_write
+                            ? write( fd, buf, len )
+                            :  read( fd, buf, len ));
+                       if( i < 0 ) {
+                               if( errno == EINTR )
+                                       continue;
+                               if( ret == 0 )
+                                       ret = -1;
+                       }
+                       break;
+               }
+               if( i <= 0 )
+                       break;
+               ret += i;
+               buf = (char *)buf + i;
+               len -= i;
+       }
+       return ret;
+}
+
+void
+make_surrogate_parent( void )
+{
+       int pair[2][2], io[2], i, j, p, argc;
+       ber_len_t len, buflen, offset;
+       char *buf, **argv;
+       pid_t pid;
+
+       if( socketpair( AF_LOCAL, SOCK_STREAM, 0, pair[0] ) < 0 ||
+           socketpair( AF_LOCAL, SOCK_STREAM, 0, pair[1] ) < 0   ) {
+               Debug( LDAP_DEBUG_ANY, "socketpair failed\n", 0, 0, 0 );
+               exit( EXIT_FAILURE );
+       }
+       fflush( NULL );
+       switch( fork() ) {
+       case -1:
+               Debug( LDAP_DEBUG_ANY, "fork failed\n", 0, 0, 0 );
+               exit( EXIT_FAILURE );
+       case 0:
+               break;
+       default:
+               shell_surrogate_fd[0] = pair[0][0];
+               shell_surrogate_fd[1] = pair[1][0];
+               close( pair[0][1] );
+               close( pair[1][1] );
+               return;
+       }
+
+       /* Close unused file descriptors */
+       for( i = 3, j = 32; j && i < 1024; i++ )
+               if( i != pair[0][1] && i != pair[1][1] && close( i ) < 0 )
+                       --j;
+               else if( j < 32 )
+                       j = 32;
+
+       /* Surrogate parent running */
+
+       buflen = 0;
+       buf = NULL;
+       argc = 0;
+       argv = NULL;
+       p = 0;
+
+       for(;;) {
+               /* Read file descriptors io[] from socket */ 
+               static char dummy;
+               static struct iovec iov = { &dummy, 1 };
+               struct msghdr msg;
+# ifdef CMSG_SPACE
+               union {
+                       struct cmsghdr cm;
+                       char control[CMSG_SPACE(sizeof(io))];
+               } control_un;
+               struct cmsghdr *cmptr;
+               msg.msg_control = control_un.control;
+               msg.msg_controllen = sizeof(control_un.control);
+# else
+               msg.msg_accrights = (caddr_t) io;
+               msg.msg_accrightslen = sizeof(io);
+# endif
+               msg.msg_name = NULL;
+               msg.msg_namelen = 0;
+               msg.msg_iov = &iov;
+               msg.msg_iovlen = 1;
+               msg.msg_flags = 0;
+               switch( recvmsg( pair[p][1], &msg, MSG_WAITALL ) ) {
+               case -1:
+                       if( errno == EINTR )
+                               continue;
+                       _exit( EXIT_FAILURE );
+               case 0:
+                       _exit( EXIT_SUCCESS );
+               }
+# ifdef CMSG_SPACE
+               if( (cmptr = CMSG_FIRSTHDR(&msg)) == NULL   ||
+                   cmptr->cmsg_len != CMSG_LEN(sizeof(io)) ||
+                   cmptr->cmsg_level != SOL_SOCKET         ||
+                   cmptr->cmsg_type != SCM_RIGHTS            ) {
+                       fputs( "bad descriptor message received\n", stderr );
+                       exit( EXIT_FAILURE );
+               }
+               memcpy( io, CMSG_DATA( cmptr ), sizeof(io) );
+# else
+               if( msg.msg_accrightslen != sizeof(io) ) {
+                       fputs( "bad descriptor message received\n", stderr );
+                       exit( EXIT_FAILURE );
+               }
+# endif
+
+               /* Read length of arguments and then arguments from socket */
+               if( nread( pair[p][1], &len, sizeof(len) ) != sizeof(len) ) {
+                       fputs( "bad descriptor message received\n", stderr );
+                       exit( EXIT_FAILURE );
+               }
+               if( buflen < len ) {
+                       buf = realloc( buf, buflen = len );
+                       if( buf == NULL ) {
+                               fputs( "realloc failed\n", stderr );
+                               exit( EXIT_FAILURE );
+                       }
+               }
+               if( nread( pair[p][1], buf, len ) != len ) {
+                       fputs( "bad descriptor message received\n", stderr );
+                       exit( EXIT_FAILURE );
+               }
+               i = 0;
+               offset = 0;
+               while( offset < len ) {
+                       if( i >= argc-1 ) {
+                               argc += i + 10;
+                               argv = realloc( argv, argc * sizeof(*argv) );
+                               if( argv == NULL ) {
+                                       fputs( "realloc failed\n", stderr );
+                                       exit( EXIT_FAILURE );
+                               }
+                       }
+                       argv[i++] = buf + offset;
+                       offset += strlen( buf + offset ) + 1;
+               }
+               argv[i] = NULL;
+
+               /* Run program */
+               pid = fork();
+               switch( pid )
+               {
+               case 0:         /* child */
+                       if( dup2( io[0], 0 ) == -1 || dup2( io[1], 1 ) == -1 ) {
+                               fputs( "dup2 failed\n", stderr );
+                               exit( EXIT_FAILURE );
+                       }
+                       close( io[0] );
+                       close( io[1] );
+                       close( pair[0][1] );
+                       close( pair[1][1] );
+                       execv( argv[0], argv );
+
+                       fputs( "execv failed\n", stderr );
+                       exit( EXIT_FAILURE );
+
+               case -1:        /* trouble */
+                       fputs( "fork failed\n", stderr );
+                       break;
+
+               default:        /* parent */
+                       close( io[0] );
+                       close( io[1] );
+                       break;
+               }
+               if( nwrite( pair[p][1], &pid,
+                           sizeof(pid_t) ) != sizeof(pid_t) )  {
+                       fputs( "could not send pid\n", stderr );
+                       exit( EXIT_FAILURE );
+               }
+               p ^= 1;
+       }
+}
+#endif /* SHELL_SURROGATE_PARENT */
+
 pid_t
 forkandexec(
-    char       **args,
+    Cmd_info  args,
     FILE       **rfp,
     FILE       **wfp
 )
 {
-       int     p2c[2], c2p[2];
+       int     p2c[2] = { -1, -1 }, c2p[2];
        pid_t   pid;
 
        if ( pipe( p2c ) != 0 || pipe( c2p ) != 0 ) {
                Debug( LDAP_DEBUG_ANY, "pipe failed\n", 0, 0, 0 );
+               close( p2c[0] );
+               close( p2c[1] );
                return( -1 );
        }
 
@@ -37,27 +246,89 @@ forkandexec(
         *      parent *rfp <- c2p[0] | c2p[1] <- stdout child
         */
 
-#ifdef HAVE_THR
-       switch ( (pid = fork1()) )
-#else
-       switch ( (pid = fork()) )
-#endif
+#ifdef SHELL_SURROGATE_PARENT
+
        {
-       case 0:         /* child */
+               int io[2] = { p2c[0], c2p[1] }, i, c;
+               static char dummy = '\0';
+               static struct iovec iov = { &dummy, 1 };
+               struct msghdr msg;
+# ifdef CMSG_SPACE
+               union {
+                       struct cmsghdr cm;
+                       char control[CMSG_SPACE(sizeof(io))];
+               } control_un;
+               struct cmsghdr *cmptr;
+               msg.msg_control = control_un.control;
+               msg.msg_controllen = sizeof(control_un.control);
+               cmptr = CMSG_FIRSTHDR(&msg);
+               cmptr->cmsg_len = CMSG_LEN(sizeof(io));
+               cmptr->cmsg_level = SOL_SOCKET;
+               cmptr->cmsg_type = SCM_RIGHTS;
+               memcpy( CMSG_DATA(cmptr), io, sizeof(io) );
+# else
+               msg.msg_accrights = (caddr_t) io;
+               msg.msg_accrightslen = sizeof(io);
+# endif
+               msg.msg_name = NULL;
+               msg.msg_namelen = 0;
+               msg.msg_iov = &iov;
+               msg.msg_iovlen = 1;
+               msg.msg_flags = 0;
+               ldap_pvt_thread_mutex_lock( &shell_surrogate_index_mutex );
+               i = shell_surrogate_index ^= 1;
+               ldap_pvt_thread_mutex_unlock( &shell_surrogate_index_mutex );
+               ldap_pvt_thread_mutex_lock( &shell_surrogate_fd_mutex[i] );
+               c = (sendmsg( shell_surrogate_fd[i], &msg, 0 ) == 1 &&
+                        nwrite( shell_surrogate_fd[i], &args.bv_len,
+                                sizeof(args.bv_len) ) == sizeof(args.bv_len) &&
+                        nwrite( shell_surrogate_fd[i], args.bv_val,
+                                args.bv_len ) == args.bv_len &&
+                        nread( shell_surrogate_fd[i], &pid,
+                               sizeof(pid) ) == sizeof(pid));
+               ldap_pvt_thread_mutex_unlock( &shell_surrogate_fd_mutex[i] );
+               close( p2c[0] );
+               close( c2p[1] );
+               if ( !c ) {
+                       Debug( LDAP_DEBUG_ANY, "process creation failed\n", 0, 0, 0 );
+                       close( p2c[1] );
+                       close( c2p[0] );
+                       close( shell_surrogate_fd[0] );
+                       close( shell_surrogate_fd[1] );
+                       shell_surrogate_fd[0] =
+                               shell_surrogate_fd[1] = -1;
+                       return( -1 );
+               }
+       }
+
+#else /* !SHELL_SURROGATE_PARENT */
+
+       fflush( NULL );
+# ifdef HAVE_THR
+       pid = fork1();
+# else
+       pid = fork();
+# endif
+       if ( pid == 0 ) {               /* child */
                /*
                 * child could deadlock here due to resources locked
                 * by our parent
                 *
-                * If so, configure --without-threads or implement forking
-                * via a surrogate parent.
+                * If so, configure --without-threads.
                 */
-               close( p2c[1] );
-               close( c2p[0] );
                if ( dup2( p2c[0], 0 ) == -1 || dup2( c2p[1], 1 ) == -1 ) {
                        Debug( LDAP_DEBUG_ANY, "dup2 failed\n", 0, 0, 0 );
                        exit( EXIT_FAILURE );
                }
-
+       }
+       close( p2c[0] );
+       close( c2p[1] );
+       if ( pid <= 0 ) {
+               close( p2c[1] );
+               close( c2p[0] );
+       }
+       switch ( pid ) {
+       case 0:
                execv( args[0], args );
 
                Debug( LDAP_DEBUG_ANY, "execv failed\n", 0, 0, 0 );
@@ -66,13 +337,11 @@ forkandexec(
        case -1:        /* trouble */
                Debug( LDAP_DEBUG_ANY, "fork failed\n", 0, 0, 0 );
                return( -1 );
-
-       default:        /* parent */
-               close( p2c[0] );
-               close( c2p[1] );
-               break;
        }
 
+#endif /* SHELL_SURROGATE_PARENT */
+
+       /* parent */
        if ( (*rfp = fdopen( c2p[0], "r" )) == NULL || (*wfp = fdopen( p2c[1],
            "w" )) == NULL ) {
                Debug( LDAP_DEBUG_ANY, "fdopen failed\n", 0, 0, 0 );
index d7add624f552cd0df738ecd4ccb63742ec8c0468..03ab2d18011c49b48b908b2d9c3e6fcaceae87a7 100644 (file)
@@ -10,6 +10,7 @@
 #include <stdio.h>
 
 #include <ac/socket.h>
+#include <ac/unistd.h>
 
 #include "slap.h"
 #include "shell.h"
@@ -37,7 +38,7 @@ shell_back_initialize(
        bi->bi_open = 0;
        bi->bi_config = 0;
        bi->bi_close = 0;
-       bi->bi_destroy = 0;
+       bi->bi_destroy = shell_back_destroy;
 
        bi->bi_db_init = shell_back_db_init;
        bi->bi_db_config = shell_back_db_config;
@@ -64,6 +65,32 @@ shell_back_initialize(
        bi->bi_connection_init = 0;
        bi->bi_connection_destroy = 0;
 
+#ifdef SHELL_SURROGATE_PARENT
+       ldap_pvt_thread_mutex_init( &shell_surrogate_index_mutex );
+       ldap_pvt_thread_mutex_init( &shell_surrogate_fd_mutex[0] );
+       ldap_pvt_thread_mutex_init( &shell_surrogate_fd_mutex[1] );
+#endif
+
+       return 0;
+}
+
+int
+shell_back_destroy(
+       BackendInfo *bi
+)
+{
+#ifdef SHELL_SURROGATE_PARENT
+       ldap_pvt_thread_mutex_destroy( &shell_surrogate_index_mutex );
+       ldap_pvt_thread_mutex_destroy( &shell_surrogate_fd_mutex[0] );
+       ldap_pvt_thread_mutex_destroy( &shell_surrogate_fd_mutex[1] );
+       if ( shell_surrogate_fd[0] >= 0 ) {
+               close( shell_surrogate_fd[0] );
+               close( shell_surrogate_fd[1] );
+       }
+       if ( shell_surrogate_pid >= 0 )
+               kill( shell_surrogate_pid, SIGTERM );
+#endif
+
        return 0;
 }
 
@@ -74,6 +101,11 @@ shell_back_db_init(
 {
        struct shellinfo        *si;
 
+#ifdef SHELL_SURROGATE_PARENT
+       if ( shell_surrogate_fd[0] < 0 )
+               make_surrogate_parent();
+#endif
+
        si = (struct shellinfo *) ch_calloc( 1, sizeof(struct shellinfo) );
 
        be->be_private = si;
index 91d7149eca03354dda942276c916ae4df77407e8..5acddbe994d9173753832b8d301e2905045d048f 100644 (file)
@@ -30,7 +30,7 @@ shell_back_modify(
        FILE                    *rfp, *wfp;
        int                     i;
 
-       if ( si->si_modify == NULL ) {
+       if ( IS_NULLCMD( si->si_modify ) ) {
                send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
                    "modify not implemented", NULL, NULL );
                return( -1 );
index 00dd8a9d6c844ffd5bdb3b93f205fcbc85986684..e2c7d64d5f046b7c921c30179a57b5f38915e3a4 100644 (file)
@@ -45,7 +45,7 @@ shell_back_modrdn(
        struct shellinfo        *si = (struct shellinfo *) be->be_private;
        FILE                    *rfp, *wfp;
 
-       if ( si->si_modrdn == NULL ) {
+       if ( IS_NULLCMD( si->si_modrdn ) ) {
                send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
                    "modrdn not implemented", NULL, NULL );
                return( -1 );
index 6d574524ad07d9833ea0c5405dc5e9fbab246ee8..a1579e20e215e31c5291f1528a96efc7c19a504e 100644 (file)
@@ -33,11 +33,10 @@ shell_back_search(
 )
 {
        struct shellinfo        *si = (struct shellinfo *) be->be_private;
-       int                     i;
        FILE                    *rfp, *wfp;
        AttributeName           *an;
 
-       if ( si->si_search == NULL ) {
+       if ( IS_NULLCMD( si->si_search ) ) {
                send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
                    "search not implemented", NULL, NULL );
                return( -1 );
index 866fd4b2aa01625de817987e2d9581617d290e97..25b7aaf28db2ece77d2fc5446ba5fde579ca07f8 100644 (file)
 
 LDAP_BEGIN_DECL
 
+#if defined(HAVE_RECVMSG) && !defined(NO_THREADS)
+#  define SHELL_SURROGATE_PARENT
+#endif
+
+#ifdef SHELL_SURROGATE_PARENT
+
+extern ldap_pvt_thread_mutex_t shell_surrogate_index_mutex;
+extern ldap_pvt_thread_mutex_t shell_surrogate_fd_mutex[2];
+extern int                     shell_surrogate_fd[2];
+extern pid_t                   shell_surrogate_pid;
+
+typedef struct berval Cmd_info;
+#define MAKE_CMD_INFO(args)  make_cmd_info( args )
+#define IS_NULLCMD(cmd)      ((cmd).bv_val == NULL)
+
+extern void make_surrogate_parent LDAP_P(( void ));
+
+#else /* !SHELL_SURROGATE_PARENT */
+
+typedef char **Cmd_info;
+#define MAKE_CMD_INFO(args)  charray_dup( args )
+#define IS_NULLCMD(cmd)      ((cmd) == NULL)
+
+#endif /* SHELL_SURROGATE_PARENT */
+
 struct shellinfo {
-       char    **si_bind;      /* cmd + args to exec for bind    */
-       char    **si_unbind;    /* cmd + args to exec for unbind  */
-       char    **si_search;    /* cmd + args to exec for search  */
-       char    **si_compare;   /* cmd + args to exec for compare */
-       char    **si_modify;    /* cmd + args to exec for modify  */
-       char    **si_modrdn;    /* cmd + args to exec for modrdn  */
-       char    **si_add;       /* cmd + args to exec for add     */
-       char    **si_delete;    /* cmd + args to exec for delete  */
-       char    **si_abandon;   /* cmd + args to exec for abandon */
+       Cmd_info si_bind;       /* cmd + args to exec for bind    */
+       Cmd_info si_unbind;     /* cmd + args to exec for unbind  */
+       Cmd_info si_search;     /* cmd + args to exec for search  */
+       Cmd_info si_compare;    /* cmd + args to exec for compare */
+       Cmd_info si_modify;     /* cmd + args to exec for modify  */
+       Cmd_info si_modrdn;     /* cmd + args to exec for modrdn  */
+       Cmd_info si_add;        /* cmd + args to exec for add     */
+       Cmd_info si_delete;     /* cmd + args to exec for delete  */
+       Cmd_info si_abandon;    /* cmd + args to exec for abandon */
 };
 
 struct slap_backend_db;
@@ -29,7 +54,7 @@ struct slap_conn;
 struct slap_op;
 
 extern pid_t forkandexec LDAP_P((
-       char **args,
+       Cmd_info args,
        FILE **rfp,
        FILE **wfp));
 
index b7c44c1577b19d37fe47e4d46fac75560ac6b443..a4327f99e2066b2f73b64e6817528140de3aa30e 100644 (file)
@@ -25,7 +25,7 @@ shell_back_unbind(
        struct shellinfo        *si = (struct shellinfo *) be->be_private;
        FILE                    *rfp, *wfp;
 
-       if ( si->si_unbind == NULL ) {
+       if ( IS_NULLCMD( si->si_unbind ) ) {
                return 0;
        }