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