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

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