Source File modules/ud/ud_process_stream.c

    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){
    73   |      bzero(parse, sizeof(Obj_parse_t));
    74   |      parse->start_object=1;
    75   | }
    76   |
    77   | void ud_parse_free(Obj_parse_t *parse){
    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){
    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)
    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)
    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)
    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) {
    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) {
    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)
    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)
    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)
    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)
    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,
    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)
    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  |