]> git.sur5r.net Git - openldap/blob - servers/slapd/slapadd.c
Merge remote-tracking branch 'origin/mdb.master'
[openldap] / servers / slapd / slapadd.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2013 The OpenLDAP Foundation.
5  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
6  * Portions Copyright 2003 IBM Corporation.
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 Kurt Zeilenga for inclusion
19  * in OpenLDAP Software.  Additional signficant contributors include
20  *    Jong Hyuk Choi
21  *    Pierangelo Masarati
22  */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27
28 #include <ac/stdlib.h>
29
30 #include <ac/ctype.h>
31 #include <ac/string.h>
32 #include <ac/socket.h>
33 #include <ac/unistd.h>
34
35 #include <lber.h>
36 #include <ldif.h>
37 #include <lutil.h>
38 #include <lutil_meter.h>
39 #include <sys/stat.h>
40
41 #include "slapcommon.h"
42
43 extern int slap_DN_strict;      /* dn.c */
44
45 static char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
46
47 typedef struct Erec {
48         Entry *e;
49         unsigned long lineno;
50         unsigned long nextline;
51 } Erec;
52
53 typedef struct Trec {
54         Entry *e;
55         unsigned long lineno;
56         unsigned long nextline;
57         int rc;
58         int ready;
59 } Trec;
60
61 static Trec trec;
62 static unsigned long sid = SLAP_SYNC_SID_MAX + 1;
63 static int checkvals;
64 static int enable_meter;
65 static lutil_meter_t meter;
66 static const char *progname = "slapadd";
67 static OperationBuffer opbuf;
68 static char *buf;
69 static int lmax;
70
71 static ldap_pvt_thread_mutex_t add_mutex;
72 static ldap_pvt_thread_cond_t add_cond;
73 static int add_stop;
74
75 /* returns:
76  *      1: got a record
77  *      0: EOF
78  * -1: read failure
79  * -2: parse failure
80  */
81 static int
82 getrec0(Erec *erec)
83 {
84         const char *text;
85         int ldifrc;
86         char textbuf[SLAP_TEXT_BUFLEN] = { '\0' };
87         size_t textlen = sizeof textbuf;
88         struct berval csn;
89         Operation *op = &opbuf.ob_op;
90         op->o_hdr = &opbuf.ob_hdr;
91
92 again:
93         erec->lineno = erec->nextline+1;
94         /* nextline is the line number of the end of the current entry */
95         ldifrc = ldif_read_record( ldiffp, &erec->nextline, &buf, &lmax );
96         if (ldifrc < 1)
97                 return ldifrc < 0 ? -1 : 0;
98         {
99                 BackendDB *bd;
100                 Entry *e;
101                 int prev_DN_strict;
102
103                 if ( erec->lineno < jumpline )
104                         goto again;
105
106                 if ( !dbnum ) {
107                         prev_DN_strict = slap_DN_strict;
108                         slap_DN_strict = 0;
109                 }
110                 e = str2entry2( buf, checkvals );
111                 if ( !dbnum ) {
112                         slap_DN_strict = prev_DN_strict;
113                 }
114
115                 if ( enable_meter )
116                         lutil_meter_update( &meter,
117                                          ftell( ldiffp->fp ),
118                                          0);
119
120                 if( e == NULL ) {
121                         fprintf( stderr, "%s: could not parse entry (line=%lu)\n",
122                                 progname, erec->lineno );
123                         return -2;
124                 }
125
126                 /* make sure the DN is not empty */
127                 if( BER_BVISEMPTY( &e->e_nname ) &&
128                         !BER_BVISEMPTY( be->be_nsuffix ))
129                 {
130                         fprintf( stderr, "%s: line %lu: "
131                                 "cannot add entry with empty dn=\"%s\"",
132                                 progname, erec->lineno, e->e_dn );
133                         bd = select_backend( &e->e_nname, nosubordinates );
134                         if ( bd ) {
135                                 BackendDB *bdtmp;
136                                 int dbidx = 0;
137                                 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
138                                         if ( bdtmp == bd ) break;
139                                         dbidx++;
140                                 }
141
142                                 assert( bdtmp != NULL );
143                                 
144                                 fprintf( stderr, "; did you mean to use database #%d (%s)?",
145                                         dbidx,
146                                         bd->be_suffix[0].bv_val );
147
148                         }
149                         fprintf( stderr, "\n" );
150                         entry_free( e );
151                         return -2;
152                 }
153
154                 /* check backend */
155                 bd = select_backend( &e->e_nname, nosubordinates );
156                 if ( bd != be ) {
157                         fprintf( stderr, "%s: line %lu: "
158                                 "database #%d (%s) not configured to hold \"%s\"",
159                                 progname, erec->lineno,
160                                 dbnum,
161                                 be->be_suffix[0].bv_val,
162                                 e->e_dn );
163                         if ( bd ) {
164                                 BackendDB *bdtmp;
165                                 int dbidx = 0;
166                                 LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
167                                         if ( bdtmp == bd ) break;
168                                         dbidx++;
169                                 }
170
171                                 assert( bdtmp != NULL );
172                                 
173                                 fprintf( stderr, "; did you mean to use database #%d (%s)?",
174                                         dbidx,
175                                         bd->be_suffix[0].bv_val );
176
177                         } else {
178                                 fprintf( stderr, "; no database configured for that naming context" );
179                         }
180                         fprintf( stderr, "\n" );
181                         entry_free( e );
182                         return -2;
183                 }
184
185                 if ( slap_tool_entry_check( progname, op, e, erec->lineno, &text, textbuf, textlen ) !=
186                         LDAP_SUCCESS ) {
187                         entry_free( e );
188                         return -2;
189                 }
190
191                 if ( SLAP_LASTMOD(be) ) {
192                         time_t now = slap_get_time();
193                         char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
194                         struct berval vals[ 2 ];
195
196                         struct berval name, timestamp;
197
198                         struct berval nvals[ 2 ];
199                         struct berval nname;
200                         char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
201
202                         enum {
203                                 GOT_NONE = 0x0,
204                                 GOT_CSN = 0x1,
205                                 GOT_UUID = 0x2,
206                                 GOT_ALL = (GOT_CSN|GOT_UUID)
207                         } got = GOT_ALL;
208
209                         vals[1].bv_len = 0;
210                         vals[1].bv_val = NULL;
211
212                         nvals[1].bv_len = 0;
213                         nvals[1].bv_val = NULL;
214
215                         csn.bv_len = ldap_pvt_csnstr( csnbuf, sizeof( csnbuf ), csnsid, 0 );
216                         csn.bv_val = csnbuf;
217
218                         timestamp.bv_val = timebuf;
219                         timestamp.bv_len = sizeof(timebuf);
220
221                         slap_timestamp( &now, &timestamp );
222
223                         if ( BER_BVISEMPTY( &be->be_rootndn ) ) {
224                                 BER_BVSTR( &name, SLAPD_ANONYMOUS );
225                                 nname = name;
226                         } else {
227                                 name = be->be_rootdn;
228                                 nname = be->be_rootndn;
229                         }
230
231                         if( attr_find( e->e_attrs, slap_schema.si_ad_entryUUID )
232                                 == NULL )
233                         {
234                                 got &= ~GOT_UUID;
235                                 vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
236                                 vals[0].bv_val = uuidbuf;
237                                 attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, vals, NULL );
238                         }
239
240                         if( attr_find( e->e_attrs, slap_schema.si_ad_creatorsName )
241                                 == NULL )
242                         {
243                                 vals[0] = name;
244                                 nvals[0] = nname;
245                                 attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals );
246                         }
247
248                         if( attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp )
249                                 == NULL )
250                         {
251                                 vals[0] = timestamp;
252                                 attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL );
253                         }
254
255                         if( attr_find( e->e_attrs, slap_schema.si_ad_entryCSN )
256                                 == NULL )
257                         {
258                                 got &= ~GOT_CSN;
259                                 vals[0] = csn;
260                                 attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL );
261                         }
262
263                         if( attr_find( e->e_attrs, slap_schema.si_ad_modifiersName )
264                                 == NULL )
265                         {
266                                 vals[0] = name;
267                                 nvals[0] = nname;
268                                 attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals );
269                         }
270
271                         if( attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp )
272                                 == NULL )
273                         {
274                                 vals[0] = timestamp;
275                                 attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL );
276                         }
277
278                         if ( SLAP_SINGLE_SHADOW(be) && got != GOT_ALL ) {
279                                 char buf[SLAP_TEXT_BUFLEN];
280
281                                 snprintf( buf, sizeof(buf),
282                                         "%s%s%s",
283                                         ( !(got & GOT_UUID) ? slap_schema.si_ad_entryUUID->ad_cname.bv_val : "" ),
284                                         ( !(got & GOT_CSN) ? "," : "" ),
285                                         ( !(got & GOT_CSN) ? slap_schema.si_ad_entryCSN->ad_cname.bv_val : "" ) );
286
287                                 Debug( LDAP_DEBUG_ANY, "%s: warning, missing attrs %s from entry dn=\"%s\"\n",
288                                         progname, buf, e->e_name.bv_val );
289                         }
290
291                         sid = slap_tool_update_ctxcsn_check( progname, e );
292                 }
293                 erec->e = e;
294         }
295         return 1;
296 }
297
298 static void *
299 getrec_thr(void *ctx)
300 {
301         ldap_pvt_thread_mutex_lock( &add_mutex );
302         while (!add_stop) {
303                 trec.rc = getrec0((Erec *)&trec);
304                 trec.ready = 1;
305                 while (trec.ready)
306                         ldap_pvt_thread_cond_wait( &add_cond, &add_mutex );
307                 /* eof or read failure */
308                 if ( trec.rc == 0 || trec.rc == -1 )
309                         break;
310         }
311         ldap_pvt_thread_mutex_unlock( &add_mutex );
312         return NULL;
313 }
314
315 static int ldif_threaded;
316
317 static int
318 getrec(Erec *erec)
319 {
320         int rc;
321         if ( !ldif_threaded )
322                 return getrec0(erec);
323
324         while (!trec.ready)
325                 ldap_pvt_thread_yield();
326         erec->e = trec.e;
327         erec->lineno = trec.lineno;
328         erec->nextline = trec.nextline;
329         trec.ready = 0;
330         rc = trec.rc;
331         ldap_pvt_thread_mutex_lock( &add_mutex );
332         ldap_pvt_thread_mutex_unlock( &add_mutex );
333         ldap_pvt_thread_cond_signal( &add_cond );
334         return rc;
335 }
336
337 int
338 slapadd( int argc, char **argv )
339 {
340         char textbuf[SLAP_TEXT_BUFLEN] = { '\0' };
341         size_t textlen = sizeof textbuf;
342         Erec erec;
343         struct berval bvtext;
344         ldap_pvt_thread_t thr;
345         ID id;
346         Entry *prev = NULL;
347
348         int ldifrc;
349         int rc = EXIT_SUCCESS;
350
351         struct stat stat_buf;
352
353         /* default "000" */
354         csnsid = 0;
355
356         if ( isatty (2) ) enable_meter = 1;
357         slap_tool_init( progname, SLAPADD, argc, argv );
358
359         if( !be->be_entry_open ||
360                 !be->be_entry_close ||
361                 !be->be_entry_put ||
362                 (update_ctxcsn &&
363                  (!be->be_dn2id_get ||
364                   !be->be_entry_get ||
365                   !be->be_entry_modify)) )
366         {
367                 fprintf( stderr, "%s: database doesn't support necessary operations.\n",
368                         progname );
369                 if ( dryrun ) {
370                         fprintf( stderr, "\t(dry) continuing...\n" );
371
372                 } else {
373                         exit( EXIT_FAILURE );
374                 }
375         }
376
377         checkvals = (slapMode & SLAP_TOOL_QUICK) ? 0 : 1;
378
379         /* do not check values in quick mode */
380         if ( slapMode & SLAP_TOOL_QUICK ) {
381                 if ( slapMode & SLAP_TOOL_VALUE_CHECK ) {
382                         fprintf( stderr, "%s: value-check incompatible with quick mode; disabled.\n", progname );
383                         slapMode &= ~SLAP_TOOL_VALUE_CHECK;
384                 }
385         }
386
387         /* enforce schema checking unless not disabled */
388         if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) {
389                 SLAP_DBFLAGS(be) &= ~(SLAP_DBFLAG_NO_SCHEMA_CHECK);
390         }
391
392         if( !dryrun && be->be_entry_open( be, 1 ) != 0 ) {
393                 fprintf( stderr, "%s: could not open database.\n",
394                         progname );
395                 exit( EXIT_FAILURE );
396         }
397
398         (void)slap_tool_update_ctxcsn_init();
399
400         if ( enable_meter
401 #ifdef LDAP_DEBUG
402                 /* tools default to "none" */
403                 && slap_debug == LDAP_DEBUG_NONE
404 #endif
405                 && !fstat ( fileno ( ldiffp->fp ), &stat_buf )
406                 && S_ISREG(stat_buf.st_mode) ) {
407                 enable_meter = !lutil_meter_open(
408                         &meter,
409                         &lutil_meter_text_display,
410                         &lutil_meter_linear_estimator,
411                         stat_buf.st_size);
412         } else {
413                 enable_meter = 0;
414         }
415
416         if ( slap_tool_thread_max > 1 ) {
417                 ldap_pvt_thread_mutex_init( &add_mutex );
418                 ldap_pvt_thread_cond_init( &add_cond );
419                 ldap_pvt_thread_create( &thr, 0, getrec_thr, NULL );
420                 ldif_threaded = 1;
421         }
422
423         erec.nextline = 0;
424         erec.e = NULL;
425
426         for (;;) {
427                 ldifrc = getrec( &erec );
428                 if ( ldifrc < 1 ) {
429                         if ( ldifrc == -2 && continuemode )
430                                 continue;
431                         break;
432                 }
433
434                 if ( !dryrun ) {
435                         /*
436                          * Initialize text buffer
437                          */
438                         bvtext.bv_len = textlen;
439                         bvtext.bv_val = textbuf;
440                         bvtext.bv_val[0] = '\0';
441
442                         id = be->be_entry_put( be, erec.e, &bvtext );
443                         if( id == NOID ) {
444                                 fprintf( stderr, "%s: could not add entry dn=\"%s\" "
445                                                                  "(line=%lu): %s\n", progname, erec.e->e_dn,
446                                                                  erec.lineno, bvtext.bv_val );
447                                 rc = EXIT_FAILURE;
448                                 if( continuemode ) {
449                                         if ( prev ) entry_free( prev );
450                                         prev = erec.e;
451                                         continue;
452                                 }
453                                 break;
454                         }
455                         if ( verbose )
456                                 fprintf( stderr, "added: \"%s\" (%08lx)\n",
457                                         erec.e->e_dn, (long) id );
458                 } else {
459                         if ( verbose )
460                                 fprintf( stderr, "added: \"%s\"\n",
461                                         erec.e->e_dn );
462                 }
463
464                 if ( prev ) entry_free( prev );
465                 prev = erec.e;
466         }
467
468         if ( ldif_threaded ) {
469                 ldap_pvt_thread_mutex_lock( &add_mutex );
470                 add_stop = 1;
471                 trec.ready = 0;
472                 ldap_pvt_thread_cond_signal( &add_cond );
473                 ldap_pvt_thread_mutex_unlock( &add_mutex );
474                 ldap_pvt_thread_join( thr, NULL );
475         }
476         if ( erec.e ) entry_free( erec.e );
477
478         if ( ldifrc < 0 )
479                 rc = EXIT_FAILURE;
480
481         bvtext.bv_len = textlen;
482         bvtext.bv_val = textbuf;
483         bvtext.bv_val[0] = '\0';
484
485         if ( enable_meter ) {
486                 lutil_meter_update( &meter, ftell( ldiffp->fp ), 1);
487                 lutil_meter_close( &meter );
488         }
489
490         if ( rc == EXIT_SUCCESS ) {
491                 rc = slap_tool_update_ctxcsn( progname, sid, &bvtext );
492         }
493
494         ch_free( buf );
495
496         if ( !dryrun ) {
497                 if ( enable_meter ) {
498                         fprintf( stderr, "Closing DB..." );
499                 }
500                 if( be->be_entry_close( be ) ) {
501                         rc = EXIT_FAILURE;
502                 }
503
504                 if( be->be_sync ) {
505                         be->be_sync( be );
506                 }
507                 if ( enable_meter ) {
508                         fprintf( stderr, "\n" );
509                 }
510         }
511
512         if ( slap_tool_destroy())
513                 rc = EXIT_FAILURE;
514
515         return rc;
516 }
517