1/* fork.c - fork and exec a process, connecting stdin/out w/pipes */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 1998-2011 The OpenLDAP Foundation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16/* Portions Copyright (c) 1995 Regents of the University of Michigan.
17 * All rights reserved.
18 *
19 * Redistribution and use in source and binary forms are permitted
20 * provided that this notice is preserved and that due credit is given
21 * to the University of Michigan at Ann Arbor. The name of the University
22 * may not be used to endorse or promote products derived from this
23 * software without specific prior written permission. This software
24 * is provided ``as is'' without express or implied warranty.
25 */
26/* ACKNOWLEDGEMENTS:
27 * This work was originally developed by the University of Michigan
28 * (as part of U-MICH LDAP).
29 */
30
31#include "portable.h"
32
33#include <stdio.h>
34
35#include <ac/errno.h>
36#include <ac/string.h>
37#include <ac/socket.h>
38#include <ac/unistd.h>
39
40#include "slap.h"
41#include "shell.h"
42
43pid_t
44forkandexec(
45    char	**args,
46    FILE	**rfp,
47    FILE	**wfp
48)
49{
50	int	p2c[2] = { -1, -1 }, c2p[2];
51	pid_t	pid;
52
53	if ( pipe( p2c ) != 0 || pipe( c2p ) != 0 ) {
54		Debug( LDAP_DEBUG_ANY, "pipe failed\n", 0, 0, 0 );
55		close( p2c[0] );
56		close( p2c[1] );
57		return( -1 );
58	}
59
60	/*
61	 * what we're trying to set up looks like this:
62	 *	parent *wfp -> p2c[1] | p2c[0] -> stdin child
63	 *	parent *rfp <- c2p[0] | c2p[1] <- stdout child
64	 */
65
66	fflush( NULL );
67# ifdef HAVE_THR
68	pid = fork1();
69# else
70	pid = fork();
71# endif
72	if ( pid == 0 ) {		/* child */
73		/*
74		 * child could deadlock here due to resources locked
75		 * by our parent
76		 *
77		 * If so, configure --without-threads.
78		 */
79		if ( dup2( p2c[0], 0 ) == -1 || dup2( c2p[1], 1 ) == -1 ) {
80			Debug( LDAP_DEBUG_ANY, "dup2 failed\n", 0, 0, 0 );
81			exit( EXIT_FAILURE );
82		}
83	}
84	close( p2c[0] );
85	close( c2p[1] );
86	if ( pid <= 0 ) {
87		close( p2c[1] );
88		close( c2p[0] );
89	}
90	switch ( pid ) {
91	case 0:
92		execv( args[0], args );
93
94		Debug( LDAP_DEBUG_ANY, "execv failed\n", 0, 0, 0 );
95		exit( EXIT_FAILURE );
96
97	case -1:	/* trouble */
98		Debug( LDAP_DEBUG_ANY, "fork failed\n", 0, 0, 0 );
99		return( -1 );
100	}
101
102	/* parent */
103	if ( (*rfp = fdopen( c2p[0], "r" )) == NULL || (*wfp = fdopen( p2c[1],
104	    "w" )) == NULL ) {
105		Debug( LDAP_DEBUG_ANY, "fdopen failed\n", 0, 0, 0 );
106		if ( *rfp ) {
107			fclose( *rfp );
108			*rfp = NULL;
109		} else {
110			close( c2p[0] );
111		}
112		close( p2c[1] );
113
114		return( -1 );
115	}
116
117	return( pid );
118}
119