]> git.sur5r.net Git - openldap/blob - servers/slapd/tools/chlog2replog.c
merged with autoconf branch
[openldap] / servers / slapd / tools / chlog2replog.c
1 /*
2  * Copyright (c) 1990, 1995 Regents of the University of Michigan.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of Michigan at Ann Arbor. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12
13 /*
14  * chlog2replog - read a quipu-style changelog on stdin and write a
15  * slapd-style replog on stdout, or write to a file, respecting
16  * slapd/slurpd locking conventions.
17  */
18
19 #include "portable.h"
20
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #include <ac/ctype.h>
25 #include <ac/string.h>
26
27 #include <quipu/commonarg.h>
28 #include <quipu/attrvalue.h>
29
30 #include "ldif.h"
31
32 static int dn2ldif();
33 static void de_t61();
34
35 extern FILE *lock_fopen( char *, char *, FILE ** );
36 extern int lock_fclose( FILE *, FILE * );
37 extern char *ch_realloc( char *, unsigned long ); 
38
39 short   ldap_dn_syntax;
40 PS      rps;
41 char    *progname;
42 int     ldap_syslog = 0;
43 int     ldap_syslog_level = 0;
44
45
46 #define ST_START        0
47 #define ST_DN           2
48 #define ST_TYPE         3
49 #define ST_ARGS         4
50 #define ST_NL1          5
51 #define ST_PUNT         6
52 #define ST_BAD          7
53 #define ST_CONCAT       8
54
55 #define TY_MODIFYTYPE   1
56 #define TY_ADD          2
57 #define TY_REMOVE       3
58 #define TY_NEWRDN       4
59 #define TY_PUNT         5
60 #define TY_MODIFYARGS   6
61
62 #define MOD_ADDVALUES           1
63 #define MOD_ADDATTRIBUTE        2
64 #define MOD_REMOVEATTRIBUTE     3
65 #define MOD_REMOVEVALUES        4
66
67
68 char *
69 dn2ldap( char *edbdn )
70 {
71     DN          dn;
72     PS          str_ps;
73     char        *ldapdn;
74     int         len;
75     static int  inited = 0;
76
77     if ( !inited ) {
78         /* load & initialize quipu syntax handlers */
79         quipu_syntaxes();
80
81 #ifdef LDAP_USE_PP
82         pp_quipu_init( progname );
83 #endif
84
85         dsap_init( NULL, NULL );
86
87         if (( ldap_dn_syntax = str2syntax( "DN" )) == 0 ) {
88             return( NULL );
89         }
90         inited = 1;
91     }
92
93     if (( dn = str2dn( edbdn )) == NULLDN ) {
94         return( NULL );
95     }
96
97     if (( str_ps = ps_alloc( str_open )) == NULLPS ||
98             str_setup( str_ps, NULLCP, 0, 0 ) == NOTOK ) {
99         dn_free( dn );
100         return( NULL );
101     }
102
103     if ( dn2ldif( str_ps, dn ) != 0 ) {
104         ps_free( str_ps );
105         dn_free( dn );
106         return( NULL );
107     }
108
109     dn_free( dn );
110     len = ( str_ps->ps_ptr - str_ps->ps_base );
111
112     if (( ldapdn = malloc( len + 1 )) == NULL ) {
113         ps_free( str_ps );
114         return( NULL );
115     }
116
117     memcpy( ldapdn, str_ps->ps_base, len );
118     ldapdn[ len ] = '\0';
119     ps_free( str_ps );
120     return( ldapdn );
121 }
122
123
124 #define SEPARATOR(c)    (c == ',' || c == ';')
125 #define SPACE(c)        (c == ' ' || c == '\n')
126
127 static int
128 dn2ldif( PS ps, DN dn )
129 {
130     RDN rdn;
131     int firstrdn, rc;
132     char        *value;
133     PS  rps;
134
135     if ( dn == NULLDN ) {
136         return( 0 );
137     }
138
139     if ( dn->dn_parent != NULLDN ) {
140         if (( rc = dn2ldif( ps, dn->dn_parent )) != 0 ) {
141             return( rc );
142         }
143         ps_print( ps, ", " );
144     }
145
146     if ( (rps = ps_alloc( str_open )) == NULLPS ||
147             str_setup( rps, NULLCP, 0, 0 ) == NOTOK ) {
148         return( -1 );
149     }
150
151     firstrdn = 1;
152     for ( rdn = dn->dn_rdn; rdn != NULLRDN; rdn = rdn->rdn_next ) {
153         if ( firstrdn ) {
154             firstrdn = 0;
155         } else {
156             ps_print( ps, " + " );
157         }
158
159         AttrT_print( ps, rdn->rdn_at, EDBOUT );
160         ps_print( ps, "=" );
161
162         if ( rdn->rdn_at->oa_syntax == ldap_dn_syntax ) {
163             if (( rc = dn2ldif( rps, (DN) rdn->rdn_av.av_struct )) != 0 ) {
164                 return( rc );
165             }
166             *rps->ps_ptr = '\0';
167             value = rps->ps_base;
168         } else {
169             AttrV_print( rps, &rdn->rdn_av, EDBOUT );
170             *rps->ps_ptr = '\0';
171             value = rps->ps_base;
172             de_t61( value, 0 );
173         }
174
175         /*
176          * ,+="\\\n all go in quotes.  " and \\ need to
177          * be preceeded by \\.
178          */
179
180         if ( strpbrk( value, ",+=\"\\\n" ) != NULL || SPACE( value[0] )
181                 || SPACE( value[max( strlen(value) - 1, 0 )] ) ) {
182             char        *p, *t, *tmp;
183             int specialcount;
184
185             ps_print( ps, "\"" );
186
187             specialcount = 0;
188             for ( p = value; *p != '\0'; p++ ) {
189                 if ( *p == '"' || *p == '\\' ) {
190                     specialcount++;
191                 }
192             }
193             if ( specialcount > 0 ) {
194                 tmp = smalloc( strlen( value ) + specialcount + 1 );
195                 for ( p = value, t = tmp; *p != '\0'; p++ ) {
196                     switch ( *p ) {
197                     case '"':
198                     case '\\':
199                             *t++ = '\\';
200                             /* FALL THROUGH */
201                     default:
202                             *t++ = *p;
203                     }
204                 }
205                 *t = '\0';
206                 ps_print( ps, tmp );
207                 free( tmp );
208             } else {
209                 ps_print( ps, value );
210             }
211
212             ps_print( ps, "\"" );
213         } else {
214             ps_print( ps, value );
215         }
216
217         rps->ps_ptr = rps->ps_base;
218     }
219
220     ps_free( rps );
221
222     return( 0 );
223 }
224
225 #define T61     "{T.61}"
226 #define T61LEN  6
227
228
229
230 static void
231 de_t61( s, t61mark )
232 char    *s;
233 int     t61mark;
234 {
235         char    *next = s;
236         int     c, hex;
237
238         while ( *s ) {
239                 switch ( *s ) {
240                 case '{' :
241                         if ( strncasecmp( s, T61, T61LEN) == 0 ) {
242                                 s += T61LEN;
243                                 if ( t61mark )
244                                         *next++ = '@';
245                         } else {
246                                 *next++ = *s++;
247                         }
248                         break;
249
250                 case '\\':
251                         c = *(s + 1);
252                         if ( c == '\n' ) {
253                                 s += 2;
254                                 if ( *s == '\t' )
255                                         s++;
256                                 break;
257                         }
258                         if ( isdigit( c ) )
259                                 hex = c - '0';
260                         else if ( c >= 'A' && c <= 'F' )
261                                 hex = c - 'A' + 10;
262                         else if ( c >= 'a' && c <= 'f' )
263                                 hex = c - 'a' + 10;
264                         else {
265                                 *next++ = *s++;
266                                 break;
267                         }
268                         hex <<= 4;
269                         c = *(s + 2);
270                         if ( isdigit( c ) )
271                                 hex += c - '0';
272                         else if ( c >= 'A' && c <= 'F' )
273                                 hex += c - 'A' + 10;
274                         else if ( c >= 'a' && c <= 'f' )
275                                 hex += c - 'a' + 10;
276                         else {
277                                 *next++ = *s++;
278                                 *next++ = *s++;
279                                 break;
280                         }
281
282                         *next++ = hex;
283                         s += 3;
284                         break;
285
286                 default:
287                         *next++ = *s++;
288                         break;
289                 }
290         }
291         *next = '\0';
292 }
293
294
295
296
297 char *
298 getattr( buf, sep )
299 char *buf;
300 char sep;
301 {
302     char *val;
303 #define RBSIZE 255
304     static char retbuf[ RBSIZE ];
305
306     if (( val = strchr( buf, sep )) != NULL ) {
307         strncpy( retbuf, buf, val - buf );
308         retbuf[ val - buf ] = '\0';
309     } else {
310         retbuf[ 0 ] = '\0';
311     }
312     return( retbuf );
313 }
314
315
316 char *
317 getattr_ldif( buf )
318 char *buf;
319 {
320     return( getattr( buf, ':' ));
321 }
322
323
324 char *
325 getattr_edb( buf )
326 char *buf;
327 {
328     return( getattr( buf, '=' ));
329 }
330
331 char *
332 getval( buf, sep )
333 char *buf;
334 char sep;
335 {
336     char *val;
337
338     if (( val = strchr( buf, sep )) != NULL ) {
339         return( strdup( ++val ));
340     } else {
341         return( NULL );
342     }
343 }
344
345 char *
346 getval_ldif( buf )
347 char *buf;
348 {
349     return( getval( buf, ':' ));
350 }
351
352
353 char *
354 getval_edb( buf )
355 char *buf;
356 {
357     return( getval( buf, '=' ));
358 }
359
360
361
362
363 int
364 isDNsyntax( attr )
365 char *attr;
366 {
367     oid_table_attr *p, *name2attr();
368
369     p = name2attr( attr );
370     if ( p == ( oid_table_attr * ) 0 ) {
371         return( -1 );
372     }
373     if ( p->oa_syntax == ldap_dn_syntax ) {
374         return( 1 );
375     } else {
376         return( 0 );
377     }
378 }
379
380
381
382 void
383 print_as( as, modtype, ofp )
384 Attr_Sequence as;
385 int modtype;
386 FILE *ofp;
387 {
388     Attr_Sequence p;
389     AV_Sequence av;
390     char *attrname, *tmpdn, *obuf;
391
392     p = as;
393     for ( p = as; p != NULLATTR; p = p->attr_link) {
394         rps->ps_ptr = rps->ps_base;
395         AttrT_print( rps,  p->attr_type, EDBOUT );
396         *rps->ps_ptr = '\0';
397         attrname = strdup( rps->ps_base  );
398         if ( modtype != 0 ) {
399             switch ( modtype ) {
400             case MOD_ADDVALUES:
401             case MOD_ADDATTRIBUTE:
402                 fprintf( ofp, "add: %s\n", attrname );
403                 break;
404             case MOD_REMOVEATTRIBUTE:
405             case MOD_REMOVEVALUES:
406                 fprintf( ofp, "delete: %s\n", attrname );
407                 break;
408             default:
409                 break;
410             }
411         }
412         for ( av = p->attr_value; av != NULLAV; av = av->avseq_next ) {
413             rps->ps_ptr = rps->ps_base;
414             AttrV_print( rps, &av->avseq_av, EDBOUT );
415             *rps->ps_ptr = '\0';
416             de_t61( rps->ps_base, 0 );
417             if ( isDNsyntax( attrname )) {
418                 tmpdn = dn2ldap( rps->ps_base );
419                 obuf = ldif_type_and_value( attrname, tmpdn,
420                         strlen( tmpdn ));
421                 free( tmpdn );
422             } else {
423                 obuf = ldif_type_and_value( attrname, rps->ps_base,
424                         strlen( rps->ps_base ));
425             }
426             if ( obuf != NULL ) {
427                 fputs( obuf, ofp );
428                 free( obuf );
429             }
430         }
431         if ( modtype != 0 ) {
432             fprintf( ofp, "-\n" );
433         }
434         free( attrname );
435     }
436 }
437
438
439
440 void
441 usage( char *name )
442 {
443     fprintf( stderr, "usage: %s -d dn-suffix -r replica:port ", name );
444     fprintf( stderr, "[-r replica:port...] [-o outputfile]\n" );
445 }
446
447
448
449 main( int argc, char **argv )
450 {
451     char                *ldapdn, nbuf[ 4096 ], *buf, *p;
452     int                 state, prevstate, modstate, modtype, i;
453     int                 buflen, nbuflen;
454     Attr_Sequence       as;
455     PS                  std_ps;
456     int                 arg;
457     char                *ofile = NULL;
458     FILE                *ofp, *lfp;
459
460     extern char         *optarg;
461     char                **replicas = NULL;
462     int                 nreplicas = 0;
463     char                *dn_suffix = NULL;
464
465     if (( progname = strrchr( argv[ 0 ], '/' )) == NULL ) {
466         progname = argv[ 0 ];
467     } else {
468         ++progname;
469     }
470
471     while (( arg = getopt( argc, argv, "o:r:d:" )) != EOF ) {
472         switch( arg ) {
473         case 'o':
474             ofile = optarg;
475             break;
476         case 'r':
477             replicas = (char **) ch_realloc( (char *) replicas, (unsigned long)
478                     ( nreplicas + 2 ) * sizeof( char * ));
479             replicas[ nreplicas ] = optarg;
480             replicas[ nreplicas + 1 ] = NULL;
481             nreplicas++;
482             break;
483         case 'd':
484             dn_suffix = optarg;
485             break;
486         default:
487             usage( progname );
488             exit( 1 );
489         }
490     }
491
492     if (( dn_suffix == NULL ) || ( nreplicas == 0 )) {
493         usage( progname );
494         exit( 1 );
495     }
496
497     if ( ofile == NULL ) {
498         /* Just write to stdout */
499         ofp = stdout;
500     }
501
502
503     state = prevstate = ST_START;
504     buf = NULL;
505     as = NULL;
506     if (( std_ps = ps_alloc( std_open )) == NULLPS ||
507             std_setup( std_ps, ofp ) != OK ) {
508         fprintf( stderr, "std_ps setup failed - help!\n" );
509         exit( 1 );
510     }
511     if (( rps = ps_alloc( str_open )) == NULLPS ||
512             str_setup( rps, NULLCP, 0, 0 ) != OK ) {
513         fprintf( stderr, "rps setup failed - help!\n" );
514         exit( 1 );
515     }
516
517
518     while ( gets( nbuf ) != NULL ) {
519         if ( nbuf[ 0 ] == '\0' ) {
520             if ( state == ST_NL1 ) {
521                 if ( prevstate == ST_ARGS ) {
522                     /* We've got an attribute sequence to print */
523                     if ( modtype == TY_ADD ) {
524                         print_as( as, 0, ofp ); 
525                     } else {
526                         print_as( as, modstate, ofp ); 
527                     }
528                     /* as_print( std_ps, as, EDBOUT ); */
529                     as_free( as );
530                     as = NULL;
531                 }
532                 state = ST_START;
533                 fprintf( ofp, "\n" );
534                 fflush( ofp );
535                 /* If writing to a file, release the lock */
536                 if ( ofile != NULL ) {
537                     lock_fclose( ofp, lfp );
538                 }
539             } else {
540                 prevstate = state;
541                 state = ST_NL1;
542             }
543             continue;
544         }
545
546         /* See if we've got a line continuation to deal with */
547         nbuflen = strlen( nbuf );
548         if ( state == ST_CONCAT ) {
549             for ( p = nbuf; isspace( *p ); p++, nbuflen-- ); /* skip space */
550             buf = realloc( buf, buflen + nbuflen + 1 );
551             strcat( buf, p );
552             buflen += ( nbuflen );
553         } else {
554             if ( buf != NULL ) {
555                 free( buf );
556             }
557             buf = strdup( nbuf );
558             buflen = nbuflen;
559         }
560         if ( buf[ buflen - 1 ] == '\\' ) {
561             if ( state != ST_CONCAT ) {
562                 prevstate = state;
563             }
564             state = ST_CONCAT;
565             buf[ buflen - 1 ] = '\0';
566             buflen--;
567             continue;
568         } else if ( state == ST_CONCAT ) {
569             state = prevstate;
570         }
571
572         if ( state == ST_PUNT ) {
573             continue;
574         }
575
576         if ( state == ST_START ) {
577             /*
578              * Acquire the file lock if writing to a file.
579              */
580             if ( ofile != NULL ) {
581                 if (( ofp = lock_fopen( ofile, "a", &lfp )) == NULL ) {
582                     perror( "open" );
583                     exit( 1 );
584                 }
585             }
586             /*
587              * If we have a changelog entry, then go ahead
588              * and write the replica: lines for the replog entry.
589              */
590             for ( i = 0; replicas[ i ] != NULL; i++ ) {
591                 fprintf( ofp, "replica: %s\n", replicas[ i ] );
592             }
593             fprintf( ofp, "time: %ld\n", time( NULL ));
594             state = ST_DN;
595             continue;
596         }
597
598         if ( state == ST_DN ) {
599             /* Second line - dn (quipu-style) of entry to be modified */
600             if (( ldapdn = dn2ldap( buf )) == NULL ) {
601                 fprintf( ofp, "dn: (conversion failed)\n" );
602             } else {
603                 fprintf( ofp, "dn: %s%s\n", ldapdn, dn_suffix );
604                 free( ldapdn );
605             }
606             state = ST_TYPE;
607             continue;
608         }
609
610         if ( state == ST_TYPE ) {
611             state = ST_ARGS;
612             modstate = 0;
613             if ( !strcmp( buf, "modify" )) {
614                 modtype = TY_MODIFYTYPE;
615                 fprintf( ofp, "changetype: modify\n" );
616             } else if ( !strcmp( buf, "add" )) {
617                 modtype = TY_ADD;
618                 fprintf( ofp, "changetype: add\n" );
619                 as = NULL;
620             } else if ( !strcmp( buf, "remove" )) {
621                 modtype = TY_REMOVE;
622                 fprintf( ofp, "changetype: delete\n" );
623             } else if ( !strcmp( buf, "newrdn" )) {
624                 modtype = TY_NEWRDN;
625                 fprintf( ofp, "changetype: modrdn\n" );
626             } else {
627                 modtype = TY_PUNT;
628                 state = ST_BAD;
629             }
630             continue;
631         }
632
633         if ( state == ST_ARGS ) {
634             switch ( modtype ) {
635             case TY_NEWRDN:
636                 fprintf( ofp, "newrdn: %s\n", buf );
637                 break;
638             case TY_REMOVE:     /* No additional args */
639                 break;
640             case TY_ADD:
641                 as = as_combine( as, buf, 0 );
642                 break;
643             case TY_MODIFYTYPE:
644             case TY_MODIFYARGS:
645                 if ( buf[ 0 ] == '\0' ) {
646                     state == ST_NL1;
647                     if ( as != NULL ) {
648                         print_as( as, modstate, ofp);
649                         as_free( as );
650                         as = NULL;
651                     }
652                     continue;
653                 }
654                 if (!strcmp( buf, "addvalues" )) {
655                     if ( as != NULL ) {
656                         print_as( as, modstate, ofp );
657                         as_free( as );
658                         as = NULL;
659                     }
660                     modstate = MOD_ADDVALUES;
661                     continue;
662                 } else if (!strcmp( buf, "removevalues" )) {
663                     if ( as != NULL ) {
664                         print_as( as, modstate, ofp );
665                         as_free( as );
666                         as = NULL;
667                     }
668                     modstate = MOD_REMOVEVALUES;
669                     continue;
670                 } else if (!strcmp( buf, "addattribute" )) {
671                     if ( as != NULL ) {
672                         print_as( as, modstate, ofp );
673                         as_free( as );
674                         as = NULL;
675                     }
676                     modstate = MOD_ADDATTRIBUTE;
677                     continue;
678                 } else if (!strcmp( buf, "removeattribute" )) {
679                     if ( as != NULL ) {
680                         print_as( as, modstate, ofp );
681                         as_free( as );
682                         as = NULL;
683                     }
684                     modstate = MOD_REMOVEATTRIBUTE;
685                     continue;
686                 } 
687                 switch ( modstate ) {
688                 case MOD_ADDVALUES:
689                     as = as_combine( as, buf, 0 );
690                     break;
691                 case MOD_REMOVEVALUES:
692                     as = as_combine( as, buf, 0 );
693                     break;
694                 case MOD_ADDATTRIBUTE:
695                     as = as_combine( as, buf, 0 );
696                     break;
697                 case MOD_REMOVEATTRIBUTE:
698                     fprintf( ofp, "delete: %s\n-\n", buf);
699                     break;
700                 }
701             }
702             continue;
703         }
704     }
705
706     if ( ofile != NULL ) {
707         lock_fclose( ofp, lfp );
708         sprintf( nbuf, "%s.lock", ofile );
709         (void) unlink( nbuf );
710     }
711     exit( 0 );
712 }