modules/ud/ud_process_stream.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- split_attribute
- reorder_attributes
- each_attribute_print
- print_object
- escape_apostrophes
- line_type
- report_transaction
- process_nrtm
- process_updates
- process_transaction
- 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