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 |