Commit 21dd7593 authored by Kurt Zeilenga's avatar Kurt Zeilenga
Browse files

surrogate parent fix from Hallvard

parent f332bba5
......@@ -29,7 +29,7 @@ shell_back_abandon(
Operation *o;
/* no abandon command defined - just kill the process handling it */
if ( IS_NULLCMD( si->si_abandon ) ) {
if ( si->si_abandon == NULL ) {
ldap_pvt_thread_mutex_lock( &conn->c_mutex );
pid = -1;
LDAP_STAILQ_FOREACH( o, &conn->c_ops, o_next ) {
......
......@@ -28,7 +28,7 @@ shell_back_add(
FILE *rfp, *wfp;
int len;
if ( IS_NULLCMD( si->si_add ) ) {
if ( si->si_add == NULL ) {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"add not implemented", NULL, NULL );
return( -1 );
......
......@@ -33,7 +33,7 @@ shell_back_bind(
FILE *rfp, *wfp;
int rc;
if ( IS_NULLCMD( si->si_bind ) ) {
if ( si->si_bind == NULL ) {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"bind not implemented", NULL, NULL );
return( -1 );
......
......@@ -30,7 +30,7 @@ shell_back_compare(
Entry e;
FILE *rfp, *wfp;
if ( IS_NULLCMD( si->si_compare ) ) {
if ( si->si_compare == NULL ) {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"compare not implemented", NULL, NULL );
return( -1 );
......
......@@ -15,28 +15,6 @@
#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,
......@@ -62,7 +40,7 @@ shell_back_db_config(
fname, lineno );
return( 1 );
}
si->si_bind = MAKE_CMD_INFO( &argv[1] );
si->si_bind = ldap_charray_dup( &argv[1] );
/* command + args to exec for unbinds */
} else if ( strcasecmp( argv[0], "unbind" ) == 0 ) {
......@@ -72,7 +50,7 @@ shell_back_db_config(
fname, lineno );
return( 1 );
}
si->si_unbind = MAKE_CMD_INFO( &argv[1] );
si->si_unbind = ldap_charray_dup( &argv[1] );
/* command + args to exec for searches */
} else if ( strcasecmp( argv[0], "search" ) == 0 ) {
......@@ -82,7 +60,7 @@ shell_back_db_config(
fname, lineno );
return( 1 );
}
si->si_search = MAKE_CMD_INFO( &argv[1] );
si->si_search = ldap_charray_dup( &argv[1] );
/* command + args to exec for compares */
} else if ( strcasecmp( argv[0], "compare" ) == 0 ) {
......@@ -92,7 +70,7 @@ shell_back_db_config(
fname, lineno );
return( 1 );
}
si->si_compare = MAKE_CMD_INFO( &argv[1] );
si->si_compare = ldap_charray_dup( &argv[1] );
/* command + args to exec for modifies */
} else if ( strcasecmp( argv[0], "modify" ) == 0 ) {
......@@ -102,7 +80,7 @@ shell_back_db_config(
fname, lineno );
return( 1 );
}
si->si_modify = MAKE_CMD_INFO( &argv[1] );
si->si_modify = ldap_charray_dup( &argv[1] );
/* command + args to exec for modrdn */
} else if ( strcasecmp( argv[0], "modrdn" ) == 0 ) {
......@@ -112,7 +90,7 @@ shell_back_db_config(
fname, lineno );
return( 1 );
}
si->si_modrdn = MAKE_CMD_INFO( &argv[1] );
si->si_modrdn = ldap_charray_dup( &argv[1] );
/* command + args to exec for add */
} else if ( strcasecmp( argv[0], "add" ) == 0 ) {
......@@ -122,7 +100,7 @@ shell_back_db_config(
fname, lineno );
return( 1 );
}
si->si_add = MAKE_CMD_INFO( &argv[1] );
si->si_add = ldap_charray_dup( &argv[1] );
/* command + args to exec for delete */
} else if ( strcasecmp( argv[0], "delete" ) == 0 ) {
......@@ -132,7 +110,7 @@ shell_back_db_config(
fname, lineno );
return( 1 );
}
si->si_delete = MAKE_CMD_INFO( &argv[1] );
si->si_delete = ldap_charray_dup( &argv[1] );
/* command + args to exec for abandon */
} else if ( strcasecmp( argv[0], "abandon" ) == 0 ) {
......@@ -142,7 +120,7 @@ shell_back_db_config(
fname, lineno );
return( 1 );
}
si->si_abandon = MAKE_CMD_INFO( &argv[1] );
si->si_abandon = ldap_charray_dup( &argv[1] );
/* anything else */
} else {
......
......@@ -29,7 +29,7 @@ shell_back_delete(
Entry e;
FILE *rfp, *wfp;
if ( IS_NULLCMD( si->si_delete ) ) {
if ( si->si_delete == NULL ) {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"delete not implemented", NULL, NULL );
return( -1 );
......
......@@ -17,222 +17,9 @@
#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;
# 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 */
pid_t
forkandexec(
Cmd_info args,
char **args,
FILE **rfp,
FILE **wfp
)
......@@ -253,70 +40,6 @@ forkandexec(
* parent *rfp <- c2p[0] | c2p[1] <- stdout child
*/
#ifdef SHELL_SURROGATE_PARENT
{
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;
# endif
/* clear msghdr */
memset( &msg, 0, sizeof msg );
# ifdef CMSG_SPACE
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;
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();
......@@ -353,8 +76,6 @@ forkandexec(
return( -1 );
}
#endif /* SHELL_SURROGATE_PARENT */
/* parent */
if ( (*rfp = fdopen( c2p[0], "r" )) == NULL || (*wfp = fdopen( p2c[1],
"w" )) == NULL ) {
......
......@@ -10,7 +10,6 @@
#include <stdio.h>
#include <ac/socket.h>
#include <ac/unistd.h>
#include "slap.h"
#include "shell.h"
......@@ -38,7 +37,7 @@ shell_back_initialize(
bi->bi_open = 0;
bi->bi_config = 0;
bi->bi_close = 0;
bi->bi_destroy = shell_back_destroy;
bi->bi_destroy = 0;
bi->bi_db_init = shell_back_db_init;
bi->bi_db_config = shell_back_db_config;
......@@ -65,32 +64,6 @@ 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;
}
......@@ -101,11 +74,6 @@ 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;
......
......@@ -32,7 +32,7 @@ shell_back_modify(
FILE *rfp, *wfp;
int i;
if ( IS_NULLCMD( si->si_modify ) ) {
if ( si->si_modify == NULL ) {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"modify not implemented", NULL, NULL );
return( -1 );
......
......@@ -47,7 +47,7 @@ shell_back_modrdn(
Entry e;
FILE *rfp, *wfp;
if ( IS_NULLCMD( si->si_modrdn ) ) {
if ( si->si_modrdn == NULL ) {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"modrdn not implemented", NULL, NULL );
return( -1 );
......
......@@ -36,7 +36,7 @@ shell_back_search(
FILE *rfp, *wfp;
AttributeName *an;
if ( IS_NULLCMD( si->si_search ) ) {
if ( si->si_search == NULL ) {
send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, NULL,
"search not implemented", NULL, NULL );
return( -1 );
......
......@@ -12,41 +12,16 @@
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) ldap_charray_dup( args )
#define IS_NULLCMD(cmd) ((cmd) == NULL)
#endif /* SHELL_SURROGATE_PARENT */
struct shellinfo {
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 */
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 */
};
struct slap_backend_db;
......@@ -54,7 +29,7 @@ struct slap_conn;
struct slap_op;
extern pid_t forkandexec LDAP_P((
Cmd_info args,
char **args,