modules/ud/ud_process_stream.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- get_NRTM_stream
- s_split
- escape_apostrophes
- line_type
- report_transaction
- process_nrtm
- process_updates
- process_transaction
- UD_process_stream
/***************************************
$Revision: 1.18 $
Functions to process data stream( file, network socket, etc.)
Status: NOT REVUED, NOT TESTED
Author(s): Chris Ottrey, Andrei Robachevsky
******************/ /******************
Modification History:
andrei (17/01/2000) Created.
******************/ /******************
Copyright (c) 2000 RIPE NCC
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of the author not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
***************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "constants.h"
#include "ud.h"
#include "ud_int.h"
typedef enum _Line_Type_t {
LINE_ATTRIBUTE,
LINE_COMMENT,
LINE_EMPTY,
LINE_EOF,
LINE_ADD,
LINE_UPD,
LINE_DEL,
LINE_OVERRIDE_ADD,
LINE_OVERRIDE_UPD,
LINE_OVERRIDE_DEL
} Line_Type_t;
/* Maximum number of objects(serials) we can consume at a time */
#define SBUNCH 1000
static int report_transaction(Transaction_t *tr, Log_t *log, char *obj_name, char *reason);
static char *s_split(char *line);
static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation);
static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation);
static int process_transaction(UD_stream_t *ud_stream,Object_t *obj,char *object_name,nic_handle_t *nh, int operation);
/* temporary files to download serials */
char tmpfile1[STR_S], tmpfile2[STR_S];
/************************************************************
* FILE *get_NRTM_stream() *
* *
* Gets the NRTM stream *
* *
* First tries to request the serials from the NRTM server *
* If the name of the server appears to be not a network name*
* it tries to open the file with this name *
* *
* After downloading (opening) the serials into the file *
* it runs ripe2rpsl script to translate objects into RPSL *
* They are stored in a temporary file *
* *
* nrtm - pointer to _nrtm structure *
* upto_last - if==1 then requests to download serials using *
* LAST keyword *
* *
* Returns: *
* A pointer to the temp. file where serials in RPSL format *
* are stored *
* NULL - error *
* *
************************************************************/
FILE *get_NRTM_stream(struct _nrtm *nrtm, int upto_last)
/* [<][>][^][v][top][bottom][index][help] */
{
int sockfd;
struct hostent *hptr;
struct sockaddr_in serv_addr;
struct in_addr *paddr;
char line_buff[STR_XXL];
FILE *fp;
int fd;
int fdtmp;
int nread, nwrite;
struct hostent result;
int error;
int network;
fprintf(stderr, "Making connection to NRTM server ...\n");
if ((sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1){
perror("socket");
return(NULL);
}
/* hptr=gethostbyname(nrtm->server);*/
hptr=gethostbyname_r(nrtm->server, &result, line_buff, sizeof(line_buff), &error);
if (hptr) { /* this is a network stream*/
paddr=(struct in_addr *)hptr->h_addr;
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=nrtm->port;
memcpy(&serv_addr.sin_addr, paddr, sizeof(struct in_addr));
fprintf(stderr,"Trying %s port %d\n", inet_ntoa(serv_addr.sin_addr), nrtm->port);
if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))==-1) {
perror("connect");
return(NULL);
}
fprintf(stderr, "Sending Invitation\n");
/* Request all available serials (upto LAST), or SBUNCH of them */
if(upto_last)
sprintf(line_buff, "-g RIPE:%d:%ld-LAST\n", nrtm->version, nrtm->current_serial+1);
else
sprintf(line_buff, "-g RIPE:%d:%ld-%ld\n", nrtm->version, nrtm->current_serial+1, nrtm->current_serial+SBUNCH);
nwrite=SK_write(sockfd, line_buff, strlen(line_buff) );
if(nwrite != strlen(line_buff)) { perror("write"); return(NULL); }
fd=sockfd;
network=1;
fprintf(stderr, "Returning stream pointer\n");
}
else { /* this is a file stream*/
network=0;
close(sockfd);
fprintf(stderr, "Trying file ...\n");
if((fd=open(nrtm->server, O_RDONLY, 0666))==-1) {
perror("open");
return(NULL);
}
}
/* make temporary files */
sprintf(tmpfile1, "temp.XXXX");
if((fdtmp=mkstemp(tmpfile1))==-1) {
perror("mkstemp");
close(fd);
return(NULL);
}
if(network) {
while ((nread=SK_read(fd, line_buff, sizeof(line_buff)))) {
if(nread==-1) return(NULL);
nwrite=write(fdtmp, line_buff,nread);
if(nread != nwrite) return(NULL);
}
} else {
while ((nread=read(fd, line_buff, sizeof(line_buff)))) {
if(nread==-1) return(NULL);
nwrite=write(fdtmp, line_buff,nread);
if(nread != nwrite) return(NULL);
}
}
close(fd); close(fdtmp);
sprintf(tmpfile2, "%s.2", tmpfile1);
sprintf(line_buff, "cat %s | ./ripe2rpsl > %s", tmpfile1, tmpfile2);
if (system(line_buff)!=0) return(NULL);
if((fp=fopen(tmpfile2, "r+"))==NULL)return(NULL);
unlink(tmpfile1);
return(fp);
}
/******************************************************************
* char *s_split(char *line) *
* consequently returns words (separated by whitespace in the line)*
* NULL - end. You need to retreive all words ! *
* *
* *****************************************************************/
static char *s_split(char *line)
/* [<][>][^][v][top][bottom][index][help] */
{
static char *delim;
static char *token=NULL;
if(token==NULL)token=line;
else token=delim;
if(token==NULL)return(token);
while(isspace((int)*token))token++;
delim=token;
while(!isspace((int)*delim)) {
if((*delim)=='\0'){
if(delim==token)token=NULL;
delim=NULL; return(token);
}
delim++;
}
*delim='\0'; delim++;
return(token);
}
/******************************************************************
* GString *escape_apostrophes() *
* Escapes apostrophes in the text so they do not confuse printf *
* functions and don't corrupt SQL queries *
* *
* *****************************************************************/
GString *escape_apostrophes(GString *text) {
/* [<][>][^][v][top][bottom][index][help] */
int i;
for (i=0; i < text->len; i++) {
if ((text->str[i] == '\'') || (text->str[i] == '\\')) {
text = g_string_insert_c(text, i, '\\');
i++;
}
}
return(text);
} /* escape_apostrophes() */
/******************************************************************
* Line_Type_t line_type(e) *
* Determines the line type analysing the first letters *
* *
* ****************************************************************/
static Line_Type_t line_type(const char *line) {
/* [<][>][^][v][top][bottom][index][help] */
Line_Type_t result = -1;
if (strncmp(line, "# EOF", 4) == 0) {
result = LINE_EOF;
}
else if (strncmp(line, "#", 1) == 0) {
result = LINE_COMMENT;
}
else if (strcmp(line, "\n") == 0) {
result = LINE_EMPTY;
}
else if (strcmp(line, "ADD\n") == 0) {
result = LINE_ADD;
}
else if (strcmp(line, "UPD\n") == 0) {
result = LINE_UPD;
}
else if (strcmp(line, "DEL\n") == 0) {
result = LINE_DEL;
}
else if (strcmp(line, "ADD_OVERRIDE\n") == 0) {
result = LINE_OVERRIDE_ADD;
}
else if (strcmp(line, "UPD_OVERRIDE\n") == 0) {
result = LINE_OVERRIDE_UPD;
}
else if (strcmp(line, "DEL_OVERRIDE\n") == 0) {
result = LINE_OVERRIDE_DEL;
}
else {
result = LINE_ATTRIBUTE;
}
return result;
} /* line_type() */
/******************************************************************
* report_transaction() *
* *
* Prints error report to the log *
* *
* reason - additional message that will be included *
* *
* *****************************************************************/
static int report_transaction(Transaction_t *tr, Log_t *log, char *obj_name, char *reason)
/* [<][>][^][v][top][bottom][index][help] */
{
int result=0;
if(tr->succeeded==0) {
result=tr->error;
log->num_failed++;
fprintf(stderr, "FAILED[%s][%s(%d)](%d/%d)\n ", obj_name, reason, result, log->num_failed, (log->num_failed)+(log->num_ok));
fprintf(log->logfile, "*FAILED[%s][%s](%d/%d)\n ", obj_name, reason, log->num_failed, (log->num_failed)+(log->num_ok));
if(result & ERROR_U_MEM) fprintf(log->logfile, "\t*Memory allocation error\n");
if(result & ERROR_U_DBS) fprintf(log->logfile, "\t*Database (SQL) error\n");
if(result & ERROR_U_OBJ) fprintf(log->logfile, "\t*Object (RF) error\n");
if(result & ERROR_U_AUT) fprintf(log->logfile, "\t*Object authentication error\n");
if(result & ERROR_U_BADOP) fprintf(log->logfile, "\t*Bad operation\n");
if(result & ERROR_U_COP) fprintf(log->logfile, "\t*Conflicting operation\n");
if(result & ERROR_U_NSUP) fprintf(log->logfile, "\t*Object of this type is not supported\n");
if(result & ERROR_U_BUG) fprintf(log->logfile, "\t*Software bug - report to <ripe-dbm@ripe.net>\n");
fprintf(log->logfile, "%s", (tr->error_script)->str);
result=(-1)*result;
fflush(log->logfile);
}
else {
result=1;
log->num_ok++;
fprintf(stderr, "OK(%d/%d)\n", log->num_ok, (log->num_failed)+(log->num_ok));
}
return(result);
}/* report_transaction() */
/************************************************************
* process_nrtm() *
* *
* Process object in NRTM client mode *
* *
* nrtm - pointer to _nrtm structure *
* log - pointer to Log_t structure *
* object_name - name of the object *
* operation - operation code (OP_ADD/OP_DEL) *
* *
* Returns: *
* 1 - okay *
* <0 - error *
* *
************************************************************/
static int process_nrtm(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation)
/* [<][>][^][v][top][bottom][index][help] */
{
int result=0;
int dummy=0;
struct _nrtm *nrtm = ud_stream->nrtm;
Log_t *log_ptr= &(ud_stream->log);
switch (operation) {
case OP_ADD:
/* XXX This hack is made to allow NRTM updates for some inconsistent objects */
/* One of the examples is reference by name which looks like nic-handle */
/* For this purpose we allow dummy creation when updating an object */
tr->dummy=1;
if(nrtm->tr){ /*saved?*/
if(tr->object_id==0) {
/* fprintf(stderr,"DEL previous\n");*/
object_process(nrtm->tr); /* delete the previous(saved) object*/
result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)");
if(result==1)create_serial(nrtm->tr);
object_free(nrtm->tr->object);
transaction_free(nrtm->tr); nrtm->tr=NULL;
/* Create an object and update NHR */
tr->action=(TA_CREATE | TA_UPD_NHR);
/* fprintf(stderr,"CREATE next\n"); */
object_process(tr); /* create a new one*/
result=report_transaction(tr, log_ptr, object_name, "NRTM:ADD:While creating new");
if(result==1)create_serial(tr);
}
else { /*compare the two, may be we may collapse operations*/
if(tr->object_id==nrtm->tr->object_id) {
object_free(nrtm->tr->object);
transaction_free(nrtm->tr); nrtm->tr=NULL;
/* fprintf(stderr,"DEL-ADD ->> UPDATE\n");*/
tr->action=TA_UPDATE;
object_process(tr);
report_transaction(tr, log_ptr, object_name,"NRTM:upd");
result=report_transaction(tr, log_ptr, object_name,"NRTM:upd");
if(result==1)create_serial(tr);
}
else { /* this should be a dummy object in the database(that we are going to replace with the real one */
/* or an interleaved operation*/
/* fprintf(stderr,"DEL previous\n");*/
object_process(nrtm->tr); /* delete the previous(saved) object*/
result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved)");
if(result==1)create_serial(nrtm->tr);
object_free(nrtm->tr->object);
transaction_free(nrtm->tr); nrtm->tr=NULL;
tr->action=TA_UPDATE;
dummy=isdummy(tr);
/* If we are replacing dummy with a real object update NHR */
if(dummy==1) tr->action |= TA_UPD_NHR;
/* fprintf(stderr,"UPDATE next(dummy)\n"); */
object_process(tr); /* create a new one*/
result=report_transaction(tr, log_ptr, object_name, "NRTM:ADD:While creating new");
/* check if it was dummy */
if (dummy==1)
tr->action=TA_CREATE; /* we don't want to generate DEL serial for dummy replacement*/
if(result==1)create_serial(tr);
}
}
}
else { /* brand new object*/
if(tr->object_id==0) {
/* fprintf(stderr,"CREATE new\n");*/
/* Create an object and update NHR */
tr->action=(TA_CREATE | TA_UPD_NHR);
object_process(tr);
result=report_transaction(tr, log_ptr, object_name,"NRTM:ADD:While creating new");
if(result==1)create_serial(tr);
}
else { /* this may happen because of dummies*/
/* fprintf(stderr,"CREATE new\n");*/
tr->action=TA_UPDATE;
dummy=isdummy(tr);
/* If we are replacing dummy with a real object update NHR */
if(dummy==1) tr->action |= TA_UPD_NHR;
object_process(tr);
result=report_transaction(tr, log_ptr, object_name,"NRTM:ADD:While creating new");
/* check if it was dummy */
if (dummy==1)
tr->action=TA_CREATE; /* we don't want to generate DEL serial for dummy replacement*/
if(result==1)create_serial(tr);
}
}
break;
case OP_DEL:
if(nrtm->tr){ /*saved?*/
/* fprintf(stderr,"DEL previous\n");*/
object_process(nrtm->tr); /* delete the previous(saved) object*/
result=report_transaction(nrtm->tr, log_ptr, nrtm->object_name, "NRTM:DEL:While deleting previous(saved) object");
if(result==1)create_serial(nrtm->tr);
object_free(nrtm->tr->object);
transaction_free(nrtm->tr); nrtm->tr=NULL;
}
if(tr->object_id>0){ /* save the object*/
fprintf(stderr,"SAVED\n");
tr->action=TA_DELETE;
nrtm->tr=tr;
strcpy(nrtm->object_name, object_name);
return(1);
}
else { /* this is an error*/
tr->succeeded=0; tr->error|=ERROR_U_COP;
result=report_transaction(tr, log_ptr, object_name, "NRTM:OOS:Trying to DEL non-existing object");
/* fprintf(stderr,"Lost sync. Skipping\n");*/
}
break;
default:
tr->succeeded=0; tr->error |=ERROR_U_BADOP;
break;
}
/* Free resources */
object_free(tr->object);
transaction_free(tr);
return(result);
} /* process_nrtm() */
/************************************************************
* process_updates() *
* *
* Process object in update mode *
* *
* ud_stream - pointer to UD_stream structure *
* object_name - name of the object *
* operation - operation code (OP_ADD/OP_DEL) *
* *
* Note: *
* Frees tr and tr->obj on exit *
* *
* Returns: *
* 1 - okay *
* <0 - error *
* *
************************************************************/
static int process_updates(UD_stream_t *ud_stream, Transaction_t *tr, char *object_name, int operation)
/* [<][>][^][v][top][bottom][index][help] */
{
int result=0;
Log_t *log_ptr= &(ud_stream->log);
int dummy=0;
switch(operation) {
/* Compare operations and report an error if they do not match */
case OP_ADD:
if(tr->object_id!=0) { /* trying to create, but object exists */
tr->succeeded=0; tr->error|=ERROR_U_COP;
} else {
/* Action: create the object and update NHR */
tr->action=(TA_CREATE | TA_UPD_NHR);
object_process(tr);
}
break;
case OP_UPD:
if(tr->object_id==0) { /* trying to update non-existing object*/
tr->succeeded=0; tr->error|=ERROR_U_COP;
} else {
tr->action=TA_UPDATE;
dummy=isdummy(tr);
/* If we are replacing dummy with a real object update NHR */
if(dummy==1) tr->action |= TA_UPD_NHR;
object_process(tr);
}
break;
case OP_DEL:
if(tr->object_id==0) { /* trying t delete non-existing object*/
tr->succeeded=0; tr->error|=ERROR_U_COP;
} else {
tr->action=TA_DELETE;
object_process(tr);
}
break;
default:
/* bad operation for this mode if not standalone */
if(tr->standalone) {
if(tr->object_id==0)tr->action=TA_CREATE; else tr->action=TA_UPDATE;
object_process(tr);
}
else {
tr->succeeded=0;
tr->error|=ERROR_U_BADOP;
}
break;
}
/* Make a report */
result=report_transaction(tr, log_ptr, object_name, "RIPupd:");
/* If not in standalone mode create serial and copy error transcript */
if(!tr->standalone) {
if(result==1)create_serial(tr);
ud_stream->error_script=g_strdup((tr->error_script)->str);
}
/* Free resources */
object_free(tr->object);
transaction_free(tr);
return(result);
} /* process_updates() */
/************************************************************
* *
* int process_transaction() *
* *
* Processes the transaction *
* *
* ud_stream - pointer to UD_stream_t structure *
* *
* Returns: *
* 1 - no error *
* <0- errors *
* *
************************************************************/
/* It frees the obj */
static int process_transaction(UD_stream_t *ud_stream,
/* [<][>][^][v][top][bottom][index][help] */
Object_t *obj,
char *object_name,
nic_handle_t *nh,
int operation)
{
Transaction_t *tr = NULL;
Log_t *log_ptr = &(ud_stream->log);
Attribute_t *attr=NULL;
int result;
/* start new transaction now */
tr = transaction_new(ud_stream->db_connection, obj->type);
/* Return with error if transaction cannot be created */
if (tr == NULL) return(-1);
tr->standalone=IS_STANDALONE(ud_stream->ud_mode);
tr->dummy=IS_DUMMY_ALLOWED(ud_stream->ud_mode);
tr->load_pass=ud_stream->load_pass;
tr->object=obj;
tr->nh=nh;
/* We perform no commit/rollback in the loader mode, so thread_id should be set to 0 */
if(ud_stream->load_pass!=0) { tr->thread_ins=0; tr->thread_upd=0; }
/* For the first load pass we only create objects */
if(ud_stream->load_pass==1) tr->object_id=0;
else tr->object_id=get_object_id(tr);
/* Object cannot be retrieved */
if(tr->object_id==-1) { /* DB error*/
tr->succeeded=0;
tr->error |= ERROR_U_DBS;
report_transaction(tr, log_ptr, object_name, "Object cannot be retrieved");
transaction_free(tr);
object_free(obj);
return(-1);
}
/* save the name of person/role as we need it for referential */
/* integrity check when deleting the object against names. */
/* This is needed to support legacy references by name rather */
/* then by nic_hdl */
if((tr->class_type==C_PN) || (tr->class_type==C_RO)){
attr = attribute_new(object_name);
if (attr==NULL) {
tr->succeeded=0;
tr->error |= ERROR_U_MEM;
report_transaction(tr, log_ptr, object_name, "Cannot allocate memery");
transaction_free(tr);
object_free(obj);
return(-1);
}
/* Save the value */
tr->save=g_strdup(attr->value);
}
/* Process transaction. tr and obj are freed inside the process_* functions */
if(IS_UPDATE(ud_stream->ud_mode))
/* We are in update mode */
result=process_updates(ud_stream, tr, object_name, operation);
else
/* We are in NRTM mode */
result=process_nrtm(ud_stream, tr, object_name, operation);
/* free attr if has been allocated */
if(attr) attribute_free(attr, NULL);
return(result);
}
/************************************************************
* *
* int UD_process_stream(UD_stream_t *ud_stream) *
* *
* Processes the stream *
* *
* ud_stream - pointer to UD_stream_t structure *
* *
* Returns: *
* in update mode (!standalone)(1 object processed): *
* 1 - no error *
* <0- errors *
* *
* in NRTM & standalone modes *
* total number of object processed *
* *
************************************************************/
int UD_process_stream(UD_stream_t *ud_stream)
/* [<][>][^][v][top][bottom][index][help] */
{
char line_buff[STR_XXL], object_name[STR_XXL];
GString *g_line_buff; // needed to escape apostrophes
Attribute_t *attr, *attr_split;
Attribute_t *mnt_by; /* we need this for reordering mnt_by and member_of (member_of should come after)*/
Attribute_t *nic_hdl; /* we need this for reordering nic_hdl and admin_c, etc. (admin_c should come after)*/
nic_handle_t *nh_ptr; /* To save NIC handle structure */
Object_t *obj = NULL;
Transaction_t *tr = NULL;
SQ_connection_t *sql_connection;
int start_object;
int a_type;
char *s_attr;
char *ptr;
/* here we will store the parsed nic-hdl in required format */
char nic[MAX_NH_LENGTH];
long num_skip;
struct _nrtm *nrtm;
Log_t *log_ptr= &(ud_stream->log);
time_t stime, ftime;
double obj_second1, obj_second10;
int result;
int operation=0;
int interrupt=0;
int do_update;
int default_ud_mode = ud_stream->ud_mode;
nrtm=ud_stream->nrtm;
start_object = 1;
/* Allocate line bufer */
if ((g_line_buff = g_string_sized_new(STR_XXL)) == NULL){
fprintf(stderr, "E: cannot allocate gstring\n");
return(-1);
}
/* Check connection to the database */
if(mysql_ping(ud_stream->db_connection)) {
fprintf(stderr, "D: ERROR: no SQL connection\n");
g_string_free(g_line_buff, TRUE);
return(-1);
}
fprintf(stderr, "OK\n");
sql_connection=ud_stream->db_connection;
/* This is useful for loading DB from huge disk file. */
/* We may start from <num_skip>th object */
num_skip=ud_stream->num_skip;
if(num_skip>0) fprintf(stderr, "skipping %lu records\n", num_skip);
/* Start timer for statistics */
stime=time(NULL);
/* Main loop. Reading input stream line by line */
/* Empty line signals to start processing an object, if we have it */
while (fgets(line_buff, STR_XXL, ud_stream->stream) != NULL) {
switch (line_type(line_buff)) {
case LINE_ATTRIBUTE:
if (start_object == 1) {
/* This is for loading stuff */
/* if(num_skip>0){ fprintf(stderr, "\r%10lu", num_skip); num_skip--; log_ptr->num_ok++; break; } */
mnt_by=NULL;
nic_hdl=NULL;
nh_ptr=NULL;
obj = object_new(line_buff);
}
if (obj) {
g_string_sprintf(g_line_buff, "%s", line_buff);
g_line_buff=escape_apostrophes(g_line_buff);
if(start_object){
/* If this is the first attribute(==object name/type) */
start_object=0;
strncpy(object_name, g_line_buff->str, g_line_buff->len-1);
*(object_name+g_line_buff->len-1)='\0';
fprintf(stderr, "D: object: [%s] ", object_name);
}
attr = attribute_new(g_line_buff->str);
if (attr != NULL) {
switch (a_type=(attr->type)) {
case A_MB: mnt_by=attr;
break;
case A_NH:
/* Parse the string into nh structure */
/* In case of an AUTO NIC handle check the ID in the database */
/* Possible errors leave to core processing */
if(NH_parse(attr->value, &nh_ptr) == 0) {
/* fprintf(stderr, "D:parsing NIC: [%s]\n", attr->value); */
/* Check if we can allocate it */
if((result = NH_check(nh_ptr, sql_connection))>0){
/* Convert nh to the database format */
NH_convert(nic, nh_ptr);
/* fprintf(stderr, "D:NIC:[%s]\n", nic); */
/* Replace NIC handle in the string which is copied to the text object */
sprintf(line_buff, g_line_buff->str);
ptr = strstr(line_buff, attr->value);
/* compose new attribute string */
strcpy(ptr, nic);
g_string_sprintf(g_line_buff, line_buff);
g_string_sprintfa(g_line_buff, "\n");
/* Update the attribute */
attribute_upd(attr, attr->type, nic);
/* fprintf(stderr, "D:attribute updated\n"); */
}
}
nic_hdl=attr;
break;
case A_PN:
case A_RO:
case A_MR:
case A_SD:
case A_RZ:
case A_NS: /*these attributes may appear several on the line - split them*/
while((s_attr=s_split(attr->value))){
attr_split = attribute_new1(a_type, s_attr);
obj->attributes = g_slist_append(obj->attributes, attr_split);
}
attribute_free(attr, NULL);
attr=NULL;
break;
default: break;
}
g_string_sprintfa(obj->object, "%s", g_line_buff->str);
if(attr){ obj->attributes = g_slist_append(obj->attributes, attr);
}
}
}
break;
case LINE_COMMENT:
break;
case LINE_EOF:
break;
case LINE_ADD:
/* restore the default operation mode */
operation=OP_ADD;
ud_stream->ud_mode=default_ud_mode;
break;
case LINE_OVERRIDE_ADD:
/* for override - switch the dummy bit on */
operation=OP_ADD;
ud_stream->ud_mode=default_ud_mode|B_DUMMY;
break;
case LINE_UPD:
/* restore the default operation mode */
operation=OP_UPD;
ud_stream->ud_mode=default_ud_mode;
break;
case LINE_OVERRIDE_UPD:
/* for override - switch the dummy bit on */
operation=OP_UPD;
ud_stream->ud_mode=default_ud_mode|B_DUMMY;
break;
case LINE_DEL:
/* restore the default operation mode */
operation=OP_DEL;
ud_stream->ud_mode=default_ud_mode;
break;
case LINE_OVERRIDE_DEL:
/* for override - switch the dummy bit on */
operation=OP_DEL;
ud_stream->ud_mode=default_ud_mode|B_DUMMY;
break;
case LINE_EMPTY:
/* Indicate that we have complete object, so a new one will be collected later */
start_object=1;
/* start processing the object */
if (obj == NULL) break; /* may be the previous lines were just garbage*/
/* reorder some attributes */
if(mnt_by){
obj->attributes = g_slist_remove(obj->attributes, mnt_by);
obj->attributes = g_slist_insert(obj->attributes, mnt_by, 1);
}
if(nic_hdl){
obj->attributes = g_slist_remove(obj->attributes, nic_hdl);
obj->attributes = g_slist_insert(obj->attributes, nic_hdl, 1);
}
/* start new transaction now */
result=process_transaction(ud_stream, obj, object_name, nh_ptr, operation);
/* process_transaction() frees tr and obj structures, */
/* so make sure we'll not reference these objects in the future */
obj=NULL; tr=NULL; operation=OP_NOOP;
ud_stream->ud_mode=default_ud_mode;
/* this is a good place for quick interrupt */
do_update=CO_get_do_update();
if (do_update) interrupt=0; else interrupt=1;
/* we still need to exit in update server mode (only 1 object at a time */
if (IS_UPDATE(ud_stream->ud_mode) && (!IS_STANDALONE(ud_stream->ud_mode))) interrupt=1;
break;
default:
fprintf(stderr, "ERROR: Bad line type\n");
} /* switch */
/* Finish processing if interrupt has been set */
if (interrupt) break;
} /* while */
/* Some postprocessing */
if(!IS_UPDATE(ud_stream->ud_mode)){
/* We are in NRTM mode */
/* Clean up */
fclose(ud_stream->stream);
unlink(tmpfile2);
/* In NRTM mode there may be a saved object that is unprocessed */
if(nrtm->tr){ /*saved backlog?*/
object_process(nrtm->tr); /* delete the previous(saved) object*/
result=report_transaction(nrtm->tr, &(ud_stream->log), nrtm->object_name,
"NRTM:DEL:While deleting previous(saved) object");
if(result==1) create_serial(nrtm->tr);
object_free(nrtm->tr->object);
transaction_free(nrtm->tr); nrtm->tr=NULL;
}
}
/* That's all. Free GString */
g_string_free(g_line_buff, TRUE);
/* Calculate some statistics */
ftime=time(NULL);
obj_second1 = (float)(log_ptr->num_ok)/(ftime-stime);
obj_second10 = (float)(log_ptr->num_ok+log_ptr->num_failed)/(ftime-stime);
/* Print the report */
if(IS_STANDALONE(ud_stream->ud_mode) || (!IS_UPDATE(ud_stream->ud_mode))) {
/* printf("\n\n******** report **********\n%d objects OK\n%d objects failed\n",
log_ptr->num_ok, log_ptr->num_failed); */
fprintf(log_ptr->logfile,"\n******** report **********\n");
fprintf(log_ptr->logfile," %d objects OK (%5.2f obj/s)\n", log_ptr->num_ok, obj_second1);
fprintf(log_ptr->logfile," %d objects failed\n", log_ptr->num_failed);
fprintf(log_ptr->logfile," average processing time %5.2f obj/s (%5.2f obj/min)\n",
obj_second10, obj_second10*60);
result=log_ptr->num_ok+log_ptr->num_failed;
}
return(result);
} /* UD_process_stream */