modules/ud/ud_process_stream.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. ud_parse_init
  2. ud_parse_free
  3. split_attribute
  4. reorder_attributes
  5. each_attribute_print
  6. print_object
  7. escape_apostrophes
  8. line_type
  9. UD_parse_object
  10. report_transaction
  11. process_nrtm
  12. process_updates
  13. process_transaction
  14. UD_process_stream

   1 /***************************************
   2   $Revision: 1.36 $
   3 
   4   Functions to process data stream( file, network socket, etc.)
   5 
   6   Status: NOT REVUED, NOT TESTED
   7 
   8  Author(s):       Chris Ottrey, Andrei Robachevsky
   9 
  10   ******************/ /******************
  11   Modification History:
  12         andrei (17/01/2000) Created.
  13   ******************/ /******************
  14   Copyright (c) 2000                              RIPE NCC
  15  
  16   All Rights Reserved
  17   
  18   Permission to use, copy, modify, and distribute this software and its
  19   documentation for any purpose and without fee is hereby granted,
  20   provided that the above copyright notice appear in all copies and that
  21   both that copyright notice and this permission notice appear in
  22   supporting documentation, and that the name of the author not be
  23   used in advertising or publicity pertaining to distribution of the
  24   software without specific, written prior permission.
  25   
  26   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  27   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  28   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  29   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  30   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  31   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  32  ***************************************/
  33 #include <sys/types.h>
  34 #include <sys/socket.h>
  35 #include <netdb.h>
  36 #include <arpa/inet.h>
  37 #include <unistd.h>
  38 #include <sys/stat.h>
  39 #include <fcntl.h>
  40 #include <string.h>
  41 #include "constants.h"
  42 #include "query_command.h"
  43 #include "ud.h"
  44 #include "ud_int.h"
  45 #include "timediff.h"
  46  
  47 typedef enum _Line_Type_t {
  48  LINE_ATTRIBUTE,
  49  LINE_COMMENT,
  50  LINE_EMPTY,
  51  LINE_EOF,
  52  LINE_ADD,
  53  LINE_UPD,
  54  LINE_DEL,
  55  LINE_OVERRIDE_ADD,
  56  LINE_OVERRIDE_UPD,
  57  LINE_OVERRIDE_DEL,
  58  LINE_PLUS
  59 } Line_Type_t;
  60 
  61 /* Maximum number of objects(serials) we can consume at a time */
  62 #define SBUNCH 1000
  63 
  64 static int report_transaction(Transaction_t *tr, Log_t *log, char *obj_name, char *reason);
  65 static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation);
  66 static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation);
  67 static int process_transaction(UD_stream_t *ud_stream,Object_t *obj,char *object_name,nic_handle_t *nh, int operation);
  68                                                                                                 
  69 /* Delimiters that separate list members, both RPS(,) and legacy( ) */
  70 #define ATTR_DELIMITERS " ,"
  71 
  72 
  73 void ud_parse_init(Obj_parse_t *parse){
     /* [<][>][^][v][top][bottom][index][help] */
  74      bzero(parse, sizeof(Obj_parse_t));
  75      parse->start_object=1;     
  76 }
  77 
  78 void ud_parse_free(Obj_parse_t *parse){
     /* [<][>][^][v][top][bottom][index][help] */
  79      free(parse->object_name);
  80 }
  81 
  82 
  83 
  84 static GSList *split_attribute(GSList *attr_list, A_Type_t attr_type, char *attr_value){
     /* [<][>][^][v][top][bottom][index][help] */
  85 char *token;
  86 char *split;
  87 char *value, *n;
  88 Attribute_t *attr_split;
  89 GSList *the_list = attr_list;
  90 
  91   /* check for line continuation (+) */
  92   if (strncmp(attr_value, "+", 1) == 0) attr_value++;
  93   /* check for end-of-line comments */
  94   n = index(attr_value, '#');
  95       /* if there is no comment check for trailing \n */
  96   if(n == NULL) n = index(attr_value, '\n');
  97   /* now copy the clean value into the attribute */
  98   if(n == NULL) value = g_strdup(attr_value); 
  99   else  value = g_strndup(attr_value, (n - attr_value));
 100      
 101   token=value;
 102   while((split=strsep(&token, ATTR_DELIMITERS))){
 103      attr_split = attribute_new1(attr_type, split);
 104      if (attr_split) the_list = g_slist_append(the_list, attr_split);
 105   }
 106   free(value);
 107  return(the_list);
 108 }
 109 
 110 /************************************************************
 111 *                                                           *
 112 * The function to reorder attributes in the List            *
 113 * nic-hdl and mnt-by should come first                      *
 114 *                                                           *
 115 * should return 0 if they are equal, a negative value if    * 
 116 * the first element comes before the second, or a positive  *
 117 * value if the first element comes after the second         *
 118 *                                                           *
 119 ************************************************************/
 120 static gint reorder_attributes(const void *element1, const void *element2)
     /* [<][>][^][v][top][bottom][index][help] */
 121 {
 122 Attribute_t *attr1 = (Attribute_t *)element1;
 123 Attribute_t *attr2 = (Attribute_t *)element2;
 124 gint order = -1;
 125   
 126   if(attr2->type == A_MB) order= 1;
 127   if(attr1->type == A_MB) order= -1;
 128   if(attr2->type == A_NH) order= 1;
 129   if(attr1->type == A_NH) order= -1;
 130 
 131   return(order);
 132 
 133 }
 134 
 135 /* XXX */
 136 static void each_attribute_print(void *element_data, void *tr_ptr)
     /* [<][>][^][v][top][bottom][index][help] */
 137 {
 138 
 139 Attribute_t *attr = (Attribute_t *)element_data;
 140 
 141  fprintf(stderr, "[%d|%s]\n", attr->type, attr->value);
 142 
 143 }
 144 
 145 /* XXX */
 146 static void print_object(Object_t *obj)
     /* [<][>][^][v][top][bottom][index][help] */
 147 {
 148   g_slist_foreach(obj->attributes, each_attribute_print, NULL); 
 149   fprintf(stderr, ">>>>>\n%s\n", obj->object->str);
 150 }
 151 
 152 
 153 /******************************************************************
 154 * GString *escape_apostrophes()                                   *
 155 * Escapes apostrophes in the text so they do not confuse printf   *
 156 * functions and don't corrupt SQL queries                         *
 157 *                                                                 *
 158 * *****************************************************************/
 159 GString *escape_apostrophes(GString *text) {
     /* [<][>][^][v][top][bottom][index][help] */
 160   int i;
 161   for (i=0; i < text->len; i++) {
 162     if ((text->str[i] == '\'') || (text->str[i] == '\\')) {
 163       text = g_string_insert_c(text, i, '\\');
 164       i++;
 165     }
 166   }
 167  return(text); 
 168 } /* escape_apostrophes() */
 169 
 170 
 171 /******************************************************************
 172 * Line_Type_t line_type(e)                                        *
 173 * Determines the line type analysing the first letters            *
 174 *                                                                 *
 175 * ****************************************************************/
 176 static Line_Type_t line_type(const char *line) {
     /* [<][>][^][v][top][bottom][index][help] */
 177   Line_Type_t result = -1;
 178 
 179   if (strncmp(line, "# EOF", 4) == 0) {
 180     result = LINE_EOF;
 181   }
 182   else if (strncmp(line, "#", 1) == 0) {
 183     result = LINE_COMMENT;
 184   }
 185   else if (strcmp(line, "\n") == 0) {
 186     result = LINE_EMPTY;
 187   }
 188   else if (strcmp(line, "ADD\n") == 0) {
 189     result = LINE_ADD;
 190   }
 191   else if (strcmp(line, "UPD\n") == 0) {
 192     result = LINE_UPD;
 193   }
 194   else if (strcmp(line, "DEL\n") == 0) {
 195     result = LINE_DEL;
 196   }
 197   else if (strcmp(line, "ADD_OVERRIDE\n") == 0) {
 198     result = LINE_OVERRIDE_ADD;
 199   }
 200   else if (strcmp(line, "UPD_OVERRIDE\n") == 0) {
 201     result = LINE_OVERRIDE_UPD;
 202   }
 203   else if (strcmp(line, "DEL_OVERRIDE\n") == 0) {
 204     result = LINE_OVERRIDE_DEL;
 205   }
 206   else if (strncmp(line, "+", 1) == 0) {
 207     result = LINE_PLUS;
 208   }  
 209   else {
 210     result = LINE_ATTRIBUTE;
 211   }
 212 
 213   return result;
 214 } /* line_type() */
 215 
 216 /******************************************************************
 217 * Object_t *UD_parse_object()                                     *
 218 *                                                                 *
 219 * Parses the object accepting line by line                        *
 220 *                                                                 *
 221 * ****************************************************************/
 222 Object_t *UD_parse_object(SQ_connection_t *sql_connection, Obj_parse_t *parse, char *line_buff)
     /* [<][>][^][v][top][bottom][index][help] */
 223 {
 224 GString *g_line_buff;
 225 Attribute_t *class_attr, *attr;
 226 char *a_value, *ptr;
 227 char nic[MAX_NH_LENGTH];
 228  
 229  
 230   if (parse->start_object == 1) {
 231    parse->obj = object_new(line_buff);
 232   }
 233   if (parse->obj) {
 234 
 235     if ((g_line_buff = g_string_sized_new(STR_XXL)) == NULL){ 
 236       fprintf(stderr, "E: cannot allocate gstring\n"); 
 237       die; 
 238     }
 239   
 240    g_string_sprintf(g_line_buff, "%s", line_buff);
 241    /* escape apostrophes in the input line */
 242    g_line_buff=escape_apostrophes(g_line_buff);
 243    
 244    if(parse->start_object == 1){
 245    /* If this is the first attribute(==object name/type) */   
 246     parse->start_object=0;
 247     parse->object_name = g_strndup(g_line_buff->str, g_line_buff->len);
 248      *(parse->object_name+g_line_buff->len-1)='\0';
 249     fprintf(stderr, "D: object: [%s] ", parse->object_name);
 250   /* Create an attribute - the first one determines a class */
 251     parse->class_attr_list=NULL; /* Initialize the list that will hold splitted class attribute */
 252     class_attr = attribute_new(g_line_buff->str);
 253     if (class_attr == NULL) die; /* Should not happen */
 254     if((class_attr->type==A_PN)||(class_attr->type==A_RO)){
 255    /* split names */  
 256       parse->class_attr_list = split_attribute(parse->class_attr_list, class_attr->type, class_attr->value);  
 257       attribute_free(class_attr, NULL);
 258     } else {
 259       parse->class_attr_list = g_slist_append(parse->class_attr_list, class_attr); 
 260     }
 261   /* do nothing more with this attribute - we will prepend it at the end */
 262    }
 263    else {
 264      attr = attribute_new(g_line_buff->str);
 265         
 266      if (attr) {
 267        parse->a_type=attr->type;   
 268        a_value=attr->value;
 269        if(parse->a_type==A_NH) {
 270           /*  Parse the string into nh structure */
 271           /*  In case of an AUTO NIC handle check the ID in the database */
 272           /* Possible errors leave to core processing */
 273           if(NH_parse(attr->value, &parse->nh_ptr) == 0) { 
 274 /*         fprintf(stderr, "D:parsing NIC: [%s]\n", attr->value); */
 275            /* Check if we can allocate it */  
 276             if(NH_check(parse->nh_ptr, sql_connection)>0){
 277             /* Convert nh to the database format */  
 278               NH_convert(nic, parse->nh_ptr);
 279 /*      fprintf(stderr, "D:NIC:[%s]\n", nic); */
 280               /* Replace NIC handle in the string which is copied to the text object */
 281               sprintf(line_buff, g_line_buff->str);
 282               ptr = strstr(line_buff, attr->value);
 283               /* parse new attribute string */
 284               strcpy(ptr, nic);
 285               g_string_sprintf(g_line_buff, line_buff);
 286               g_string_sprintfa(g_line_buff, "\n");
 287               /* Update the attribute */
 288               attribute_upd(attr, attr->type, nic); 
 289 /*      fprintf(stderr, "D:attribute updated\n"); */
 290             }
 291           }
 292        } /* NHR stuff */
 293      }
 294      else 
 295        a_value=g_line_buff->str;
 296 
 297      if (parse->a_type>=0) { /* This indicates that the input line contains the value of the attribute */
 298          switch (parse->a_type) {
 299             /*these attributes may appear several on the line - split them*/   
 300             case A_PN: /* person */
 301             case A_RO: /* role */
 302             case A_MR: /* mbrs-by-ref */
 303             case A_MB: /* mnt-by */
 304             case A_MO: /* member-of */
 305             case A_SD: /* sub-dom */
 306             case A_RZ: /* rev-srv */
 307             case A_NS: /* nserver */
 308                 parse->obj->attributes = split_attribute(parse->obj->attributes, parse->a_type, a_value);
 309                 if (attr) attribute_free(attr, NULL);
 310              attr=NULL;
 311              break; 
 312             default: break;  
 313          }
 314 /*       g_string_sprintfa(obj->object, "%s", g_line_buff->str); */
 315          if(attr)parse->obj->attributes = g_slist_append(parse->obj->attributes, attr);  
 316      }
 317    } /* if not start_object (not the first/class attribute) */
 318    /* copy the line into object no matter whether it is an attribute or not (continualtion, etc.) */
 319    g_string_sprintfa(parse->obj->object, "%s", g_line_buff->str);
 320    g_string_free(g_line_buff, TRUE);
 321   }/* if (obj) */
 322     return(parse->obj);
 323 }
 324 
 325 /******************************************************************
 326 * report_transaction()                                            *
 327 *                                                                 * 
 328 * Prints error report to the log                                  *
 329 *                                                                 *
 330 * reason - additional message that will be included               *
 331 *                                                                 *
 332 * *****************************************************************/
 333 static int report_transaction(Transaction_t *tr, Log_t *log, char *obj_name, char *reason)
     /* [<][>][^][v][top][bottom][index][help] */
 334 {
 335 int result=0;
 336 
 337  if(tr->succeeded==0) {
 338   result=tr->error;
 339   log->num_failed++;
 340   fprintf(stderr, "FAILED[%s][%s(%d)](%d/%d)\n ", obj_name, reason, result, log->num_failed, (log->num_failed)+(log->num_ok)); 
 341   fprintf(log->logfile, "*FAILED[%s][%s](%d/%d)\n ", obj_name, reason, log->num_failed, (log->num_failed)+(log->num_ok));
 342   if(result & ERROR_U_MEM) fprintf(log->logfile, "\t*Memory allocation error\n");
 343   if(result & ERROR_U_DBS) fprintf(log->logfile, "\t*Database (SQL) error\n");
 344   if(result & ERROR_U_OBJ) fprintf(log->logfile, "\t*Object (RF) error\n");
 345   if(result & ERROR_U_AUT) fprintf(log->logfile, "\t*Object authentication error\n");
 346   if(result & ERROR_U_BADOP) fprintf(log->logfile, "\t*Bad operation\n");
 347   if(result & ERROR_U_COP) fprintf(log->logfile, "\t*Conflicting operation\n");
 348   if(result & ERROR_U_NSUP) fprintf(log->logfile, "\t*Object of this type is not supported\n");
 349   if(result & ERROR_U_BUG) fprintf(log->logfile, "\t*Software bug - report to <ripe-dbm@ripe.net>\n");
 350   fprintf(log->logfile, "%s", (tr->error_script)->str);
 351   result=(-1)*result;                                                
 352   fflush(log->logfile);
 353  }
 354  else {
 355   result=1;
 356   log->num_ok++;
 357   fprintf(stderr, "OK(%d/%d)\n", log->num_ok, (log->num_failed)+(log->num_ok));
 358  }
 359                                                                                                                                                 
 360  return(result);
 361 }/* report_transaction() */
 362 
 363 
 364 
 365 /************************************************************
 366 * process_nrtm()                                            *
 367 *                                                           *
 368 * Process object in NRTM client mode                        *
 369 *                                                           *
 370 * nrtm - pointer to _nrtm structure                         *
 371 * log - pointer to Log_t structure                          *
 372 * object_name - name of the object                          * 
 373 * operation - operation code (OP_ADD/OP_DEL)                *
 374 *                                                           *
 375 * Returns:                                                  *
 376 * 1  - okay                                                 *
 377 * <0 - error                                                *
 378 *                                                           *
 379 ************************************************************/
 380 
 381 static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation)
     /* [<][>][^][v][top][bottom][index][help] */
 382 {
 383 int result=0;
 384 int dummy=0;
 385 struct _nrtm *nrtm = ud_stream->nrtm;
 386 Log_t *log_ptr= &(ud_stream->log);
 387 
 388   /* We allow NRTM updates for some inconsistent objects                  */
 389   /* One of the examples is reference by name which looks like nic-handle */
 390   /* For this purpose we allow dummy creation when updating an object     */
 391   /* We also check for dummy allowance when deleting an object            */
 392   /* this is done to allow deletion of person objects referenced by name  */
 393 
 394   tr->dummy=1;
 395   
 396   switch (operation) {
 397   
 398   case OP_ADD:
 399     if(nrtm->tr){ /* DEL ADD => saved*/
 400       if(tr->object_id==0) { 
 401         /* object does not exist in the DB */      
 402         object_process(nrtm->tr); /* delete the previous(saved) object*/
 403         result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)");
 404         /* create DEL serial */
 405         create_serial(nrtm->tr);
 406         object_free(nrtm->tr->object);
 407         transaction_free(nrtm->tr); nrtm->tr=NULL;
 408         /* Create an object and update NHR */
 409         tr->action=(TA_CREATE | TA_UPD_NHR);
 410 /*      fprintf(stderr,"CREATE next\n"); */
 411         object_process(tr); /* create a new one*/
 412         result=report_transaction(tr, log_ptr, object_name, "NRTM:ADD:While creating new");
 413         /* create ADD serial */
 414         create_serial(tr);
 415       }
 416       else { 
 417       /* object already exists in the DB - update or dummy replacement*/
 418         if(tr->object_id==nrtm->tr->object_id) {/*compare the two, may be we may collapse operations*/
 419           object_free(nrtm->tr->object);
 420           transaction_free(nrtm->tr); nrtm->tr=NULL;
 421 /*        fprintf(stderr,"DEL-ADD ->> UPDATE\n");*/
 422           tr->action=TA_UPDATE;
 423           object_process(tr);
 424           report_transaction(tr, log_ptr, object_name,"NRTM:upd");
 425           result=report_transaction(tr, log_ptr, object_name,"NRTM:upd");
 426           /* create DEL+ADD serial records */
 427           tr->action=TA_DELETE; create_serial(tr);
 428           tr->action=TA_CREATE; create_serial(tr);
 429         }
 430         else { /* this should be a dummy object in the database(that we are going to replace with the real one */
 431         /* or an interleaved operation*/
 432 /*        fprintf(stderr,"DEL previous\n");*/
 433           object_process(nrtm->tr); /* delete the previous(saved) object*/
 434           result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)");
 435           /* create a DEL serial record */
 436           create_serial(nrtm->tr);
 437           object_free(nrtm->tr->object);
 438           transaction_free(nrtm->tr); nrtm->tr=NULL;
 439           tr->action=TA_UPDATE;
 440           dummy=isdummy(tr);
 441           /* If we are replacing dummy with a real object update NHR */
 442           if(dummy==1) tr->action |= TA_UPD_NHR;
 443 /*        fprintf(stderr,"UPDATE next(dummy)\n"); */
 444           object_process(tr); /* create a new one*/
 445           result=report_transaction(tr, log_ptr, object_name, "NRTM:ADD:While creating new");
 446           /* For serials this is CREATE operation */
 447           if(dummy==1) tr->action=TA_CREATE;
 448           /* create ADD serial record */
 449           create_serial(tr);
 450         }
 451       }
 452     }
 453     else { /* ADD ADD =>brand new object*/
 454       if(tr->object_id==0) {
 455 /*      fprintf(stderr,"CREATE new\n");*/
 456         /* Create an object and update NHR */
 457         tr->action=(TA_CREATE | TA_UPD_NHR);
 458         object_process(tr);
 459         result=report_transaction(tr, log_ptr, object_name,"NRTM:ADD:While creating new");
 460         /* create ADD serial */
 461         create_serial(tr);
 462       }
 463       else { /* object already exists in the database */
 464         /* this may happen because of dummies*/
 465         /* or with some implementations of mirroring protocol that have atomic update */
 466         /* instead of add + del */
 467 /*      fprintf(stderr,"CREATE new\n");*/
 468         tr->action=TA_UPDATE;
 469         dummy=isdummy(tr);
 470  /* If we are replacing dummy with a real object update NHR */
 471         if(dummy==1) tr->action |= TA_UPD_NHR;
 472         object_process(tr);
 473         result=report_transaction(tr, log_ptr, object_name,"NRTM:ADD:While creating new");
 474         if(dummy==1) tr->action=TA_CREATE; /* we don't want to generate DEL serial for dummy replacement*/
 475         /* create ADD serial record */
 476         create_serial(tr);
 477       } 
 478     }
 479     break;
 480     
 481   case OP_DEL:
 482     if(nrtm->tr){ /*DEL DEL =>saved */
 483 /*    fprintf(stderr,"DEL previous\n");*/
 484       object_process(nrtm->tr); /* delete the previous(saved) object*/
 485       result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved) object");
 486       /* create DEL serial record */
 487       create_serial(nrtm->tr);
 488       object_free(nrtm->tr->object);
 489       transaction_free(nrtm->tr); nrtm->tr=NULL;
 490     }
 491     if(tr->object_id>0){ /* save the object*/
 492       fprintf(stderr,"SAVED\n");
 493       tr->action=TA_DELETE;
 494       nrtm->tr=tr;
 495       strcpy(nrtm->object_name, object_name);
 496       return(1);
 497     }
 498     else { /* this is an error - Trying to DEL non-existing object*/
 499       tr->succeeded=0; tr->error|=ERROR_U_COP;
 500       result=report_transaction(tr, log_ptr, object_name, "NRTM:OOS:Trying to DEL non-existing object");
 501       /* create DEL serial record anyway */
 502       tr->action=TA_DELETE;
 503       create_serial(tr);
 504     }
 505     break;
 506   
 507   default:
 508     tr->succeeded=0; tr->error |=ERROR_U_BADOP;
 509     break;  
 510   }
 511 
 512  /* Free resources */  
 513   object_free(tr->object);
 514   transaction_free(tr);
 515   
 516   return(result);
 517 } /* process_nrtm() */
 518 
 519 
 520 
 521 /************************************************************
 522 * process_updates()                                         *
 523 *                                                           *
 524 * Process object in update mode                             *
 525 *                                                           *
 526 * ud_stream - pointer to UD_stream structure                *
 527 * object_name - name of the object                          *
 528 * operation - operation code (OP_ADD/OP_DEL)                *
 529 *                                                           *
 530 * Note:                                                     *
 531 * Frees tr and tr->obj on exit                              *
 532 *                                                           *
 533 * Returns:                                                  *
 534 * 1  - okay                                                 *
 535 * <0 - error                                                *
 536 *                                                           * 
 537 ************************************************************/
 538 
 539 static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation)
     /* [<][>][^][v][top][bottom][index][help] */
 540 {
 541 int result=0;
 542 Log_t *log_ptr= &(ud_stream->log);
 543 int dummy=0;
 544 
 545     switch(operation) {
 546     /* Compare operations and report an error if they do not match */    
 547     case OP_ADD:
 548              if(tr->object_id!=0) { /* trying to create, but object exists */
 549         tr->succeeded=0; tr->error|=ERROR_U_COP;
 550       } else {
 551        /* Action: create the object and update NHR */
 552         tr->action=(TA_CREATE | TA_UPD_NHR);
 553         object_process(tr);
 554       }
 555       break;
 556     case OP_UPD:
 557       if(tr->object_id==0) { /* trying to update non-existing object*/
 558         tr->succeeded=0; tr->error|=ERROR_U_COP;
 559       } else {
 560         tr->action=TA_UPDATE;
 561         dummy=isdummy(tr);
 562         /* If we are replacing dummy with a real object update NHR */
 563         if(dummy==1) tr->action |= TA_UPD_NHR;
 564         object_process(tr);
 565       }
 566       break;
 567 
 568     case OP_DEL:        
 569       if(tr->object_id==0) { /* trying t delete non-existing object*/
 570         tr->succeeded=0; tr->error|=ERROR_U_COP;
 571       } else {
 572         tr->action=TA_DELETE;
 573         object_process(tr);
 574       }
 575       break;
 576                 
 577     default:                
 578       /* bad operation for this mode if not standalone */
 579       if(tr->standalone) {
 580         if(tr->object_id==0)tr->action=TA_CREATE; else tr->action=TA_UPDATE;
 581         object_process(tr);
 582       }
 583       else {
 584         tr->succeeded=0; 
 585         tr->error|=ERROR_U_BADOP; 
 586       }
 587       break;
 588     }
 589    /* Make a report */
 590     result=report_transaction(tr, log_ptr, object_name, "RIPupd:");
 591 
 592    /* If not in standalone mode create serial and copy error transcript */ 
 593     if(!tr->standalone) {
 594       if(result==1)create_serial(tr);
 595       ud_stream->error_script=g_strdup((tr->error_script)->str);
 596     }  
 597 
 598    /* Free resources */   
 599     object_free(tr->object);
 600     transaction_free(tr);
 601     
 602     return(result);
 603         
 604 } /* process_updates() */
 605 
 606 
 607 /************************************************************
 608 *                                                           *
 609 * int process_transaction()                                 *
 610 *                                                           *
 611 * Processes the transaction                                 *
 612 *                                                           *
 613 * ud_stream - pointer to UD_stream_t structure              *
 614 *                                                           *
 615 * Returns:                                                  *
 616 * 1 - no error                                              *
 617 * <0- errors                                                *
 618 *                                                           *
 619 ************************************************************/
 620 
 621 /* It frees the obj */
 622 
 623 static int process_transaction(UD_stream_t *ud_stream, 
     /* [<][>][^][v][top][bottom][index][help] */
 624                         Object_t *obj, 
 625                         char *object_name, 
 626                         nic_handle_t *nh,
 627                         int operation)
 628 {
 629 Transaction_t *tr = NULL;
 630 Log_t *log_ptr = &(ud_stream->log);
 631 Attribute_t *attr=NULL;
 632 int result;
 633 
 634 /* start new transaction now */ 
 635  tr = transaction_new(ud_stream->db_connection, obj->type);
 636 
 637 /* Return with error if transaction cannot be created */ 
 638  if (tr == NULL) die;
 639  
 640  tr->standalone=IS_STANDALONE(ud_stream->ud_mode);
 641  tr->dummy=IS_DUMMY_ALLOWED(ud_stream->ud_mode);
 642  tr->load_pass=ud_stream->load_pass;
 643  tr->object=obj;
 644  tr->nh=nh;
 645  tr->source_hdl=ud_stream->source_hdl;
 646  
 647 /* We perform no commit/rollback in the loader mode, so thread_id should be set to 0 */
 648  if(ud_stream->load_pass!=0) { tr->thread_ins=0; tr->thread_upd=0; }
 649     
 650 /* For the first load pass we only create objects */ 
 651  if(ud_stream->load_pass==1) tr->object_id=0;
 652   else tr->object_id=get_object_id(tr);
 653  
 654 /* Object cannot be retrieved */
 655  if(tr->object_id==-1) { /* DB error*/
 656     tr->succeeded=0;
 657     tr->error |= ERROR_U_DBS;
 658     report_transaction(tr, log_ptr, object_name, "Object cannot be retrieved");
 659     transaction_free(tr);
 660     object_free(obj);
 661     die;
 662  }
 663 /* save the name of person/role as we need it for referential */
 664 /* integrity check when deleting the object against names. */
 665 /* This is needed to support legacy references by name rather */
 666 /* then by nic_hdl */
 667   if((tr->class_type==C_PN) || (tr->class_type==C_RO)){
 668      attr = attribute_new(object_name);
 669       
 670      if (attr==NULL) {
 671        tr->succeeded=0;
 672        tr->error |= ERROR_U_MEM;
 673        report_transaction(tr, log_ptr, object_name, "Cannot allocate memory");
 674        transaction_free(tr);
 675        object_free(obj);
 676        die;
 677     }
 678     
 679     /* Save the value */
 680     tr->save=g_strdup(attr->value);
 681 /*    fprintf(stderr, "Allocated [%s]\n", tr->save); */
 682     attribute_free(attr, NULL);
 683   }
 684                                                
 685 /* Process transaction. tr and obj are freed inside the process_* functions */
 686 
 687  if(IS_UPDATE(ud_stream->ud_mode))
 688  /* We are in update mode */
 689     result=process_updates(ud_stream, tr, object_name, operation);
 690  else
 691  /* We are in NRTM mode */   
 692     result=process_nrtm(ud_stream, tr, object_name, operation);
 693 
 694  return(result);
 695 
 696 }          
 697           
 698 
 699 /************************************************************
 700 *                                                           *
 701 * int UD_process_stream(UD_stream_t *ud_stream)             *
 702 *                                                           *
 703 * Processes the stream                                      *
 704 *                                                           *
 705 * ud_stream - pointer to UD_stream_t structure              *
 706 *                                                           *
 707 * Returns:                                                  *
 708 * in update mode (!standalone)(1 object processed):         *
 709 * 1 - no error                                              *
 710 * <0- errors                                                *
 711 *                                                           *
 712 * in NRTM & standalone modes                                *
 713 * total number of object processed                          *
 714 *                                                           *
 715 ************************************************************/
 716 
 717 int UD_process_stream(UD_stream_t *ud_stream)
     /* [<][>][^][v][top][bottom][index][help] */
 718 {
 719   char line_buff[STR_XXL];
 720 /*  GString *g_line_buff; */
 721   GSList *class_attr_list = NULL;
 722   Attribute_t *class_attr;
 723   Attribute_t *attr;
 724   nic_handle_t *nh_ptr = NULL; /* To save  NIC handle structure */
 725   Object_t *obj = NULL;
 726   SQ_connection_t *sql_connection;
 727   int start_object;
 728   int a_type;
 729   char *a_value;
 730   char *ptr;
 731   /* here we will store the parsed nic-hdl in required format */
 732   char nic[MAX_NH_LENGTH];
 733   struct _nrtm *nrtm;
 734   Log_t *log_ptr= &(ud_stream->log);
 735 /*  time_t stime, ftime; */
 736   ut_timer_t stime, ftime;
 737   float obj_second1, obj_second10, timediff;
 738   int result;
 739   int operation=0;
 740   int interrupt=0;
 741   int do_update;
 742   int default_ud_mode = ud_stream->ud_mode;
 743   Line_Type_t linetype;
 744 
 745   Obj_parse_t obj_parse; /* the structure used to parse a text object */
 746   ud_parse_init(&obj_parse);
 747   
 748   nrtm=ud_stream->nrtm;
 749   start_object = 1;
 750   a_type=-1; 
 751 
 752 
 753   /* Allocate line bufer */
 754 /*  if ((g_line_buff = g_string_sized_new(STR_XXL)) == NULL){ 
 755     fprintf(stderr, "E: cannot allocate gstring\n"); 
 756     die; 
 757   }
 758 */
 759   /* Check connection to the database */
 760   if(mysql_ping(ud_stream->db_connection)) {
 761    fprintf(stderr, "D: ERROR: no SQL connection\n");
 762 /*   g_string_free(g_line_buff, TRUE);*/
 763    return(-1);
 764   }
 765    
 766   fprintf(stderr, "OK\n");
 767   sql_connection=ud_stream->db_connection;
 768 
 769 /* This is useful for loading DB from huge disk file. */
 770 /* We may start from <num_skip>th object */
 771 /*  num_skip=ud_stream->num_skip; */
 772 /*  if(num_skip>0) fprintf(stderr, "skipping %lu records\n", num_skip); */
 773 
 774   /* Start timer for statistics */
 775   UT_timeget(&stime);
 776 /*  stime=time(NULL); */
 777 
 778  /* Main loop. Reading input stream line by line */
 779  /* Empty line signals to start processing an object, if we have it */ 
 780   while (fgets(line_buff, STR_XXL, ud_stream->stream) != NULL) {
 781 
 782     switch (linetype=line_type(line_buff)) {
 783       case LINE_PLUS:
 784       case LINE_ATTRIBUTE:
 785        
 786        obj = UD_parse_object(ud_stream->db_connection, &obj_parse, line_buff);
 787 
 788       break;
 789 
 790       case LINE_COMMENT:
 791       break;
 792 
 793       case LINE_EOF:
 794       break;
 795       
 796       case LINE_ADD:
 797       /* restore the default operation mode */
 798        operation=OP_ADD;
 799        ud_stream->ud_mode=default_ud_mode;
 800       break;
 801       
 802       case LINE_OVERRIDE_ADD:
 803       /* for override - switch the dummy bit on */
 804        operation=OP_ADD;
 805        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
 806       break;
 807       
 808       case LINE_UPD:
 809       /* restore the default operation mode */
 810        operation=OP_UPD;
 811        ud_stream->ud_mode=default_ud_mode;
 812       break;  
 813 
 814       case LINE_OVERRIDE_UPD:
 815       /* for override - switch the dummy bit on */
 816        operation=OP_UPD;
 817        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
 818       break;
 819       
 820       case LINE_DEL:
 821       /* restore the default operation mode */
 822        operation=OP_DEL;
 823        ud_stream->ud_mode=default_ud_mode;
 824       break; 
 825 
 826       case LINE_OVERRIDE_DEL:
 827       /* for override - switch the dummy bit on */
 828        operation=OP_DEL;
 829        ud_stream->ud_mode=default_ud_mode|B_DUMMY;
 830       break;
 831  
 832       case LINE_EMPTY:
 833        /* start processing the object */
 834         if ((obj=obj_parse.obj)) { /* if not just garbage*/
 835          /* reorder some attributes */
 836          obj->attributes = g_slist_sort(obj->attributes, reorder_attributes);
 837          /* prepend the class attribute */
 838          obj->attributes = g_slist_concat(obj_parse.class_attr_list, obj->attributes);
 839          /* XXX */
 840          /* print_object(obj); */
 841 
 842          /* start new transaction now */ 
 843          result=process_transaction(ud_stream, obj, obj_parse.object_name, obj_parse.nh_ptr, operation);
 844           
 845          /* process_transaction() frees tr and obj structures, */
 846          /* so make sure we'll not reference these objects in the future */
 847          operation=OP_NOOP;
 848          ud_stream->ud_mode=default_ud_mode;
 849          ud_parse_free(&obj_parse);
 850           
 851          /* this is a good place for quick interrupt */
 852          do_update=CO_get_do_update();
 853          if (do_update) interrupt=0; else interrupt=1;
 854          /* we still need to exit in update server mode (only 1 object at a time */ 
 855          if (IS_UPDATE(ud_stream->ud_mode) && (!IS_STANDALONE(ud_stream->ud_mode))) interrupt=1;
 856         } /* if this is a real object */
 857         /* initialize the parsing structure */
 858         ud_parse_init(&obj_parse);
 859 
 860       break;
 861 
 862       default:
 863         fprintf(stderr, "ERROR: Bad line type\n");
 864     } /* switch */
 865     
 866     /* Finish processing if interrupt has been set */
 867     if (interrupt) break;
 868   } /* while */
 869  
 870  /* Some postprocessing */
 871   if(!IS_UPDATE(ud_stream->ud_mode)){
 872   /* We are in NRTM mode */
 873   /* Clean up */
 874    fclose(ud_stream->stream);
 875   /* In NRTM mode there may be a saved object that is unprocessed */   
 876    if(nrtm->tr){ /*saved backlog?*/
 877     object_process(nrtm->tr); /* delete the previous(saved) object*/
 878     result=report_transaction(nrtm->tr, &(ud_stream->log), nrtm->object_name, 
 879                               "NRTM:DEL:While deleting previous(saved) object");
 880     /* create DEL serial record no matter what the result is */
 881     create_serial(nrtm->tr);
 882     object_free(nrtm->tr->object);
 883     transaction_free(nrtm->tr); nrtm->tr=NULL;
 884    } 
 885   }
 886 
 887  /* That's all. Free GString */
 888 /*  g_string_free(g_line_buff, TRUE);*/
 889 
 890                                                                                                        
 891  /* Calculate some statistics */
 892 /*  ftime=time(NULL); */
 893   UT_timeget(&ftime);
 894 /*  obj_second1 = (float)(log_ptr->num_ok)/(ftime-stime);
 895   obj_second10 = (float)(log_ptr->num_ok+log_ptr->num_failed)/(ftime-stime); */
 896   timediff = UT_timediff(&stime, &ftime);
 897   obj_second1 = (float)(log_ptr->num_ok)/timediff;
 898   obj_second10 = (float)(log_ptr->num_ok+log_ptr->num_failed)/timediff;
 899   
 900   /* Print the report */
 901   if(IS_STANDALONE(ud_stream->ud_mode) || (!IS_UPDATE(ud_stream->ud_mode))) {
 902 /*   printf("\n\n******** report **********\n%d objects OK\n%d objects failed\n", 
 903             log_ptr->num_ok, log_ptr->num_failed); */
 904    fprintf(log_ptr->logfile,"\n******** report **********\n");
 905    fprintf(log_ptr->logfile," %d objects OK (%7.4f obj/s)\n", log_ptr->num_ok, obj_second1);
 906    fprintf(log_ptr->logfile," %d objects failed\n", log_ptr->num_failed);
 907    fprintf(log_ptr->logfile," average processing time %7.4f obj/s (%6.2f obj/min)\n", 
 908                           obj_second10, obj_second10*60);
 909    result=log_ptr->num_ok+log_ptr->num_failed;
 910   }
 911   return(result);
 912 
 913 } /* UD_process_stream */
 914 

/* [<][>][^][v][top][bottom][index][help] */