]> git.sur5r.net Git - openldap/blob - servers/slapd/tools/slapcommon.c
slaptools update : replica promotion / demotion
[openldap] / servers / slapd / tools / slapcommon.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /* slapcommon.c - common routine for the slap tools */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/stdlib.h>
13 #include <ac/ctype.h>
14 #include <ac/string.h>
15 #include <ac/socket.h>
16 #include <ac/unistd.h>
17
18 #include "slapcommon.h"
19 #include "lutil.h"
20
21
22 char    *progname       = NULL;
23 char    *conffile       = SLAPD_DEFAULT_CONFIGFILE;
24 int             truncatemode = 0;
25 int             verbose         = 0;
26 int             update_ctxcsn = SLAP_TOOL_CTXCSN_KEEP;
27 int             retrieve_ctxcsn = 0;
28 int             retrieve_synccookie = 0;
29 int             replica_promotion = 0;
30 int             replica_demotion = 0;
31 char    *replica_id_string = NULL;
32 char    **replica_id_strlist = NULL;
33 int             *replica_id_list = NULL;
34 int             continuemode = 0;
35 int             nosubordinates = 0;
36 int             dryrun = 0;
37 struct berval   sub_ndn = { 0, NULL };
38
39 char    *ldiffile       = NULL;
40 FILE    *ldiffp         = NULL;
41
42 #ifdef CSRIMALLOC
43         char *leakfilename;
44         FILE *leakfile;
45 #endif
46
47 Backend *be = NULL;
48
49 static void
50 usage( int tool )
51 {
52         char *options = NULL;
53         fprintf( stderr,
54                 "usage: %s [-v] [-c] [-d debuglevel] [-f configfile]\n"
55                         "\t[-n databasenumber | -b suffix]", progname );
56
57         switch( tool ) {
58         case SLAPADD:
59                 options = "\n\t[-l ldiffile] [-u] [-p [-w] | -r [-i syncreplidlist] [-w]]\n";
60                 break;
61
62         case SLAPCAT:
63                 options = "\t[-l ldiffile] [-m] [-k]\n";
64                 break;
65
66         case SLAPINDEX:
67                 options = "\n";
68                 break;
69         }
70
71         if( options != NULL ) {
72                 fputs( options, stderr );
73         }
74         exit( EXIT_FAILURE );
75 }
76
77
78 /*
79  * slap_tool_init - initialize slap utility, handle program options.
80  * arguments:
81  *      name            program name
82  *      tool            tool code
83  *      argc, argv      command line arguments
84  */
85
86 void
87 slap_tool_init(
88         const char* name,
89         int tool,
90         int argc, char **argv )
91 {
92         char *options;
93         struct berval base = { 0, NULL };
94         char *subtree = NULL;
95         int rc, i, dbnum;
96         int mode = SLAP_TOOL_MODE;
97
98         progname = lutil_progname( name, argc, argv );
99
100 #ifdef CSRIMALLOC
101         leakfilename = malloc( strlen( progname ) + sizeof(".leak") );
102         sprintf( leakfilename, "%s.leak", progname );
103         if( ( leakfile = fopen( leakfilename, "w" )) == NULL ) {
104                 leakfile = stderr;
105         }
106         free( leakfilename );
107 #endif
108
109         switch( tool ) {
110         case SLAPADD:
111                 options = "b:cd:f:i:l:n:prtuvWw";
112                 break;
113
114         case SLAPINDEX:
115                 options = "b:cd:f:n:v";
116                 mode |= SLAP_TOOL_READMAIN;
117                 break;
118
119         case SLAPCAT:
120                 options = "b:cd:f:kl:mn:s:v";
121                 mode |= SLAP_TOOL_READMAIN | SLAP_TOOL_READONLY;
122                 break;
123
124         default:
125                 fprintf( stderr, "%s: unknown tool mode (%d)\n",
126                          progname, tool );
127                 exit( EXIT_FAILURE );
128         }
129
130         ldiffile = NULL;
131         conffile = SLAPD_DEFAULT_CONFIGFILE;
132         dbnum = -1;
133         while ( (i = getopt( argc, argv, options )) != EOF ) {
134                 switch ( i ) {
135                 case 'b':
136                         base.bv_val = strdup( optarg );
137                         base.bv_len = strlen( base.bv_val );
138                         break;
139
140                 case 'c':       /* enable continue mode */
141                         continuemode++;
142                         break;
143
144                 case 'd':       /* turn on debugging */
145                         ldap_debug += atoi( optarg );
146                         break;
147
148                 case 'f':       /* specify a conf file */
149                         conffile = strdup( optarg );
150                         break;
151
152                 case 'i': /* specify syncrepl id list */
153                         replica_id_string = strdup( optarg );
154                         if ( !isdigit( *replica_id_string )) {
155                                 usage( tool );
156                                 exit( EXIT_FAILURE );
157                         }
158                         str2clist( &replica_id_strlist, replica_id_string, "," );
159                         for ( i = 0; replica_id_strlist && replica_id_strlist[i]; i++ ) ;
160                         replica_id_list = ch_calloc( i + 1, sizeof( int ) );
161                         for ( i = 0; replica_id_strlist && replica_id_strlist[i]; i++ ) {
162                                 replica_id_list[i] = atoi( replica_id_strlist[i] );
163                         }
164                         replica_id_list[i] = -1;
165                         break;
166
167                 case 'k':       /* Retrieve sync cookie entry */
168                         retrieve_synccookie = 1;
169                         break;
170
171                 case 'l':       /* LDIF file */
172                         ldiffile = strdup( optarg );
173                         break;
174
175                 case 'm':       /* Retrieve ldapsync entry */
176                         retrieve_ctxcsn = 1;
177                         break;
178
179                 case 'n':       /* which config file db to index */
180                         dbnum = atoi( optarg ) - 1;
181                         break;
182
183                 case 'p':       /* replica promotion */
184                         replica_promotion = 1;          
185                         break;
186
187                 case 'r':       /* replica demotion */
188                         replica_demotion = 1;           
189                         break;
190
191                 case 's':       /* dump subtree */
192                         subtree = strdup( optarg );
193                         break;
194
195                 case 't':       /* turn on truncate */
196                         truncatemode++;
197                         mode |= SLAP_TRUNCATE_MODE;
198                         break;
199
200                 case 'u':       /* dry run */
201                         dryrun++;
202                         break;
203
204                 case 'v':       /* turn on verbose */
205                         verbose++;
206                         break;
207
208                 case 'W':       /* write context csn on every entry add */
209                         update_ctxcsn = SLAP_TOOL_CTXCSN_BATCH;
210                         /* FIXME : update_ctxcsn = SLAP_TOOL_CTXCSN_ENTRY; */
211                         break;
212
213                 case 'w':       /* write context csn on at the end */
214                         update_ctxcsn = SLAP_TOOL_CTXCSN_BATCH;
215                         break;
216
217                 default:
218                         usage( tool );
219                         break;
220                 }
221         }
222
223         if ( ( argc != optind ) || (dbnum >= 0 && base.bv_val != NULL ) ) {
224                 usage( tool );
225         }
226
227         if ( replica_promotion && replica_demotion ) {
228                 usage( tool );
229         } else if ( !replica_promotion && !replica_demotion ) {
230                 if ( update_ctxcsn != SLAP_TOOL_CTXCSN_KEEP ) {
231                         usage( tool );
232                 }
233         }
234
235         if ( ldiffile == NULL ) {
236                 ldiffp = tool == SLAPCAT ? stdout : stdin;
237
238         } else if( (ldiffp = fopen( ldiffile, tool == SLAPCAT ? "w" : "r" ))
239                 == NULL )
240         {
241                 perror( ldiffile );
242                 exit( EXIT_FAILURE );
243         }
244
245         /*
246          * initialize stuff and figure out which backend we're dealing with
247          */
248
249 #ifdef SLAPD_MODULES
250         if ( module_init() != 0 ) {
251                 fprintf( stderr, "%s: module_init failed!\n", progname );
252                 exit( EXIT_FAILURE );
253         }
254 #endif
255                 
256         rc = slap_init( mode, progname );
257
258         if ( rc != 0 ) {
259                 fprintf( stderr, "%s: slap_init failed!\n", progname );
260                 exit( EXIT_FAILURE );
261         }
262
263         rc = slap_schema_init();
264
265         if ( rc != 0 ) {
266                 fprintf( stderr, "%s: slap_schema_init failed!\n", progname );
267                 exit( EXIT_FAILURE );
268         }
269
270         rc = read_config( conffile, 0 );
271
272         if ( rc != 0 ) {
273                 fprintf( stderr, "%s: bad configuration file!\n", progname );
274                 exit( EXIT_FAILURE );
275         }
276
277         if ( !nbackends ) {
278                 fprintf( stderr, "No databases found in config file\n" );
279                 exit( EXIT_FAILURE );
280         }
281
282         rc = glue_sub_init();
283
284         if ( rc != 0 ) {
285                 fprintf( stderr, "Subordinate configuration error\n" );
286                 exit( EXIT_FAILURE );
287         }
288
289         rc = slap_schema_check();
290
291         if ( rc != 0 ) {
292                 fprintf( stderr, "%s: slap_schema_prep failed!\n", progname );
293                 exit( EXIT_FAILURE );
294         }
295
296         if( subtree ) {
297                 struct berval val;
298                 val.bv_val = subtree;
299                 val.bv_len = strlen( subtree );
300                 rc = dnNormalize( 0, NULL, NULL, &val, &sub_ndn, NULL );
301                 if( rc != LDAP_SUCCESS ) {
302                         fprintf( stderr, "Invalid subtree DN '%s'\n", optarg );
303                         exit( EXIT_FAILURE );
304                 }
305
306                 if( base.bv_val == NULL && dbnum == -1 )
307                         base = val;
308                 else
309                         free( subtree );
310         }
311
312         if( base.bv_val != NULL ) {
313                 struct berval nbase;
314
315                 rc = dnNormalize( 0, NULL, NULL, &base, &nbase, NULL );
316                 if( rc != LDAP_SUCCESS ) {
317                         fprintf( stderr, "%s: slap_init invalid suffix (\"%s\")\n",
318                                 progname, base.bv_val );
319                         exit( EXIT_FAILURE );
320                 }
321
322                 be = select_backend( &nbase, 0, 0 );
323                 ber_memfree( nbase.bv_val );
324
325                 if( be == NULL ) {
326                         fprintf( stderr, "%s: slap_init no backend for \"%s\"\n",
327                                 progname, base.bv_val );
328                         exit( EXIT_FAILURE );
329                 }
330                 /* If the named base is a glue master, operate on the
331                  * entire context
332                  */
333                 if (SLAP_GLUE_INSTANCE(be)) {
334                         nosubordinates = 1;
335                 }
336
337         } else if ( dbnum == -1 ) {
338                 if ( nbackends <= 0 ) {
339                         fprintf( stderr, "No available databases\n" );
340                         exit( EXIT_FAILURE );
341                 }
342                 
343                 be = &backends[dbnum=0];
344                 /* If just doing the first by default and it is a
345                  * glue subordinate, find the master.
346                  */
347                 while (SLAP_GLUE_SUBORDINATE(be) || SLAP_MONITOR(be)) {
348                         if (SLAP_GLUE_SUBORDINATE(be)) {
349                                 nosubordinates = 1;
350                         }
351                         be++;
352                         dbnum++;
353                 }
354
355
356                 if ( dbnum >= nbackends ) {
357                         fprintf( stderr, "Available database(s) "
358                                         "do not allow %s\n", name );
359                         exit( EXIT_FAILURE );
360                 }
361                 
362                 if ( nosubordinates == 0 && dbnum > 0 ) {
363 #ifdef NEW_LOGGING
364                         LDAP_LOG( BACKEND, ERR, 
365 "The first database does not allow %s; using the first available one (%d)\n",
366                                 name, dbnum + 1, 0 );
367 #else
368                         Debug( LDAP_DEBUG_ANY,
369 "The first database does not allow %s; using the first available one (%d)\n",
370                                 name, dbnum + 1, 0 );
371 #endif
372                 }
373
374         } else if ( dbnum < 0 || dbnum > (nbackends-1) ) {
375                 fprintf( stderr,
376                         "Database number selected via -n is out of range\n"
377                         "Must be in the range 1 to %d"
378                                 " (number of databases in the config file)\n",
379                         nbackends );
380                 exit( EXIT_FAILURE );
381
382         } else {
383                 be = &backends[dbnum];
384         }
385
386 #ifdef CSRIMALLOC
387         mal_leaktrace(1);
388 #endif
389
390         slap_startup( be );
391 }
392
393 void slap_tool_destroy( void )
394 {
395         slap_shutdown( be );
396         slap_destroy();
397 #ifdef SLAPD_MODULES
398         if ( slapMode == SLAP_SERVER_MODE ) {
399         /* always false. just pulls in necessary symbol references. */
400                 lutil_uuidstr(NULL, 0);
401         }
402         module_kill();
403 #endif
404         schema_destroy();
405 #ifdef HAVE_TLS
406         ldap_pvt_tls_destroy();
407 #endif
408         config_destroy();
409
410 #ifdef CSRIMALLOC
411         mal_dumpleaktrace( leakfile );
412 #endif
413 }