## modules/ud/ud_process_stream.c

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

## FUNCTIONS

This source file includes following functions.

1. split_attribute
2. reorder_attributes
3. each_attribute_print
4. print_object
5. escape_apostrophes
6. line_type
7. report_transaction
8. process_nrtm
9. process_updates
10. process_transaction
11. UD_process_stream

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

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