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