-#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;
-# endif
-
- /* clear msghdr */
- memset( &msg, 0, sizeof msg );
-
-# ifdef CMSG_SPACE
- 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;
-
- 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 */
-