xref: /netbsd-src/external/bsd/openldap/dist/tests/progs/slapd-modrdn.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: slapd-modrdn.c,v 1.3 2021/08/14 16:15:03 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2021 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Howard Chu, based in part
19  * on other OpenLDAP test tools, for inclusion in OpenLDAP Software.
20  */
21 
22 #include <sys/cdefs.h>
23 __RCSID("$NetBSD: slapd-modrdn.c,v 1.3 2021/08/14 16:15:03 christos Exp $");
24 
25 #include "portable.h"
26 
27 #include <stdio.h>
28 
29 #include "ac/stdlib.h"
30 
31 #include "ac/ctype.h"
32 #include "ac/param.h"
33 #include "ac/socket.h"
34 #include "ac/string.h"
35 #include "ac/unistd.h"
36 #include "ac/wait.h"
37 
38 #include "ldap.h"
39 #include "lutil.h"
40 
41 #include "slapd-common.h"
42 
43 #define LOOPS	100
44 #define RETRIES	0
45 
46 static void
47 do_modrdn( struct tester_conn_args *config,
48 		char *entry, int friendly );
49 
50 static void
usage(char * name,char opt)51 usage( char *name, char opt )
52 {
53 	if ( opt ) {
54 		fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
55 			name, opt );
56 	}
57 
58 	fprintf( stderr, "usage: %s " TESTER_COMMON_HELP
59 		"-e <entry> "
60 		"[-F]\n",
61 		name );
62 	exit( EXIT_FAILURE );
63 }
64 
65 int
main(int argc,char ** argv)66 main( int argc, char **argv )
67 {
68 	int		i;
69 	char		*entry = NULL;
70 	int		friendly = 0;
71 	struct tester_conn_args	*config;
72 
73 	config = tester_init( "slapd-modrdn", TESTER_MODRDN );
74 
75 	while ( ( i = getopt( argc, argv, TESTER_COMMON_OPTS "e:F" ) ) != EOF )
76 	{
77 		switch ( i ) {
78 		case 'F':
79 			friendly++;
80 			break;
81 
82 		case 'i':
83 			/* ignored (!) by now */
84 			break;
85 
86 		case 'e':		/* entry to rename */
87 			entry = optarg;
88 			break;
89 
90 		default:
91 			if ( tester_config_opt( config, i, optarg ) == LDAP_SUCCESS ) {
92 				break;
93 			}
94 			usage( argv[0], i );
95 			break;
96 		}
97 	}
98 
99 	if ( entry == NULL )
100 		usage( argv[0], 0 );
101 
102 	if ( *entry == '\0' ) {
103 
104 		fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
105 				argv[0] );
106 		exit( EXIT_FAILURE );
107 
108 	}
109 
110 	tester_config_finish( config );
111 
112 	for ( i = 0; i < config->outerloops; i++ ) {
113 		do_modrdn( config, entry, friendly );
114 	}
115 
116 	exit( EXIT_SUCCESS );
117 }
118 
119 
120 static void
do_modrdn(struct tester_conn_args * config,char * entry,int friendly)121 do_modrdn( struct tester_conn_args *config,
122 	char *entry, int friendly )
123 {
124 	LDAP	*ld = NULL;
125 	int  	i, do_retry = config->retries;
126 	char	*DNs[2];
127 	char	*rdns[2];
128 	int	rc = LDAP_SUCCESS;
129 	char	*p1, *p2;
130 
131 	DNs[0] = entry;
132 	DNs[1] = strdup( entry );
133 	if ( DNs[1] == NULL ) {
134 		tester_error( "strdup failed" );
135 		exit( EXIT_FAILURE );
136 	}
137 
138 	/* reverse the RDN, make new DN */
139 	p1 = strchr( entry, '=' ) + 1;
140 	p2 = strchr( p1, ',' );
141 
142 	*p2 = '\0';
143 	rdns[1] = strdup( entry );
144 	if ( rdns[1] == NULL ) {
145 		tester_error( "strdup failed" );
146 		exit( EXIT_FAILURE );
147 	}
148 	*p2-- = ',';
149 
150 	for (i = p1 - entry;p2 >= p1;)
151 		DNs[1][i++] = *p2--;
152 
153 	DNs[1][i] = '\0';
154 	rdns[0] = strdup( DNs[1] );
155 	if ( rdns[0] == NULL ) {
156 		tester_error( "strdup failed" );
157 		exit( EXIT_FAILURE );
158 	}
159 	DNs[1][i] = ',';
160 
161 	i = 0;
162 
163 retry:;
164 	if ( ld == NULL ) {
165 		tester_init_ld( &ld, config, 0 );
166 	}
167 
168 	if ( do_retry == config->retries ) {
169 		fprintf( stderr, "PID=%ld - Modrdn(%d): entry=\"%s\".\n",
170 			(long) pid, config->loops, entry );
171 	}
172 
173 	for ( ; i < config->loops; i++ ) {
174 		rc = ldap_rename_s( ld, DNs[0], rdns[0], NULL, 0, NULL, NULL );
175 		if ( rc != LDAP_SUCCESS ) {
176 			tester_ldap_error( ld, "ldap_rename_s", NULL );
177 			switch ( rc ) {
178 			case LDAP_NO_SUCH_OBJECT:
179 				/* NOTE: this likely means
180 				 * the second modrdn failed
181 				 * during the previous round... */
182 				if ( !friendly ) {
183 					goto done;
184 				}
185 				break;
186 
187 			case LDAP_BUSY:
188 			case LDAP_UNAVAILABLE:
189 				if ( do_retry > 0 ) {
190 					do_retry--;
191 					goto retry;
192 				}
193 				/* fall thru */
194 
195 			default:
196 				goto done;
197 			}
198 		}
199 		rc = ldap_rename_s( ld, DNs[1], rdns[1], NULL, 1, NULL, NULL );
200 		if ( rc != LDAP_SUCCESS ) {
201 			tester_ldap_error( ld, "ldap_rename_s", NULL );
202 			switch ( rc ) {
203 			case LDAP_NO_SUCH_OBJECT:
204 				/* NOTE: this likely means
205 				 * the first modrdn failed
206 				 * during the previous round... */
207 				if ( !friendly ) {
208 					goto done;
209 				}
210 				break;
211 
212 			case LDAP_BUSY:
213 			case LDAP_UNAVAILABLE:
214 				if ( do_retry > 0 ) {
215 					do_retry--;
216 					goto retry;
217 				}
218 				/* fall thru */
219 
220 			default:
221 				goto done;
222 			}
223 		}
224 	}
225 
226 done:;
227 	fprintf( stderr, "  PID=%ld - Modrdn done (%d).\n", (long) pid, rc );
228 
229 	ldap_unbind_ext( ld, NULL, NULL );
230 
231 	free( DNs[1] );
232 	free( rdns[0] );
233 	free( rdns[1] );
234 }
235