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