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

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