1 | /*************************************** 2 | $Revision: 1.7 $ 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 "ud.h" 41 | #include "ud_int.h" 42 | 43 | typedef enum _Line_Type_t { 44 | LINE_ATTRIBUTE, 45 | LINE_COMMENT, 46 | LINE_EMPTY, 47 | LINE_EOF, 48 | LINE_ADD, 49 | LINE_UPD, 50 | LINE_DEL 51 | } Line_Type_t; 52 | 53 | /* Maximum number of objects(serials) we can consume at a time */ 54 | #define SBUNCH 1000 55 | 56 | static int report_transaction(Transaction_t *tr, Log_t *log, char *obj_name, char *reason); 57 | static char *s_split(char *line); 58 | 59 | static int process_nrtm(Transaction_t *tr, struct _nrtm *nrtm, Log_t *log, char *object_name, int operation); 60 | static int process_updates(Transaction_t *tr, Log_t *log, char *object_name, int operation, int standalone); 61 | 62 | 63 | 64 | 65 | /* temporary files to download serials */ 66 | char tmpfile1[STR_S], tmpfile2[STR_S]; 67 | 68 | FILE *get_NRTM_stream(struct _nrtm *nrtm, int upto_last) 69 | { 70 | int sockfd; 71 | struct hostent *hptr; 72 | struct sockaddr_in serv_addr; 73 | struct in_addr *paddr; 74 | char line_buff[STR_XXL]; 75 | FILE *fp; 76 | int fd; 77 | int fdtmp; 78 | int nread, nwrite; 79 | struct hostent result; 80 | int error; 81 | 82 | 83 | fprintf(stderr, "Making connection to NRTM server ...\n"); 84 | if ((sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1){ 85 | perror("socket"); 86 | return(NULL); 87 | } 88 | // hptr=gethostbyname(nrtm->server); 89 | hptr=gethostbyname_r(nrtm->server, &result, line_buff, sizeof(line_buff), &error); 90 | if (hptr) { // this is a network stream 91 | paddr=(struct in_addr *)hptr->h_addr; 92 | bzero(&serv_addr, sizeof(serv_addr)); 93 | serv_addr.sin_family=AF_INET; 94 | serv_addr.sin_port=nrtm->port; 95 | memcpy(&serv_addr.sin_addr, paddr, sizeof(struct in_addr)); 96 | fprintf(stderr,"Trying %s port %d\n", inet_ntoa(serv_addr.sin_addr), nrtm->port); 97 | if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))==-1) { 98 | perror("connect"); 99 | return(NULL); 100 | } 101 | fprintf(stderr, "Sending Invitation\n"); 102 | if(upto_last) 103 | sprintf(line_buff, "-g RIPE:%d:%d-LAST\n", nrtm->version, nrtm->current_serial+1); 104 | else 105 | sprintf(line_buff, "-g RIPE:%d:%d-%d\n", nrtm->version, nrtm->current_serial+1, nrtm->current_serial+SBUNCH); 106 | write(sockfd, line_buff, strlen(line_buff)); 107 | fd=sockfd; 108 | fprintf(stderr, "%s", line_buff); 109 | fprintf(stderr, "Returning stream pointer\n"); 110 | } 111 | else { // this is a file stream 112 | fprintf(stderr, "Trying file ...\n"); 113 | if((fd=open(nrtm->server, O_RDONLY, 0666))==-1) { 114 | perror("open"); 115 | return(NULL); 116 | } 117 | } 118 | 119 | /* make temporary files */ 120 | sprintf(tmpfile1, "temp.XXXX"); 121 | 122 | if((fdtmp=mkstemp(tmpfile1))==-1) { 123 | perror("mkstemp"); 124 | close(fd); 125 | return(NULL); 126 | } 127 | while ((nread=read(fd, line_buff, sizeof(line_buff)))) { 128 | if(nread==-1) return(NULL); 129 | nwrite=write(fdtmp, line_buff,nread); 130 | if(nread != nwrite) return(NULL); 131 | } 132 | 133 | close(fd); close(fdtmp); 134 | 135 | sprintf(tmpfile2, "%s.2", tmpfile1); 136 | 137 | sprintf(line_buff, "cat %s | ./ripe2rpsl > %s", tmpfile1, tmpfile2); 138 | if (system(line_buff)!=0) return(NULL); 139 | if((fp=fopen(tmpfile2, "r+"))==NULL)return(NULL); 140 | 141 | unlink(tmpfile1); 142 | 143 | return(fp); 144 | 145 | } 146 | 147 | /****************************************************************** 148 | * report_transaction() * 149 | * * 150 | * Prints error report to the log * 151 | * * 152 | * reason - additional message thet will be included * 153 | * * 154 | * *****************************************************************/ 155 | static int report_transaction(Transaction_t *tr, Log_t *log, char *obj_name, char *reason) 156 | { 157 | int result=0; 158 | 159 | if(tr->succeeded==0) { 160 | result=tr->error; 161 | log->num_failed++; 162 | printf("FAILED[%s][%s(%d)](%d/%d)\n ", obj_name, reason, result, log->num_failed, (log->num_failed)+(log->num_ok)); 163 | fprintf(log->logfile, "*FAILED[%s][%s](%d/%d)\n ", obj_name, reason, log->num_failed, (log->num_failed)+(log->num_ok)); 164 | if(result & ERROR_U_MEM) fprintf(log->logfile, "\t*Memory allocation error\n"); 165 | if(result & ERROR_U_DBS) fprintf(log->logfile, "\t*Database (SQL) error\n"); 166 | if(result & ERROR_U_OBJ) fprintf(log->logfile, "\t*Object (RF) error\n"); 167 | if(result & ERROR_U_AUT) fprintf(log->logfile, "\t*Object authentication error\n"); 168 | if(result & ERROR_U_BADOP) fprintf(log->logfile, "\t*Bad operation\n"); 169 | if(result & ERROR_U_COP) fprintf(log->logfile, "\t*Conflicting operation\n"); 170 | if(result & ERROR_U_NSUP) fprintf(log->logfile, "\t*Object of this type is not supported\n"); 171 | if(result & ERROR_U_BUG) fprintf(log->logfile, "\t*Software bug - report to <ripe-dbm@ripe.net>\n"); 172 | fprintf(log->logfile, "%s", (tr->error_script)->str); 173 | result=(-1)*result; 174 | fflush(log->logfile); 175 | } 176 | else { 177 | result=1; 178 | log->num_ok++; 179 | printf("OK(%d/%d)\n", log->num_ok, (log->num_failed)+(log->num_ok)); 180 | } 181 | 182 | return(result); 183 | } 184 | 185 | /****************************************************************** 186 | * char *s_split(char *line) * 187 | * consequently returns words (separated by whitespace in the line)* 188 | * NULL - end. You need to retreive all words ! * 189 | * * 190 | * *****************************************************************/ 191 | static char *s_split(char *line) 192 | { 193 | static char *delim; 194 | static char *token=NULL; 195 | 196 | if(token==NULL)token=line; 197 | else token=delim; 198 | 199 | if(token==NULL)return(token); 200 | while(isspace((int)*token))token++; 201 | delim=token; 202 | 203 | while(!isspace((int)*delim)) { 204 | if((*delim)=='\0'){ 205 | if(delim==token)token=NULL; 206 | delim=NULL; return(token); 207 | } 208 | delim++; 209 | } 210 | *delim='\0'; delim++; 211 | return(token); 212 | 213 | } 214 | 215 | 216 | 217 | GString *escape_apostrophes(GString *text) { 218 | int i; 219 | for (i=0; i < text->len; i++) { 220 | if ((text->str[i] == '\'') || (text->str[i] == '\\')) { 221 | text = g_string_insert_c(text, i, '\\'); 222 | i++; 223 | } 224 | } 225 | return(text); 226 | } /* escape_apostrophes() */ 227 | 228 | static Line_Type_t line_type(const char *line) { 229 | Line_Type_t result = -1; 230 | 231 | if (strncmp(line, "# EOF", 4) == 0) { 232 | result = LINE_EOF; 233 | } 234 | else if (strncmp(line, "#", 1) == 0) { 235 | result = LINE_COMMENT; 236 | } 237 | else if (strcmp(line, "\n") == 0) { 238 | result = LINE_EMPTY; 239 | } 240 | else if (strncmp(line, "ADD", 3) == 0) { 241 | result = LINE_ADD; 242 | } 243 | else if (strncmp(line, "UPD", 3) == 0) { 244 | result = LINE_UPD; 245 | } 246 | else if (strncmp(line, "DEL", 3) == 0) { 247 | result = LINE_DEL; 248 | } 249 | else { 250 | result = LINE_ATTRIBUTE; 251 | } 252 | 253 | return result; 254 | } /* line_type() */ 255 | 256 | 257 | 258 | 259 | /************************************************************ 260 | * process_nrtm() * 261 | * * 262 | * Process object in NRTM client mode * 263 | * * 264 | * nrtm - pointer to _nrtm structure * 265 | * log - pointer to Log_t structure * 266 | * object_name - name of the object * 267 | * operation - operation code (OP_ADD/OP_DEL) * 268 | * * 269 | * Returns: * 270 | * 1 - okay * 271 | * <0 - error * 272 | * * 273 | ************************************************************/ 274 | 275 | static int process_nrtm(Transaction_t *tr, struct _nrtm *nrtm, Log_t *log, char *object_name, int operation) 276 | { 277 | int error=0; 278 | //fprintf(stderr,"NRTM mode\n"); 279 | 280 | switch (operation) { 281 | 282 | case OP_ADD: 283 | if(nrtm->tr){ //saved? 284 | if(tr->object_id==0) { 285 | // fprintf(stderr,"DEL previous\n"); 286 | object_process(nrtm->tr); // delete the previous(saved) object 287 | error=report_transaction(nrtm->tr, log, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)"); 288 | object_free(nrtm->tr->object); 289 | transaction_free(nrtm->tr); nrtm->tr=NULL; 290 | tr->action=TR_CREATE; 291 | // fprintf(stderr,"CREATE next\n"); 292 | object_process(tr); // create a new one 293 | error=report_transaction(tr, log, object_name, "NRTM:ADD:While creating new"); 294 | } 295 | else { //compare the two, may be we may collapse operations 296 | if(tr->object_id==nrtm->tr->object_id) { 297 | object_free(nrtm->tr->object); 298 | transaction_free(nrtm->tr); nrtm->tr=NULL; 299 | // fprintf(stderr,"DEL-ADD ->> UPDATE\n"); 300 | tr->action=TR_UPDATE; 301 | object_process(tr); 302 | report_transaction(tr, log, object_name,"NRTM:upd"); 303 | error=report_transaction(tr, log, object_name,"NRTM:upd"); 304 | } 305 | else { // this should be a dummy object in the database or an interleaved operation 306 | // fprintf(stderr,"DEL previous\n"); 307 | object_process(nrtm->tr); // delete the previous(saved) object 308 | error=report_transaction(nrtm->tr, log, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)"); 309 | object_free(nrtm->tr->object); 310 | transaction_free(nrtm->tr); nrtm->tr=NULL; 311 | tr->action=TR_UPDATE; 312 | // fprintf(stderr,"UPDATE next(dummy)\n"); 313 | object_process(tr); // create a new one 314 | error=report_transaction(tr, log, object_name, "NRTM:ADD:While creating new"); 315 | } 316 | } 317 | } 318 | else { // brand new object 319 | if(tr->object_id==0) { 320 | // fprintf(stderr,"CREATE new\n"); 321 | tr->action=TR_CREATE; 322 | object_process(tr); 323 | error=report_transaction(tr, log, object_name,"NRTM:ADD:While creating new"); 324 | } 325 | else { // this may happen because of dummies 326 | // fprintf(stderr,"CREATE new\n"); 327 | tr->action=TR_UPDATE; 328 | object_process(tr); 329 | error=report_transaction(tr, log, object_name,"NRTM:ADD:While creating new"); 330 | } 331 | } 332 | break; 333 | 334 | case OP_DEL: 335 | if(nrtm->tr){ //saved? 336 | // fprintf(stderr,"DEL previous\n"); 337 | object_process(nrtm->tr); // delete the previous(saved) object 338 | error=report_transaction(nrtm->tr, log, nrtm->object_name, "NRTM:DEL:While deleting previous(saved) object"); 339 | object_free(nrtm->tr->object); 340 | transaction_free(nrtm->tr); nrtm->tr=NULL; 341 | } 342 | if(tr->object_id>0){ // save the object 343 | // fprintf(stderr,"SAVE del object\n"); 344 | tr->action=TR_DELETE; 345 | nrtm->tr=tr; 346 | strcpy(nrtm->object_name, object_name); 347 | return(error); 348 | } 349 | else { // this is an error 350 | tr->succeeded=0; tr->error|=ERROR_U_COP; 351 | error=report_transaction(tr, log, object_name, "NRTM:OOS:Trying to DEL non-existing object"); 352 | // fprintf(stderr,"Lost sync. Skipping\n"); 353 | } 354 | break; 355 | 356 | default: 357 | tr->succeeded=0; tr->error |=ERROR_U_BADOP; 358 | break; 359 | } 360 | 361 | object_free(tr->object); 362 | transaction_free(tr); 363 | return(error); 364 | } /* process_nrtm() */ 365 | 366 | 367 | 368 | /************************************************************ 369 | * process_updates() * 370 | * * 371 | * Process object in update mode * 372 | * * 373 | * nrtm - pointer to _nrtm structure * 374 | * log - pointer to Log_t structure * 375 | * object_name - name of the object * 376 | * operation - operation code (OP_ADD/OP_DEL) * 377 | * standalone - if the program is executed standalone * 378 | * * 379 | * Returns: * 380 | * 1 - okay * 381 | * <0 - error * 382 | * * 383 | ************************************************************/ 384 | 385 | static int process_updates(Transaction_t *tr, Log_t *log, char *object_name, int operation, int standalone) 386 | { 387 | int error=0; 388 | 389 | switch(operation) { 390 | 391 | case OP_ADD: 392 | case OP_UPD: 393 | if(tr->object_id==0) tr->action=TR_CREATE; else tr->action=TR_UPDATE; 394 | object_process(tr); 395 | break; 396 | 397 | case OP_DEL: 398 | if(tr->object_id==0) { // trying t delete non-existing object 399 | tr->succeeded=0; tr->error|=ERROR_U_COP; 400 | } else { 401 | tr->action=TR_DELETE; 402 | object_process(tr); 403 | } 404 | break; 405 | 406 | default: 407 | /* bad operation for this mode if not standalone */ 408 | if(standalone) { 409 | if(tr->object_id==0)tr->action=TR_CREATE; else tr->action=TR_UPDATE; 410 | object_process(tr); 411 | } 412 | else { 413 | tr->succeeded=0; 414 | tr->error|=ERROR_U_BADOP; 415 | } 416 | break; 417 | } 418 | error=report_transaction(tr, log, object_name, "UPD"); 419 | 420 | return(error); 421 | 422 | } /* process_updates() */ 423 | 424 | /************************************************************ 425 | * * 426 | * int UD_process_stream(UD_stream_t *ud_stream) * 427 | * * 428 | * Processes the stream * 429 | * * 430 | * ud_stream - pointer to UD_stream_t structure * 431 | * * 432 | * Returns: * 433 | * in update mode (!standalone)(1 object processed): * 434 | * 1 - no error * 435 | * <0- errors * 436 | * * 437 | * in NRTM & standalone modes * 438 | * total number of object processed * 439 | * * 440 | ************************************************************/ 441 | 442 | int UD_process_stream(UD_stream_t *ud_stream) 443 | { 444 | FILE *logfile; 445 | char line_buff[STR_XXL], object_name[STR_XXL]; 446 | GString *g_line_buff; // needed to escape apostrophes 447 | 448 | Attribute_t *attr, *attr_split; 449 | Attribute_t *mnt_by; // we need this for reordering mnt_by and member_of (member_of should come after) 450 | Attribute_t *nic_hdl; // we need this for reordering nic_hdl and admin_c, etc. (admin_c should come after) 451 | Object_t *obj = NULL; 452 | Transaction_t *tr = NULL; 453 | SQ_connection_t *sql_connection; 454 | int start_object; 455 | int a_type; 456 | char *s_attr; 457 | long num_skip; 458 | struct _nrtm *nrtm; 459 | Log_t log; 460 | time_t stime, ftime; 461 | double obj_second1, obj_second10; 462 | int standalone; 463 | int error; 464 | int operation=0; 465 | 466 | nrtm=ud_stream->nrtm; 467 | standalone=IS_STANDALONE(ud_stream->ud_mode); 468 | start_object = 1; 469 | 470 | if ((g_line_buff = g_string_sized_new(STR_XXL)) == NULL){ fprintf(stderr, "E: cannot allocate gstring\n"); return(-1); } 471 | 472 | 473 | 474 | fprintf(stderr, "D: Making SQL connection to %s@%s ...", ud_stream->db_name, ud_stream->db_host); 475 | sql_connection = SQ_get_connection(ud_stream->db_host, ud_stream->db_port, 476 | ud_stream->db_name, ud_stream->db_user, ud_stream->db_pswd); 477 | if(!sql_connection) { 478 | fprintf(stderr, "D: ERROR: no SQL connection\n"); 479 | return(-1); 480 | } 481 | fprintf(stderr, "OK\n"); 482 | 483 | logfile = fopen(ud_stream->log, "a+"); 484 | log.logfile=logfile; 485 | log.num_ok=0; log.num_failed=0; 486 | 487 | /* This is useful for loading DB from huge disk file. */ 488 | num_skip=ud_stream->num_skip; 489 | if(num_skip>0) fprintf(stderr, "skipping %lu records\n", num_skip); 490 | 491 | stime=time(NULL); 492 | 493 | 494 | while (fgets(line_buff, STR_XXL, ud_stream->stream) != NULL) { 495 | 496 | switch (line_type(line_buff)) { 497 | case LINE_ATTRIBUTE: 498 | if (start_object == 1) { 499 | if(num_skip>0){ printf("\r%10lu", num_skip); num_skip--; log.num_ok++; break; } 500 | 501 | mnt_by=NULL; 502 | nic_hdl=NULL; 503 | strncpy(object_name, line_buff, strlen(line_buff)-1); 504 | *(object_name+strlen(line_buff)-1)='\0'; 505 | obj = object_new(line_buff); 506 | if (obj) { 507 | start_object = 0; 508 | printf("D: object: [%s] ", object_name); 509 | } 510 | } 511 | if (obj != NULL) { 512 | g_string_sprintf(g_line_buff, "%s", line_buff); 513 | g_line_buff=escape_apostrophes(g_line_buff); 514 | attr = attribute_new(g_line_buff->str); 515 | g_string_sprintfa(obj->object, "%s", g_line_buff->str); 516 | if (attr != NULL) { 517 | switch (a_type=(attr->type)) { 518 | case A_MB: mnt_by=attr; 519 | break; 520 | case A_NH: nic_hdl=attr; 521 | break; 522 | case A_PN: 523 | case A_RO: 524 | case A_MR: 525 | case A_SD: 526 | case A_RZ: 527 | case A_NS: //these attributes may appear several on the line - split them 528 | while((s_attr=s_split(attr->value))){ 529 | attr_split = attribute_new1(a_type, s_attr); 530 | obj->attributes = g_slist_append(obj->attributes, attr_split); 531 | } 532 | attribute_free(attr, NULL); 533 | attr=NULL; 534 | break; 535 | default: break; 536 | } 537 | if(attr){ obj->attributes = g_slist_append(obj->attributes, attr); 538 | } 539 | } 540 | } 541 | break; 542 | 543 | case LINE_COMMENT: 544 | break; 545 | 546 | case LINE_EOF: 547 | break; 548 | 549 | case LINE_ADD: 550 | operation=OP_ADD; 551 | break; 552 | 553 | case LINE_UPD: 554 | operation=OP_UPD; 555 | break; 556 | 557 | case LINE_DEL: 558 | operation=OP_DEL; 559 | break; 560 | 561 | case LINE_EMPTY: 562 | start_object=1; 563 | if (obj != NULL) { 564 | /* reorder some attributes */ 565 | if(mnt_by){ 566 | obj->attributes = g_slist_remove(obj->attributes, mnt_by); 567 | obj->attributes = g_slist_insert(obj->attributes, mnt_by, 1); 568 | } 569 | if(nic_hdl){ 570 | obj->attributes = g_slist_remove(obj->attributes, nic_hdl); 571 | obj->attributes = g_slist_insert(obj->attributes, nic_hdl, 1); 572 | } 573 | tr = transaction_new(sql_connection, obj->type); 574 | if (tr != NULL) { 575 | tr->standalone=standalone; 576 | tr->dummy=IS_DUMMY_ALLOWED(ud_stream->ud_mode); 577 | tr->load_pass=ud_stream->load_pass; 578 | tr->object=obj; 579 | if(ud_stream->load_pass) { tr->thread_ins=0; tr->thread_upd=0; } 580 | if(ud_stream->load_pass==1) tr->object_id=0; 581 | else tr->object_id=get_object_id(tr); 582 | if(tr->object_id==-1) { // some error 583 | tr->succeeded=0; 584 | report_transaction(tr, &log, object_name, "DB error"); 585 | transaction_free(tr); tr=NULL; 586 | object_free(obj); obj=NULL; 587 | operation=OP_NOOP; 588 | break; 589 | } 590 | else 591 | if(nrtm) { //NRTM mode 592 | error=process_nrtm(tr, nrtm, &log, object_name, operation); 593 | tr=NULL; 594 | obj=NULL; 595 | operation=OP_NOOP; 596 | } 597 | else { //update mode 598 | error=process_updates(tr, &log, object_name, operation, standalone); 599 | if(!standalone) { /* copy the script */ 600 | ud_stream->error_script=g_strdup((tr->error_script)->str); 601 | object_free(tr->object); obj=NULL; 602 | transaction_free(tr); tr=NULL; 603 | g_string_free(g_line_buff, TRUE); 604 | SQ_close_connection(sql_connection); 605 | fclose(logfile); 606 | return(error); 607 | } 608 | else { 609 | object_free(tr->object); obj=NULL; 610 | transaction_free(tr); tr=NULL; 611 | operation=OP_NOOP; 612 | } 613 | } 614 | /* this is a good place for quick inerrupt */ 615 | } 616 | } 617 | break; 618 | 619 | default: 620 | fprintf(stderr, "ERROR: Bad line type\n"); 621 | } /* switch */ 622 | } /* while */ 623 | 624 | if(nrtm) 625 | if(nrtm->tr){ //saved backlog? 626 | object_process(nrtm->tr); // delete the previous(saved) object 627 | report_transaction(nrtm->tr, &log, nrtm->object_name, "NRTM:DEL:While deleting previous(saved) object"); 628 | object_free(nrtm->tr->object); 629 | transaction_free(nrtm->tr); nrtm->tr=NULL; 630 | } 631 | 632 | ftime=time(NULL); 633 | obj_second1 = (float)(log.num_ok)/(ftime-stime); 634 | obj_second10 = (float)(log.num_ok+log.num_failed)/(ftime-stime); 635 | 636 | SQ_close_connection(sql_connection); 637 | g_string_free(g_line_buff, TRUE); 638 | fclose(ud_stream->stream); 639 | if(IS_STANDALONE(ud_stream->ud_mode) || (!IS_UPDATE(ud_stream->ud_mode)))unlink(tmpfile2); 640 | printf("\n\n******** report **********\n%d objects OK\n%d objects failed\n", log.num_ok, log.num_failed); 641 | fprintf(logfile,"\n******** report **********\n"); 642 | fprintf(logfile," %d objects OK (%5.2f obj/s)\n", log.num_ok, obj_second1); 643 | fprintf(logfile," %d objects failed\n", log.num_failed); 644 | fprintf(logfile," average processing time %5.2f obj/s (%5.2f obj/min)\n", obj_second10, obj_second10*60); 645 | fclose(logfile); 646 | return(log.num_ok+log.num_failed); 647 | 648 | } /* UD_process_stream */ 649 | 650 | 651 | 652 |