3 * Copyright (c) 1990, 1995 Regents of the University of Michigan.
6 * Redistribution and use in source and binary forms are permitted
7 * provided that this notice is preserved and that due credit is given
8 * to the University of Michigan at Ann Arbor. The name of the University
9 * may not be used to endorse or promote products derived from this
10 * software without specific prior written permission. This software
11 * is provided ``as is'' without express or implied warranty.
15 * chlog2replog - read a quipu-style changelog on stdin and write a
16 * slapd-style replog on stdout, or write to a file, respecting
17 * slapd/slurpd locking conventions.
23 #include <ac/stdlib.h>
26 #include <ac/string.h>
27 #include <ac/unistd.h>
29 #include <quipu/commonarg.h>
30 #include <quipu/attrvalue.h>
34 static int dn2ldif(PS ps, DN dn);
35 static void de_t61(char *s, int t61mark);
37 extern FILE *lock_fopen( char *, char *, FILE ** );
38 extern int lock_fclose( FILE *, FILE * );
39 extern void *ch_realloc( void *, unsigned long );
45 int ldap_syslog_level = 0;
57 #define TY_MODIFYTYPE 1
62 #define TY_MODIFYARGS 6
64 #define MOD_ADDVALUES 1
65 #define MOD_ADDATTRIBUTE 2
66 #define MOD_REMOVEATTRIBUTE 3
67 #define MOD_REMOVEVALUES 4
71 dn2ldap( char *edbdn )
77 static int inited = 0;
80 /* load & initialize quipu syntax handlers */
84 pp_quipu_init( progname );
87 dsap_init( NULL, NULL );
89 if (( ldap_dn_syntax = str2syntax( "DN" )) == 0 ) {
95 if (( dn = str2dn( edbdn )) == NULLDN ) {
99 if (( str_ps = ps_alloc( str_open )) == NULLPS ||
100 str_setup( str_ps, NULLCP, 0, 0 ) == NOTOK ) {
105 if ( dn2ldif( str_ps, dn ) != 0 ) {
112 len = ( str_ps->ps_ptr - str_ps->ps_base );
114 if (( ldapdn = malloc( len + 1 )) == NULL ) {
119 memcpy( ldapdn, str_ps->ps_base, len );
120 ldapdn[ len ] = '\0';
126 #define SEPARATOR(c) ((c) == ',' || (c) == ';')
127 #define SPACE(c) ((c) == ' ' || (c) == '\n')
130 dn2ldif( PS ps, DN dn )
137 if ( dn == NULLDN ) {
141 if ( dn->dn_parent != NULLDN ) {
142 if (( rc = dn2ldif( ps, dn->dn_parent )) != 0 ) {
145 ps_print( ps, ", " );
148 if ( (rps = ps_alloc( str_open )) == NULLPS ||
149 str_setup( rps, NULLCP, 0, 0 ) == NOTOK ) {
154 for ( rdn = dn->dn_rdn; rdn != NULLRDN; rdn = rdn->rdn_next ) {
158 ps_print( ps, " + " );
161 AttrT_print( ps, rdn->rdn_at, EDBOUT );
164 if ( rdn->rdn_at->oa_syntax == ldap_dn_syntax ) {
165 if (( rc = dn2ldif( rps, (DN) rdn->rdn_av.av_struct )) != 0 ) {
169 value = rps->ps_base;
171 AttrV_print( rps, &rdn->rdn_av, EDBOUT );
173 value = rps->ps_base;
178 * ,+="\\\n all go in quotes. " and \\ need to
179 * be preceeded by \\.
182 if ( strpbrk( value, ",+=\"\\\n" ) != NULL || SPACE( value[0] )
183 || SPACE( value[max( strlen(value) - 1, 0 )] ) ) {
187 ps_print( ps, "\"" );
190 for ( p = value; *p != '\0'; p++ ) {
191 if ( *p == '"' || *p == '\\' ) {
195 if ( specialcount > 0 ) {
196 tmp = smalloc( strlen( value ) + specialcount + 1 );
197 for ( p = value, t = tmp; *p != '\0'; p++ ) {
211 ps_print( ps, value );
214 ps_print( ps, "\"" );
216 ps_print( ps, value );
219 rps->ps_ptr = rps->ps_base;
233 de_t61(char *s, int t61mark)
242 if ( strncasecmp( s, T61, T61LEN) == 0 ) {
261 else if ( c >= 'A' && c <= 'F' )
263 else if ( c >= 'a' && c <= 'f' )
273 else if ( c >= 'A' && c <= 'F' )
275 else if ( c >= 'a' && c <= 'f' )
299 getattr(char *buf, char sep)
303 static char retbuf[ RBSIZE ];
305 if (( val = strchr( buf, sep )) != NULL ) {
306 strncpy( retbuf, buf, val - buf );
307 retbuf[ val - buf ] = '\0';
316 getattr_ldif(char *buf)
318 return( getattr( buf, ':' ));
323 getattr_edb(char *buf)
325 return( getattr( buf, '=' ));
329 getval(char *buf, char sep)
333 if (( val = strchr( buf, sep )) != NULL ) {
334 return( strdup( ++val ));
341 getval_ldif(char *buf)
343 return( getval( buf, ':' ));
348 getval_edb(char *buf)
350 return( getval( buf, '=' ));
357 isDNsyntax(char *attr)
359 oid_table_attr *p, *name2attr(char *);
361 p = name2attr( attr );
362 if ( p == ( oid_table_attr * ) 0 ) {
365 if ( p->oa_syntax == ldap_dn_syntax ) {
375 print_as(Attr_Sequence as, int modtype, FILE *ofp)
379 char *attrname, *tmpdn, *obuf;
382 for ( p = as; p != NULLATTR; p = p->attr_link) {
383 rps->ps_ptr = rps->ps_base;
384 AttrT_print( rps, p->attr_type, EDBOUT );
386 attrname = strdup( rps->ps_base );
387 if ( modtype != 0 ) {
390 case MOD_ADDATTRIBUTE:
391 fprintf( ofp, "add: %s\n", attrname );
393 case MOD_REMOVEATTRIBUTE:
394 case MOD_REMOVEVALUES:
395 fprintf( ofp, "delete: %s\n", attrname );
401 for ( av = p->attr_value; av != NULLAV; av = av->avseq_next ) {
402 rps->ps_ptr = rps->ps_base;
403 AttrV_print( rps, &av->avseq_av, EDBOUT );
405 de_t61( rps->ps_base, 0 );
406 if ( isDNsyntax( attrname )) {
407 tmpdn = dn2ldap( rps->ps_base );
408 obuf = ldif_type_and_value( attrname, tmpdn,
412 obuf = ldif_type_and_value( attrname, rps->ps_base,
413 strlen( rps->ps_base ));
415 if ( obuf != NULL ) {
420 if ( modtype != 0 ) {
421 fprintf( ofp, "-\n" );
432 fprintf( stderr, "usage: %s -d dn-suffix -r replica:port ", name );
433 fprintf( stderr, "[-r replica:port...] [-o outputfile]\n" );
438 main( int argc, char **argv )
440 char *ldapdn, nbuf[ 4096 ], *buf, *p;
441 int state, prevstate, modstate, modtype, i;
450 char **replicas = NULL;
452 char *dn_suffix = NULL;
454 if (( progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
455 progname = argv[ 0 ];
460 while (( arg = getopt( argc, argv, "o:r:d:" )) != EOF ) {
466 replicas = (char **) ch_realloc( (char *) replicas, (unsigned long)
467 ( nreplicas + 2 ) * sizeof( char * ));
468 replicas[ nreplicas ] = optarg;
469 replicas[ nreplicas + 1 ] = NULL;
477 exit( EXIT_FAILURE );
481 if (( dn_suffix == NULL ) || ( nreplicas == 0 )) {
483 exit( EXIT_FAILURE );
486 if ( ofile == NULL ) {
487 /* Just write to stdout */
492 state = prevstate = ST_START;
495 if (( std_ps = ps_alloc( std_open )) == NULLPS ||
496 std_setup( std_ps, ofp ) != OK ) {
497 fprintf( stderr, "std_ps setup failed - help!\n" );
498 exit( EXIT_FAILURE );
500 if (( rps = ps_alloc( str_open )) == NULLPS ||
501 str_setup( rps, NULLCP, 0, 0 ) != OK ) {
502 fprintf( stderr, "rps setup failed - help!\n" );
503 exit( EXIT_FAILURE );
507 while ( gets( nbuf ) != NULL ) {
508 if ( nbuf[ 0 ] == '\0' ) {
509 if ( state == ST_NL1 ) {
510 if ( prevstate == ST_ARGS ) {
511 /* We've got an attribute sequence to print */
512 if ( modtype == TY_ADD ) {
513 print_as( as, 0, ofp );
515 print_as( as, modstate, ofp );
517 /* as_print( std_ps, as, EDBOUT ); */
522 fprintf( ofp, "\n" );
524 /* If writing to a file, release the lock */
525 if ( ofile != NULL ) {
526 lock_fclose( ofp, lfp );
535 /* See if we've got a line continuation to deal with */
536 nbuflen = strlen( nbuf );
537 if ( state == ST_CONCAT ) {
538 for ( p = nbuf; isspace( (unsigned char) *p ); p++, nbuflen-- )
540 buf = realloc( buf, buflen + nbuflen + 1 );
542 buflen += ( nbuflen );
547 buf = strdup( nbuf );
550 if ( buf[ buflen - 1 ] == '\\' ) {
551 if ( state != ST_CONCAT ) {
555 buf[ buflen - 1 ] = '\0';
558 } else if ( state == ST_CONCAT ) {
562 if ( state == ST_PUNT ) {
566 if ( state == ST_START ) {
568 * Acquire the file lock if writing to a file.
570 if ( ofile != NULL ) {
571 if (( ofp = lock_fopen( ofile, "a", &lfp )) == NULL ) {
573 exit( EXIT_FAILURE );
577 * If we have a changelog entry, then go ahead
578 * and write the replica: lines for the replog entry.
580 for ( i = 0; replicas[ i ] != NULL; i++ ) {
581 fprintf( ofp, "replica: %s\n", replicas[ i ] );
583 fprintf( ofp, "time: %ld\n", time( NULL ));
588 if ( state == ST_DN ) {
589 /* Second line - dn (quipu-style) of entry to be modified */
590 if (( ldapdn = dn2ldap( buf )) == NULL ) {
591 fprintf( ofp, "dn: (conversion failed)\n" );
593 fprintf( ofp, "dn: %s%s\n", ldapdn, dn_suffix );
600 if ( state == ST_TYPE ) {
603 if ( !strcmp( buf, "modify" )) {
604 modtype = TY_MODIFYTYPE;
605 fprintf( ofp, "changetype: modify\n" );
606 } else if ( !strcmp( buf, "add" )) {
608 fprintf( ofp, "changetype: add\n" );
610 } else if ( !strcmp( buf, "remove" )) {
612 fprintf( ofp, "changetype: delete\n" );
613 } else if ( !strcmp( buf, "newrdn" )) {
615 fprintf( ofp, "changetype: modrdn\n" );
623 if ( state == ST_ARGS ) {
626 fprintf( ofp, "newrdn: %s\n", buf );
628 case TY_REMOVE: /* No additional args */
631 as = as_combine( as, buf, 0 );
635 if ( buf[ 0 ] == '\0' ) {
638 print_as( as, modstate, ofp);
644 if (!strcmp( buf, "addvalues" )) {
646 print_as( as, modstate, ofp );
650 modstate = MOD_ADDVALUES;
652 } else if (!strcmp( buf, "removevalues" )) {
654 print_as( as, modstate, ofp );
658 modstate = MOD_REMOVEVALUES;
660 } else if (!strcmp( buf, "addattribute" )) {
662 print_as( as, modstate, ofp );
666 modstate = MOD_ADDATTRIBUTE;
668 } else if (!strcmp( buf, "removeattribute" )) {
670 print_as( as, modstate, ofp );
674 modstate = MOD_REMOVEATTRIBUTE;
677 switch ( modstate ) {
679 as = as_combine( as, buf, 0 );
681 case MOD_REMOVEVALUES:
682 as = as_combine( as, buf, 0 );
684 case MOD_ADDATTRIBUTE:
685 as = as_combine( as, buf, 0 );
687 case MOD_REMOVEATTRIBUTE:
688 fprintf( ofp, "delete: %s\n-\n", buf);
696 if ( ofile != NULL ) {
697 lock_fclose( ofp, lfp );
698 sprintf( nbuf, "%s.lock", ofile );
699 (void) unlink( nbuf );
701 exit( EXIT_SUCCESS );