Back to index

openldap  2.4.31
slapadd.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * Portions Copyright 1998-2003 Kurt D. Zeilenga.
00006  * Portions Copyright 2003 IBM Corporation.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* ACKNOWLEDGEMENTS:
00018  * This work was initially developed by Kurt Zeilenga for inclusion
00019  * in OpenLDAP Software.  Additional signficant contributors include
00020  *    Jong Hyuk Choi
00021  *    Pierangelo Masarati
00022  */
00023 
00024 #include "portable.h"
00025 
00026 #include <stdio.h>
00027 
00028 #include <ac/stdlib.h>
00029 
00030 #include <ac/ctype.h>
00031 #include <ac/string.h>
00032 #include <ac/socket.h>
00033 #include <ac/unistd.h>
00034 
00035 #include <lber.h>
00036 #include <ldif.h>
00037 #include <lutil.h>
00038 #include <lutil_meter.h>
00039 #include <sys/stat.h>
00040 
00041 #include "slapcommon.h"
00042 
00043 static char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
00044 
00045 typedef struct Erec {
00046        Entry *e;
00047        int lineno;
00048        int nextline;
00049 } Erec;
00050 
00051 typedef struct Trec {
00052        Entry *e;
00053        int lineno;
00054        int nextline;
00055        int rc;
00056        int ready;
00057 } Trec;
00058 
00059 static Trec trec;
00060 static unsigned long sid = SLAP_SYNC_SID_MAX + 1;
00061 static int checkvals;
00062 static int enable_meter;
00063 static lutil_meter_t meter;
00064 static const char *progname = "slapadd";
00065 static OperationBuffer opbuf;
00066 static char *buf;
00067 static int lmax;
00068 
00069 static ldap_pvt_thread_mutex_t add_mutex;
00070 static ldap_pvt_thread_cond_t add_cond;
00071 static int add_stop;
00072 
00073 /* returns:
00074  *     1: got a record
00075  *     0: EOF
00076  * -1: read failure
00077  * -2: parse failure
00078  */
00079 static int
00080 getrec0(Erec *erec)
00081 {
00082        const char *text;
00083        int ldifrc;
00084        char textbuf[SLAP_TEXT_BUFLEN] = { '\0' };
00085        size_t textlen = sizeof textbuf;
00086        struct berval csn;
00087        Operation *op = &opbuf.ob_op;
00088        op->o_hdr = &opbuf.ob_hdr;
00089 
00090 again:
00091        erec->lineno = erec->nextline+1;
00092        /* nextline is the line number of the end of the current entry */
00093        ldifrc = ldif_read_record( ldiffp, &erec->nextline, &buf, &lmax );
00094        if (ldifrc < 1)
00095               return ldifrc < 0 ? -1 : 0;
00096        {
00097               BackendDB *bd;
00098               Entry *e;
00099 
00100               if ( erec->lineno < jumpline )
00101                      goto again;
00102 
00103               e = str2entry2( buf, checkvals );
00104 
00105               if ( enable_meter )
00106                      lutil_meter_update( &meter,
00107                                     ftell( ldiffp->fp ),
00108                                     0);
00109 
00110               if( e == NULL ) {
00111                      fprintf( stderr, "%s: could not parse entry (line=%d)\n",
00112                             progname, erec->lineno );
00113                      return -2;
00114               }
00115 
00116               /* make sure the DN is not empty */
00117               if( BER_BVISEMPTY( &e->e_nname ) &&
00118                      !BER_BVISEMPTY( be->be_nsuffix ))
00119               {
00120                      fprintf( stderr, "%s: line %d: "
00121                             "cannot add entry with empty dn=\"%s\"",
00122                             progname, erec->lineno, e->e_dn );
00123                      bd = select_backend( &e->e_nname, nosubordinates );
00124                      if ( bd ) {
00125                             BackendDB *bdtmp;
00126                             int dbidx = 0;
00127                             LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
00128                                    if ( bdtmp == bd ) break;
00129                                    dbidx++;
00130                             }
00131 
00132                             assert( bdtmp != NULL );
00133                             
00134                             fprintf( stderr, "; did you mean to use database #%d (%s)?",
00135                                    dbidx,
00136                                    bd->be_suffix[0].bv_val );
00137 
00138                      }
00139                      fprintf( stderr, "\n" );
00140                      entry_free( e );
00141                      return -2;
00142               }
00143 
00144               /* check backend */
00145               bd = select_backend( &e->e_nname, nosubordinates );
00146               if ( bd != be ) {
00147                      fprintf( stderr, "%s: line %d: "
00148                             "database #%d (%s) not configured to hold \"%s\"",
00149                             progname, erec->lineno,
00150                             dbnum,
00151                             be->be_suffix[0].bv_val,
00152                             e->e_dn );
00153                      if ( bd ) {
00154                             BackendDB *bdtmp;
00155                             int dbidx = 0;
00156                             LDAP_STAILQ_FOREACH( bdtmp, &backendDB, be_next ) {
00157                                    if ( bdtmp == bd ) break;
00158                                    dbidx++;
00159                             }
00160 
00161                             assert( bdtmp != NULL );
00162                             
00163                             fprintf( stderr, "; did you mean to use database #%d (%s)?",
00164                                    dbidx,
00165                                    bd->be_suffix[0].bv_val );
00166 
00167                      } else {
00168                             fprintf( stderr, "; no database configured for that naming context" );
00169                      }
00170                      fprintf( stderr, "\n" );
00171                      entry_free( e );
00172                      return -2;
00173               }
00174 
00175               if ( slap_tool_entry_check( progname, op, e, erec->lineno, &text, textbuf, textlen ) !=
00176                      LDAP_SUCCESS ) {
00177                      entry_free( e );
00178                      return -2;
00179               }
00180 
00181               if ( SLAP_LASTMOD(be) ) {
00182                      time_t now = slap_get_time();
00183                      char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
00184                      struct berval vals[ 2 ];
00185 
00186                      struct berval name, timestamp;
00187 
00188                      struct berval nvals[ 2 ];
00189                      struct berval nname;
00190                      char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
00191 
00192                      enum {
00193                             GOT_NONE = 0x0,
00194                             GOT_CSN = 0x1,
00195                             GOT_UUID = 0x2,
00196                             GOT_ALL = (GOT_CSN|GOT_UUID)
00197                      } got = GOT_ALL;
00198 
00199                      vals[1].bv_len = 0;
00200                      vals[1].bv_val = NULL;
00201 
00202                      nvals[1].bv_len = 0;
00203                      nvals[1].bv_val = NULL;
00204 
00205                      csn.bv_len = ldap_pvt_csnstr( csnbuf, sizeof( csnbuf ), csnsid, 0 );
00206                      csn.bv_val = csnbuf;
00207 
00208                      timestamp.bv_val = timebuf;
00209                      timestamp.bv_len = sizeof(timebuf);
00210 
00211                      slap_timestamp( &now, &timestamp );
00212 
00213                      if ( BER_BVISEMPTY( &be->be_rootndn ) ) {
00214                             BER_BVSTR( &name, SLAPD_ANONYMOUS );
00215                             nname = name;
00216                      } else {
00217                             name = be->be_rootdn;
00218                             nname = be->be_rootndn;
00219                      }
00220 
00221                      if( attr_find( e->e_attrs, slap_schema.si_ad_entryUUID )
00222                             == NULL )
00223                      {
00224                             got &= ~GOT_UUID;
00225                             vals[0].bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
00226                             vals[0].bv_val = uuidbuf;
00227                             attr_merge_normalize_one( e, slap_schema.si_ad_entryUUID, vals, NULL );
00228                      }
00229 
00230                      if( attr_find( e->e_attrs, slap_schema.si_ad_creatorsName )
00231                             == NULL )
00232                      {
00233                             vals[0] = name;
00234                             nvals[0] = nname;
00235                             attr_merge( e, slap_schema.si_ad_creatorsName, vals, nvals );
00236                      }
00237 
00238                      if( attr_find( e->e_attrs, slap_schema.si_ad_createTimestamp )
00239                             == NULL )
00240                      {
00241                             vals[0] = timestamp;
00242                             attr_merge( e, slap_schema.si_ad_createTimestamp, vals, NULL );
00243                      }
00244 
00245                      if( attr_find( e->e_attrs, slap_schema.si_ad_entryCSN )
00246                             == NULL )
00247                      {
00248                             got &= ~GOT_CSN;
00249                             vals[0] = csn;
00250                             attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL );
00251                      }
00252 
00253                      if( attr_find( e->e_attrs, slap_schema.si_ad_modifiersName )
00254                             == NULL )
00255                      {
00256                             vals[0] = name;
00257                             nvals[0] = nname;
00258                             attr_merge( e, slap_schema.si_ad_modifiersName, vals, nvals );
00259                      }
00260 
00261                      if( attr_find( e->e_attrs, slap_schema.si_ad_modifyTimestamp )
00262                             == NULL )
00263                      {
00264                             vals[0] = timestamp;
00265                             attr_merge( e, slap_schema.si_ad_modifyTimestamp, vals, NULL );
00266                      }
00267 
00268                      if ( SLAP_SINGLE_SHADOW(be) && got != GOT_ALL ) {
00269                             char buf[SLAP_TEXT_BUFLEN];
00270 
00271                             snprintf( buf, sizeof(buf),
00272                                    "%s%s%s",
00273                                    ( !(got & GOT_UUID) ? slap_schema.si_ad_entryUUID->ad_cname.bv_val : "" ),
00274                                    ( !(got & GOT_CSN) ? "," : "" ),
00275                                    ( !(got & GOT_CSN) ? slap_schema.si_ad_entryCSN->ad_cname.bv_val : "" ) );
00276 
00277                             Debug( LDAP_DEBUG_ANY, "%s: warning, missing attrs %s from entry dn=\"%s\"\n",
00278                                    progname, buf, e->e_name.bv_val );
00279                      }
00280 
00281                      sid = slap_tool_update_ctxcsn_check( progname, e );
00282               }
00283               erec->e = e;
00284        }
00285        return 1;
00286 }
00287 
00288 static void *
00289 getrec_thr(void *ctx)
00290 {
00291        ldap_pvt_thread_mutex_lock( &add_mutex );
00292        while (!add_stop) {
00293               trec.rc = getrec0((Erec *)&trec);
00294               trec.ready = 1;
00295               while (trec.ready)
00296                      ldap_pvt_thread_cond_wait( &add_cond, &add_mutex );
00297               /* eof or read failure */
00298               if ( trec.rc == 0 || trec.rc == -1 )
00299                      break;
00300        }
00301        ldap_pvt_thread_mutex_unlock( &add_mutex );
00302        return NULL;
00303 }
00304 
00305 static int
00306 getrec(Erec *erec)
00307 {
00308        int rc;
00309        if ( slap_tool_thread_max < 2 )
00310               return getrec0(erec);
00311 
00312        while (!trec.ready)
00313               ldap_pvt_thread_yield();
00314        erec->e = trec.e;
00315        erec->lineno = trec.lineno;
00316        erec->nextline = trec.nextline;
00317        trec.ready = 0;
00318        rc = trec.rc;
00319        ldap_pvt_thread_mutex_lock( &add_mutex );
00320        ldap_pvt_thread_mutex_unlock( &add_mutex );
00321        ldap_pvt_thread_cond_signal( &add_cond );
00322        return rc;
00323 }
00324 
00325 int
00326 slapadd( int argc, char **argv )
00327 {
00328        char textbuf[SLAP_TEXT_BUFLEN] = { '\0' };
00329        size_t textlen = sizeof textbuf;
00330        Erec erec;
00331        struct berval bvtext;
00332        ldap_pvt_thread_t thr;
00333        ID id;
00334 
00335        int ldifrc;
00336        int rc = EXIT_SUCCESS;
00337 
00338        struct stat stat_buf;
00339 
00340        /* default "000" */
00341        csnsid = 0;
00342 
00343        if ( isatty (2) ) enable_meter = 1;
00344        slap_tool_init( progname, SLAPADD, argc, argv );
00345 
00346        if( !be->be_entry_open ||
00347               !be->be_entry_close ||
00348               !be->be_entry_put ||
00349               (update_ctxcsn &&
00350                (!be->be_dn2id_get ||
00351                 !be->be_entry_get ||
00352                 !be->be_entry_modify)) )
00353        {
00354               fprintf( stderr, "%s: database doesn't support necessary operations.\n",
00355                      progname );
00356               if ( dryrun ) {
00357                      fprintf( stderr, "\t(dry) continuing...\n" );
00358 
00359               } else {
00360                      exit( EXIT_FAILURE );
00361               }
00362        }
00363 
00364        checkvals = (slapMode & SLAP_TOOL_QUICK) ? 0 : 1;
00365 
00366        /* do not check values in quick mode */
00367        if ( slapMode & SLAP_TOOL_QUICK ) {
00368               if ( slapMode & SLAP_TOOL_VALUE_CHECK ) {
00369                      fprintf( stderr, "%s: value-check incompatible with quick mode; disabled.\n", progname );
00370                      slapMode &= ~SLAP_TOOL_VALUE_CHECK;
00371               }
00372        }
00373 
00374        /* enforce schema checking unless not disabled */
00375        if ( (slapMode & SLAP_TOOL_NO_SCHEMA_CHECK) == 0) {
00376               SLAP_DBFLAGS(be) &= ~(SLAP_DBFLAG_NO_SCHEMA_CHECK);
00377        }
00378 
00379        if( !dryrun && be->be_entry_open( be, 1 ) != 0 ) {
00380               fprintf( stderr, "%s: could not open database.\n",
00381                      progname );
00382               exit( EXIT_FAILURE );
00383        }
00384 
00385        (void)slap_tool_update_ctxcsn_init();
00386 
00387        if ( enable_meter
00388 #ifdef LDAP_DEBUG
00389               /* tools default to "none" */
00390               && slap_debug == LDAP_DEBUG_NONE
00391 #endif
00392               && !fstat ( fileno ( ldiffp->fp ), &stat_buf )
00393               && S_ISREG(stat_buf.st_mode) ) {
00394               enable_meter = !lutil_meter_open(
00395                      &meter,
00396                      &lutil_meter_text_display,
00397                      &lutil_meter_linear_estimator,
00398                      stat_buf.st_size);
00399        } else {
00400               enable_meter = 0;
00401        }
00402 
00403        if ( slap_tool_thread_max > 1 ) {
00404               ldap_pvt_thread_mutex_init( &add_mutex );
00405               ldap_pvt_thread_cond_init( &add_cond );
00406               ldap_pvt_thread_create( &thr, 0, getrec_thr, NULL );
00407        }
00408 
00409        erec.nextline = 0;
00410        erec.e = NULL;
00411 
00412        for (;;) {
00413               ldifrc = getrec( &erec );
00414               if ( ldifrc < 1 ) {
00415                      if ( ldifrc == -2 && continuemode )
00416                             continue;
00417                      break;
00418               }
00419 
00420               if ( !dryrun ) {
00421                      /*
00422                       * Initialize text buffer
00423                       */
00424                      bvtext.bv_len = textlen;
00425                      bvtext.bv_val = textbuf;
00426                      bvtext.bv_val[0] = '\0';
00427 
00428                      id = be->be_entry_put( be, erec.e, &bvtext );
00429                      if( id == NOID ) {
00430                             fprintf( stderr, "%s: could not add entry dn=\"%s\" "
00431                                                          "(line=%d): %s\n", progname, erec.e->e_dn,
00432                                                          erec.lineno, bvtext.bv_val );
00433                             rc = EXIT_FAILURE;
00434                             entry_free( erec.e );
00435                             if( continuemode ) continue;
00436                             break;
00437                      }
00438                      if ( verbose )
00439                             fprintf( stderr, "added: \"%s\" (%08lx)\n",
00440                                    erec.e->e_dn, (long) id );
00441               } else {
00442                      if ( verbose )
00443                             fprintf( stderr, "added: \"%s\"\n",
00444                                    erec.e->e_dn );
00445               }
00446 
00447               entry_free( erec.e );
00448        }
00449 
00450        if ( slap_tool_thread_max > 1 ) {
00451               ldap_pvt_thread_mutex_lock( &add_mutex );
00452               add_stop = 1;
00453               trec.ready = 0;
00454               ldap_pvt_thread_cond_signal( &add_cond );
00455               ldap_pvt_thread_mutex_unlock( &add_mutex );
00456               ldap_pvt_thread_join( thr, NULL );
00457        }
00458 
00459        if ( ldifrc < 0 )
00460               rc = EXIT_FAILURE;
00461 
00462        bvtext.bv_len = textlen;
00463        bvtext.bv_val = textbuf;
00464        bvtext.bv_val[0] = '\0';
00465 
00466        if ( enable_meter ) {
00467               lutil_meter_update( &meter, ftell( ldiffp->fp ), 1);
00468               lutil_meter_close( &meter );
00469        }
00470 
00471        if ( rc == EXIT_SUCCESS ) {
00472               rc = slap_tool_update_ctxcsn( progname, sid, &bvtext );
00473        }
00474 
00475        ch_free( buf );
00476 
00477        if ( !dryrun ) {
00478               if ( enable_meter ) {
00479                      fprintf( stderr, "Closing DB..." );
00480               }
00481               if( be->be_entry_close( be ) ) {
00482                      rc = EXIT_FAILURE;
00483               }
00484 
00485               if( be->be_sync ) {
00486                      be->be_sync( be );
00487               }
00488               if ( enable_meter ) {
00489                      fprintf( stderr, "\n" );
00490               }
00491        }
00492 
00493        if ( slap_tool_destroy())
00494               rc = EXIT_FAILURE;
00495 
00496        return rc;
00497 }
00498