/*{ ** Name: IIME_adAddTag - Add a node of allocated memory to a tag. ** ** Description: ** This routine is called when a new block of dynamic memory is being ** allocated under a tag. It is called by MEdoAlloc. The job ** of this routine is to store the allocated memory so that it ** will be freed with the other blocks allocated under this tag when ** MEtfree is called. ** ** It works by checking the hash table for an METAGNODE for this tag. ** If none is found, a new METAGNODE is allocated for this tag. ** Then the block of memory is put on the QUEUE for the METAGNODE. ** ** Inputs: ** tag The tag under which this block of memory is ** being allocated. ** ** node The block of memory being allocated. ** ** Side Effects: ** This will take a node off freelist, and if necessary will allocate ** dynamic memory. ** ** History: ** 5-dec-1989 (Joe) ** First Written */ VOID IIME_atAddTag( i4 tag, ME_NODE *node) { register METAGNODE **first; # ifdef OS_THREADS_USED CS_synch_lock( &MEtaglist_mutex ); # endif /* OS_THREADS_USED */ /* ** Note that first is a pointer to a pointer. ** The loop will cause a return from the routine if the tag already ** has an METAGNODE in the hash table. ** If the loop finishes, then first will point to the pointer ** that must contain the METAGNODE. */ for (first = &(htab[tag%256]); *first != NULL; first = &((*first)->met_hash)) { if ((*first)->met_tag == tag) { (void)QUinsert((QUEUE *) node, (QUEUE *) (*first)->met_list.MElast); # ifdef OS_THREADS_USED CS_synch_unlock( &MEtaglist_mutex ); # endif /* OS_THREADS_USED */ return; } } if (freelist == NULL) { register METAGNODE *next; register int i; freelist = (METAGNODE *) MEreqmem(0, sizeof(METAGNODE)*50, TRUE, NULL); for (i = 0, next = freelist; i < 49; i++) { next->met_hash = next + 1; next = next->met_hash; } next->met_hash = NULL; } *first = freelist; freelist = freelist->met_hash; (*first)->met_hash = NULL; (*first)->met_tag = tag; QUinit((QUEUE *)&((*first)->met_list)); (void)QUinsert((QUEUE *) node, (QUEUE *) (*first)->met_list.MElast); # ifdef OS_THREADS_USED CS_synch_unlock( &MEtaglist_mutex ); # endif /* OS_THREADS_USED */ return; }
GCADM_SCB * gcadm_new_scb( i4 aid, PTR gca_cb ) { GCADM_SCB *scb; scb = (GCADM_SCB *)(* GCADM_global.alloc_rtn )( sizeof( GCADM_SCB ) ); if ( scb ) { MEfill( sizeof( GCADM_SCB ), 0, scb); scb->buffer = (char *) (*GCADM_global.alloc_rtn) ( GCADM_global.gcadm_buff_len ); } if ( scb->buffer ) { scb->aid = aid; scb->gca_cb = gca_cb; QUinit( &scb->q ); QUinsert( &scb->q, GCADM_global.scb_q.q_prev); } else { (*GCADM_global.dealloc_rtn)( (PTR)scb ); scb = NULL; } return( scb ); }
RETCODE SQL_API SQLSetConnectOption( SQLHDBC hdbc, UWORD fOption, SQLUINTEGER vParam) { RETCODE rc, traceRet = 1; pDBC pdbc = (pDBC)hdbc; IISETCONNECTOPTION_PARAM *iiSetConnectOptionParam; ODBC_TRACE_ENTRY(ODBC_TR_TRACE, IITraceSQLSetConnectOption(hdbc, fOption, vParam), traceRet); if (!hdbc) { ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, SQL_INVALID_HANDLE)); return SQL_INVALID_HANDLE; } /* ** If the driver isn't loaded yet, set a placeholder to do this ** later. */ if ( !IISetConnectOption ) { iiSetConnectOptionParam = (IISETCONNECTOPTION_PARAM *)MEreqmem(0, sizeof(IISETCONNECTOPTION_PARAM), TRUE, NULL); QUinsert((QUEUE *)iiSetConnectOptionParam, &pdbc->setConnectOption_q); iiSetConnectOptionParam->ConnectionHandle = hdbc; iiSetConnectOptionParam->Option = fOption; iiSetConnectOptionParam->Value = vParam; pdbc->setConnectOption_count++; ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, SQL_SUCCESS)); return SQL_SUCCESS; } else { resetErrorBuff(pdbc, SQL_HANDLE_DBC); rc = IISetConnectOption( pdbc->hdr.driverHandle, fOption, vParam); applyLock(SQL_HANDLE_DBC, pdbc); if (rc != SQL_SUCCESS) { pdbc->hdr.driverError = TRUE; pdbc->errHdr.rc = rc; } else if (fOption == SQL_ATTR_AUTOCOMMIT) pdbc->autocommit = TRUE; releaseLock(SQL_HANDLE_DBC, pdbc); } ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, rc)); return rc; }
void gcd_del_rcb( GCD_RCB *rcb ) { GCD_CCB *ccb = rcb->ccb; u_i2 dflt_len = ccb->max_buff_len + (u_i2)GCD_global.nl_hdr_sz; /* ** If RCB has no buffer or has a default sized ** buffer, save RCB on free queue for re-use. ** Otherwise, free the RCB. */ if ( ! rcb->buf_max ) QUinsert( &rcb->q, GCD_global.rcb_q.q_prev ); else if ( rcb->buf_max == dflt_len ) QUinsert( &rcb->q, ccb->rcb_q.q_prev ); else gcd_free_rcb( rcb ); return; }
GCD_CCB * gcd_new_ccb( void ) { GCD_CCB *ccb; if ( ! (ccb = (GCD_CCB *)QUremove( GCD_global.ccb_free.q_next )) ) if ( (ccb = (GCD_CCB *)MEreqmem( 0, sizeof(GCD_CCB), FALSE, NULL )) ) ccb->id = GCD_global.ccb_total++; if ( ! ccb ) gcu_erlog(0, GCD_global.language, E_GC4808_NO_MEMORY, NULL, 0, NULL); else { u_i4 id = ccb->id; MEfill( sizeof( GCD_CCB ), 0, (PTR)ccb ); ccb->id = id; ccb->use_cnt = 1; ccb->max_buff_len = 1 << DAM_TL_PKT_MIN; ccb->tl.proto_lvl = DAM_TL_PROTO_1; ccb->xact.auto_mode = GCD_XACM_DBMS; ccb->api.env = NULL; QUinit( &ccb->q ); QUinit( &ccb->rcb_q ); QUinit( &ccb->gcc.send_q ); QUinit( &ccb->msg.msg_q ); QUinit( &ccb->msg.info_q ); QUinit( &ccb->stmt.stmt_q ); QUinit( &ccb->rqst.rqst_q ); GCD_global.ccb_active++; QUinsert( &ccb->q, &GCD_global.ccb_q ); if ( GCD_global.gcd_trace_level >= 5 ) TRdisplay( "%4d GCD new CCB (%d)\n", ccb->id, ccb->id ); } return( ccb ); }
static void gcadm_event( GCADM_RCB *rcb ) { GCADM_SCB *scb=rcb->scb; if ( gcadm_active ) { if ( GCADM_global.gcadm_trace_level >= 5 ) TRdisplay( "%4d GCADM event: queueing event %s \n", scb->aid, events[ rcb->event ]); QUinsert( &rcb->q, GCADM_global.rcb_q.q_prev); return; } gcadm_active = TRUE; gcadm_sm( rcb ); while( ( rcb = (GCADM_RCB *)QUremove( GCADM_global.rcb_q.q_next )) ) { if ( GCADM_global.gcadm_state != GCADM_ACTIVE ) { if ( GCADM_global.gcadm_trace_level >= 1 ) TRdisplay( "%4d GCADM event: ADM not active\n", -1 ); gcadm_free_rcb ( rcb ); } else { if( GCADM_global.gcadm_trace_level >= 5 ) TRdisplay( "%4d GCADM event: processing queued event %s \n", scb->aid, events[ rcb->event ]); gcadm_sm( rcb ); } } gcadm_active = FALSE; return; }
void gcd_del_cib( GCD_CIB *cib ) { GCD_CAPS *caps; char buff[16]; u_i2 i; GCD_global.cib_active--; MOulongout( 0, (u_i8)cib->id, sizeof( buff ), buff ); MOdetach( GCD_MIB_DBMS, buff ); while( (caps = (GCD_CAPS *)QUremove( cib->caps.q_next )) ) { MEfree( caps->data ); MEfree( (PTR)caps ); } if ( cib->database ) MEfree( (PTR)cib->database ); if ( cib->username ) MEfree( (PTR)cib->username ); if ( cib->password ) MEfree( (PTR)cib->password ); for( i = 0; i < cib->parm_cnt; i++ ) MEfree( (PTR)cib->parms[i].value ); if ( GCD_global.gcd_trace_level >= 6 ) TRdisplay( "%4d GCD del CIB (%d)\n", -1, cib->id ); if ( cib->parm_max < ARR_SIZE( GCD_global.cib_free ) ) QUinsert( &cib->q, GCD_global.cib_free[ cib->parm_max ].q_prev ); else { MEfree( (PTR)cib ); GCD_global.cib_total--; } return; }
PTR MEreqmem( u_i2 tag, SIZE_TYPE size, bool zero, STATUS *status) { PTR block=NULL; register ME_NODE *node; /* the node to return */ register ME_NODE *start; /* for searching free list */ register ME_NODE *this; /* block to get node from */ register ME_NODE *frag; /* fragment block */ ME_NODE *tmp; /* not register for MEadd */ SIZE_TYPE nsize; /* nsize node to obtain */ SIZE_TYPE fsize; /* size of 'this' fragment block */ SIZE_TYPE newstuff; /* size to add to process, or 0 */ SIZE_TYPE prev_actual; /* rescan free list? */ SIZE_TYPE alloc_pages; CL_ERR_DESC err_code; STATUS MEstatus = OK; i_meuser += size; if (!size) MEstatus = ME_NO_ALLOC; if( !MEsetup ) MEinitLists(); /* ** Try to do the allocation. */ if( MEstatus == OK ) { nsize = SIZE_ROUND( size ); /* ** Get memory with malloc(). */ if( MEadvice == ME_USER_ALLOC ) { if( (node = (ME_NODE *)malloc( nsize )) == NULL ) MEstatus = ME_GONE; } /* ** Get block from private free list. */ else { # ifdef OS_THREADS_USED CS_synch_lock( &MEfreelist_mutex ); # endif /* OS_THREADS_USED */ /* ** Look on free list for 1st block big enough ** to hold request. This linear search can be slow. */ start = (ME_NODE *)&MEfreelist; this = MEfreelist.MEfirst; while ( this != NULL && this != start && this->MEsize < nsize ) this = this->MEnext; if( this == NULL ) MEstatus = ME_CORRUPTED; /* ** At this point, we are in one of three states: ** 1) Corrupted memory; MEstatus != OK ** 2) this is good node, this != start ** 3) No good node; this == start; */ if ( MEstatus == OK ) { /* ** If nothing on free list is big enough ** get one or more standard blocks from system, ** take what is needed and add remainder ** to free list. */ if (this != start) { /* take right off the free list */ newstuff = 0; } else /* this == start */ { /* * Expand the free list by calling getpages * newstuff holds the number of pages needed */ newstuff = (nsize + ME_MPAGESIZE-1)/ME_MPAGESIZE; /* if first time allocation, get enough for MO overhead */ if ( (prev_actual = i_meactual) == (SIZE_TYPE) 0 ) newstuff += 4; # ifdef OS_THREADS_USED CS_synch_unlock( &MEfreelist_mutex ); # endif /* OS_THREADS_USED */ MEstatus = MEget_pages(ME_SPARSE_MASK, newstuff, NULL, (PTR *)&tmp, &alloc_pages, &err_code); # ifdef OS_THREADS_USED CS_synch_lock( &MEfreelist_mutex ); # endif /* OS_THREADS_USED */ if (MEstatus == OK) { /* now we need to find where to put this new memory on the sorted free list - we search in reverse */ tmp->MEsize = newstuff * ME_MPAGESIZE; this = MEfreelist.MElast; while (start != this && this != NULL && this > tmp) this = this->MEprev; if (this != start && NEXT_NODE(this) == tmp) { this->MEsize += tmp->MEsize; } else { (void)QUinsert( (QUEUE *) tmp, (QUEUE *)this ); this = tmp; } if (this->MEnext != start && NEXT_NODE(this) == this->MEnext) { this->MEsize += this->MEnext->MEsize; (void)QUremove( (QUEUE *) this->MEnext); } /* ** While the free list mutex was released, another ** thread may have freed up a big enough piece of ** memory for our needs, or may have extended the ** free list. ** If that's the case, research the free list; ** we'll find either a right-sized node or ** the new memory we just added to the free list. */ if ( prev_actual != i_meactual ) { this = MEfreelist.MEfirst; while ( this != NULL && this != start && this->MEsize < nsize ) this = this->MEnext; if( this == NULL ) MEstatus = ME_CORRUPTED; } } else if (MEstatus == ME_OUT_OF_MEM) MEstatus = ME_GONE; } /* ** At this point, we can be in two states. ** 1) Corrupted memory, MEstatus != OK ** 2) 'this' is an OK node from the free list. */ if ( MEstatus == OK ) { node = this; /* ** if this is correct size or would ** leave useless block in chain ** just move block to allocated list ** else ** grab what is needed from 'this' ** block and then update 'this' */ fsize = node->MEsize - nsize; if ( fsize <= sizeof(ME_NODE) ) { (void)QUremove( (QUEUE *) node ); /* fudge size in node to eat leftover amount. */ fsize = 0; nsize = node->MEsize; } else /* make fragment block */ { /* ** Make a leftover block after the ** allocated space in node, in 'this' */ frag = (ME_NODE *)((char *) node + nsize ); frag->MEsize = fsize; frag->MEtag = 0; /* remove node, add fragment to free list */ (void)QUremove( (QUEUE *) node ); MEstatus = MEfadd( frag, FALSE ); } /* fragment left over */ /* Increment meactual while mutex held */ i_meactual += nsize; } /* Got a node */ } /* free list search OK */ # ifdef OS_THREADS_USED CS_synch_unlock( &MEfreelist_mutex ); # endif /* OS_THREADS_USED */ } /* ME_USER_ALLOC */ /* ** At this point we are in one of two states: ** 1. Corrupted, MEstatus != OK. ** 2. Have a 'node' to use, from freelist or malloc. ** The freelist is consistant, but the allocated list is ** not setup for the node. "nsize" is the actual size of "node". */ if( MEstatus == OK ) { /* splice into allocated object queue */ if (0 == tag) { # ifdef OS_THREADS_USED CS_synch_lock( &MElist_mutex ); # endif /* OS_THREADS_USED */ (void)QUinsert( (QUEUE *) node, (QUEUE *) MElist.MElast ); # ifdef OS_THREADS_USED CS_synch_unlock( &MElist_mutex ); # endif /* OS_THREADS_USED */ } else { IIME_atAddTag(tag, node); } /* Set values in block to be returned */ node->MEtag = tag; node->MEsize = nsize; node->MEaskedfor = size; /* Fill in the returned pointer */ block = (PTR)((char *)node + sizeof(ME_NODE)); if (zero) MEfill( (nsize - sizeof(ME_NODE)), 0, block); } /* got node OK */ } if (status != NULL) *status = MEstatus; if (MEstatus != OK) return((PTR)NULL); else return(block); }
II_EXTERN IIAPI_ENVHNDL * IIapi_initAPI( II_LONG version, II_LONG timeout ) { IIAPI_ENVHNDL *envHndl; IIAPI_ENVHNDL *defEnvHndl; II_BOOL first_init = FALSE; STATUS status; char *env; if ( ! IIapi_static ) { /* ** Perform global initializations which are ** environment independent. */ first_init = TRUE; if ( ! ( IIapi_static = (IIAPI_STATIC *) MEreqmem( 0, sizeof( IIAPI_STATIC ), TRUE, &status ) ) ) return( NULL ); QUinit( &IIapi_static->api_env_q ); if ( MUi_semaphore( &IIapi_static->api_semaphore ) != OK ) goto muiFail; if ( MEtls_create( &IIapi_static->api_thread ) != OK ) goto metFail; /* ** Initialize sub-systems. */ IIAPI_INITTRACE(); IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_initAPI: initializing API.\n" ); /* ** Make sure II_SYSTEM or similar is set to provide useful feedback ** rather than just failing in one of following subsystems. */ NMgtAt( SYSTEM_LOCATION_VARIABLE, &env ); if ( env == NULL || *env == EOS ) { IIAPI_TRACE( IIAPI_TR_FATAL ) ( "IIapi_initAPI: error - %s not set.\n", SYSTEM_LOCATION_VARIABLE ); goto adfFail; } IIapi_init_mib(); if ( ! IIapi_initADF() ) goto adfFail; if ( ! IIapi_initGCA(timeout) ) goto gcaFail; /* Initialize the unicode collation values */ IIapi_static->api_unicol_init = FALSE; IIapi_static->api_ucode_ctbl = NULL; IIapi_static->api_ucode_cvtbl = NULL; /* ** Create the default environment. */ if ( ! (IIapi_static->api_env_default = (PTR)IIapi_createEnvHndl( IIAPI_VERSION_1 )) ) goto defFail; /* Spoken Language to use */ if( ( status = ERlangcode( (char *)NULL, &IIapi_static->api_slang ) != OK) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_initAPI: error initializing lang 0x%x\n", status ); return( NULL ); } /* ** The SQL state machines are used by default prior to ** IIapi_connect() being called, so make sure they are ** initialized. */ if ( IIapi_sm_init( IIAPI_SMT_SQL ) != IIAPI_ST_SUCCESS ) goto envFail; } /* ** Now do environment specific initialization. */ defEnvHndl = IIapi_defaultEnvHndl(); if ( version == IIAPI_VERSION_1 ) { /* ** Version 1 initializers share the default ** environment. Keep track of the number of ** initializers so that IIapi_termAPI() can ** determine when to do global shutdown. */ envHndl = defEnvHndl; MUp_semaphore( &defEnvHndl->en_semaphore ); defEnvHndl->en_initCount++; MUv_semaphore( &defEnvHndl->en_semaphore ); } else { /* ** Create a new environment for the initializer. ** These environments are saved on the global ** environment queue. The caller may also make ** API calls using the default environment handle, ** so increment the default environment handle ** initialization count. */ if ( (envHndl = IIapi_createEnvHndl( version )) ) { MUp_semaphore( &IIapi_static->api_semaphore ); QUinsert( (QUEUE *)envHndl, &IIapi_static->api_env_q ); MUv_semaphore( &IIapi_static->api_semaphore ); MUp_semaphore( &defEnvHndl->en_semaphore ); defEnvHndl->en_initCount++; MUv_semaphore( &defEnvHndl->en_semaphore ); } else { /* ** We may need to undo the global initialization. ** If not, the NULL environment handle will simply ** be returned. */ if ( first_init ) goto envFail; } } return( envHndl ); envFail: IIapi_deleteEnvHndl( (IIAPI_ENVHNDL *)IIapi_static->api_env_default ); defFail: IIapi_termGCA(); gcaFail: IIapi_termADF(); adfFail: IIAPI_TERMTRACE(); MEtls_destroy( &IIapi_static->api_thread, NULL ); metFail: MUr_semaphore( &IIapi_static->api_semaphore ); muiFail: MEfree( (PTR)IIapi_static ); IIapi_static = NULL; return( NULL ); }
void gcd_del_ccb( GCD_CCB *ccb ) { if ( ccb->use_cnt ) ccb->use_cnt--; if ( ccb->use_cnt ) { if ( GCD_global.gcd_trace_level >= 5 ) TRdisplay( "%4d GCD del CCB (use count %d)\n", ccb->id, ccb->use_cnt ); } else { GCD_RCB *rcb; GCD_SCB *scb; QUEUE *q; QUremove( &ccb->q ); GCD_global.ccb_active--; if ( ccb->qry.crsr_name ) MEfree( (PTR)ccb->qry.crsr_name ); if ( ccb->qry.schema_name ) MEfree( (PTR)ccb->qry.schema_name ); if ( ccb->qry.proc_name ) MEfree( (PTR)ccb->qry.proc_name ); if ( ccb->qry.qtxt_max ) MEfree( (PTR)ccb->qry.qtxt ); if ( ccb->rqst.rqst_id0 ) MEfree( (PTR)ccb->rqst.rqst_id0 ); if ( ccb->rqst.rqst_id1 ) MEfree( (PTR)ccb->rqst.rqst_id1 ); if ( ccb->client_user ) MEfree( (PTR)ccb->client_user ); if ( ccb->client_host ) MEfree( (PTR)ccb->client_host ); if ( ccb->client_addr ) MEfree( (PTR)ccb->client_addr ); gcd_free_qdata( &ccb->qry.svc_parms ); gcd_free_qdata( &ccb->qry.qry_parms ); gcd_free_qdata( &ccb->qry.all_parms ); /* ** Free control blocks and request queues. */ if ( ccb->cib ) gcd_del_cib( ccb->cib ); if ( ccb->xact.savepoints ) gcd_release_sp( ccb, NULL ); if ( ccb->msg.xoff_pcb ) gcd_del_pcb( (GCD_PCB *)ccb->msg.xoff_pcb ); if ( ccb->gcc.abort_rcb ) gcd_del_rcb( (GCD_RCB *)ccb->gcc.abort_rcb ); while( (scb = (GCD_SCB *)QUremove( ccb->stmt.stmt_q.q_next )) ) { gcd_free_qdata( &scb->column ); MEfree( (PTR)scb ); } while( (rcb = (GCD_RCB *)QUremove( ccb->gcc.send_q.q_next )) ) gcd_del_rcb( rcb ); while( (rcb = (GCD_RCB *)QUremove( ccb->msg.msg_q.q_next )) ) gcd_del_rcb( rcb ); while( (rcb = (GCD_RCB *)QUremove( ccb->msg.info_q.q_next )) ) gcd_del_rcb( rcb ); /* Free RCB must be physically freed */ while( (rcb = (GCD_RCB *)QUremove( ccb->rcb_q.q_next )) ) gcd_free_rcb( rcb ); while( (q = QUremove( ccb->rqst.rqst_q.q_next )) ) MEfree( (PTR)q ); /* ** Save CCB on free queue. */ QUinsert( &ccb->q, GCD_global.ccb_free.q_prev ); if ( GCD_global.gcd_trace_level >= 5 ) TRdisplay( "%4d GCD del CCB (%d)\n", ccb->id, ccb->id ); } return; }
STATUS MEfadd( ME_NODE *block, i4 releasep) { register ME_NODE *this; register ME_NODE *start; register ME_NODE *nextblk; /* 1st address after end of 'block' */ STATUS MEstatus; MEstatus = OK; if ( block == NULL ) { MEstatus = ME_00_PTR; } else if ( OUT_OF_DATASPACE(block) ) { MEstatus = ME_OUT_OF_RANGE; } else { nextblk = NEXT_NODE(block); /* ** The freelist IS sorted. We might be able to take ** advantage of this to speed up this linear search. ** In practice the freelist is usually much ** smaller than the allocated list, so it might not ** really matter (daveb). */ /* adding inside existing freelist */ start = (ME_NODE *)&MEfreelist; this = MEfreelist.MEfirst; while ( this != NULL && this != start && this < nextblk ) this = this->MEnext; if( this == NULL ) MEstatus = ME_CORRUPTED; /* ** this->MEprev points to free node before 'block', the one ** to free. this points to the block in the free ** list following 'block' to free. */ if ( MEstatus == OK ) { block->MEaskedfor = 0; (void)QUinsert( (QUEUE *) block, (QUEUE *) this->MEprev ); /* Coalesce backwards until this is the start of the queue */ this = block; while( this->MEprev != start && this->MEprev != this && NEXT_NODE(this->MEprev) == this ) { block = this->MEprev; block->MEsize += this->MEsize; (void)QUremove( (QUEUE *) this ); this = block; } /* Coalesce forwards until the queue goes back to the start */ while( this->MEnext != start && NEXT_NODE(this) == this->MEnext ) { this->MEsize += this->MEnext->MEsize; (void)QUremove( (QUEUE *) this->MEnext ); } } } return(MEstatus); }
/* ** Name: GClanman_listen ** Description: ** This is the listen thread for lanman. It runs a syncronous accept() ** on the listen socket. When complete it Q's the completetion to ** the completed event Q. When accept completes, this thread returns. ** A new one will be created when GClanman() gets the request to ** repost the listen. ** History: ** 11-nov-93 (edg) ** created. ** 29-jun-2000 (somsa01) ** Use GCc_listen_port for the ncb_name. ** 16-mar-2001 (somsa01) ** Set node_id to ncb_callname. ** 06-Aug-2009 (Bruce Lunsford) Sir 122426 ** Convert GCC completion queue mutex to a critical section ** to improve performance (less overhead). ** Since _beginthreadex() is now used to start this thread, ** use _endthreadex() to end it. */ VOID GClanman_listen( VOID *parms ) { GCC_P_PLIST *parm_list = (GCC_P_PLIST *)parms; PCB *pcb; STATUS status = OK; REQUEST_Q *rq; SECURITY_ATTRIBUTES sa; iimksec (&sa); /* ** Initialize the listen node_id to NULL. */ parm_list->function_parms.listen.node_id = NULL; /* ** Initialize fields of the Listen_Ncb */ memset( &Listen_Ncb, 0, sizeof(NCB) ); Listen_Ncb.ncb_buffer = parm_list->buffer_ptr; Listen_Ncb.ncb_length = (USHORT)parm_list->buffer_lng; Listen_Ncb.ncb_command = NCBLISTEN; Listen_Ncb.ncb_lana_num = lana_num; *Listen_Ncb.ncb_callname = (unsigned char)NULL; STmove( "*", ' ', NCBNAMSZ, Listen_Ncb.ncb_callname ); *Listen_Ncb.ncb_name = (unsigned char)NULL; STcopy( GCc_listen_port, Listen_Ncb.ncb_name ); /* ** Now we can do the NCBLISTEN request. Block until it completes. */ Netbios( &Listen_Ncb ); if ( Listen_Ncb.ncb_retcode != NRC_GOODRET ) { status = (int)Listen_Ncb.ncb_retcode; goto sys_err; } /* ** Allocate Protcol Control Block specific to this driver and put into ** parm list */ pcb = (PCB *) malloc( sizeof(PCB) ); if (pcb == NULL) { status = errno; goto sys_err; } memset( pcb, 0, sizeof( *pcb ) ); parm_list->pcb = (char *)pcb; /* ** Set node_id to the node name of the partner. */ parm_list->function_parms.listen.node_id = STalloc(Listen_Ncb.ncb_callname); /* ** Now assign the pcb's send and receive NCB's the local session number ** returned by listen for further communications. */ pcb->s_ncb.ncb_lsn = pcb->r_ncb.ncb_lsn = Listen_Ncb.ncb_lsn; /* ** Now create handles for the read and write event handles in the ** NCB. These are created with manual reset as cautioned by the ** programmer's guide so a ResetEvent MUST be done on them. */ if ((pcb->s_ncb.ncb_event = CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL) { status = GetLastError(); goto sys_err; } if ((pcb->r_ncb.ncb_event = CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL) { status = GetLastError(); CloseHandle( pcb->s_ncb.ncb_event ); pcb->s_ncb.ncb_event = NULL; goto sys_err; } sys_err: if (status != OK) { SETWIN32ERR(&parm_list->system_status, status, ER_create); parm_list->generic_status = GC_LISTEN_FAIL; } /* ** Now allocate a request q structure, stick it into complete q, and ** raise the GCC_COMPLETE event. */ if ( (rq = (REQUEST_Q *)MEreqmem(0, sizeof(*rq), TRUE, NULL ) ) != NULL ) { rq->plist = parm_list; /* ** Get critical section for completion Q. */ EnterCriticalSection( &GccCompleteQCritSect ); /* ** Now insert the completed request into the completed Q. */ QUinsert( &rq->req_q, &IIGCc_proto_threads.completed_head ); /* ** Exit/leave critical section for completion Q */ LeaveCriticalSection( &GccCompleteQCritSect ); /* ** raise the completion event to wake up GCexec. */ if ( !SetEvent( hAsyncEvents[GCC_COMPLETE] ) ) { /* ** ruh roh. We're screwed if this event can't be signaled. */ status = GetLastError(); GCTRACE(1)("GClanman_listen, SetEvent error = %d\n", status ); } } else { /* ** ruh-roh. MEreqmem failed. Selious tlouble. Not sure what to ** do about it at this point since if it failed we can't notify ** the completion routine. For now, just return (exit thread) ** which will probably have the effect of blocking all incoming ** connections. */ } _endthreadex(0); }
/* ** Name: GClanman ** Description: ** Main entry point for the window's NT lan manager protocol driver. This ** driver is essentially just a dispatcher -- it runs in the primary ** GCC thread and mostly just Q's things to do to the constantly running ** aynchronous request thread. It may also start a listen thread if ** it is a LISTEN request. ** ** The following functions are handled: ** GCC_OPEN - call GClanman_open ** GCC_LISTEN - start listen thread ** GCC_SEND - Q request for asynch thread ** GCC_RECEIVE - Q request for asynch thread ** GCC_CONNECT - Q request for asynch thread ** GCC_DISCONN - Q request for asynch thread ** History: ** 11-Nov-93 (edg) ** Original. ** 06-Aug-2009 (Bruce Lunsford) Sir 122426 ** Remove mutexing around calls to GCA service completion routine ** as it is no longer necessary, since GCA is thread-safe...removes ** calls to GCwaitCompletion + GCrestart. Should improve peformance. ** Convert CreateThread() to _beginthreadex() which is recommended ** when using C runtime. */ STATUS GClanman( i4 function_code, GCC_P_PLIST * parm_list) { STATUS generror = 0; int status = 0; int tid; HANDLE hThread; REQUEST_Q *rq; SECURITY_ATTRIBUTES sa; iimksec (&sa); CLEAR_ERR(&parm_list->system_status); /* ** set error based on function code and determine whether we got a ** valid function. */ switch (function_code) { case GCC_OPEN: is_comm_svr = TRUE; GCTRACE(2) ("GClanman: Function = OPEN\n" ); return GClanman_open( parm_list ); case GCC_LISTEN: GCTRACE(2) ("GClanman: Function = LISTEN\n" ); generror = GC_LISTEN_FAIL; /* ** For Lanman, the peer is always remote. */ parm_list->options = 0; /* ** Spawn off a thread to handle the listen request */ hThread = (HANDLE)_beginthreadex(&sa, GC_STACK_SIZE, (LPTHREAD_START_ROUTINE) GClanman_listen, parm_list, (unsigned long)NULL, &tid); if (hThread) { CloseHandle(hThread); return (OK); } status = errno; SETWIN32ERR(&parm_list->system_status, status, ER_create); goto err_exit; break; case GCC_CONNECT: GCTRACE(2) ("GClanman: Function = CONNECT\n" ); generror = GC_CONNECT_FAIL; break; case GCC_SEND: GCTRACE(2) ("GClanman: Function = SEND\n" ); generror = GC_SEND_FAIL; break; case GCC_RECEIVE: GCTRACE(2) ("GClanman: Function = RECEIVE\n" ); generror = GC_RECEIVE_FAIL; break; case GCC_DISCONNECT: GCTRACE(2) ("GClanman: Function = DISCONNECT\n" ); generror = GC_DISCONNECT_FAIL; break; default: return FAIL; } /* end switch */ /* ** CONNECT, SEND, RECEIVE and DISCONNECT are all dispatched ** to the asynch thread. ** Now allocate a request q structure, stick it into incoming q, ** and raise the INCOMING REQUEST event. */ GCTRACE(2)("GClanman: Q'ing request ...\n"); if ( (rq = (REQUEST_Q *)MEreqmem(0, sizeof(*rq), TRUE, NULL ) ) != NULL ) { rq->plist = parm_list; /* ** get mutex for completion Q */ GCTRACE(2)("GClanman: wait for input mutex ...\n"); WaitForSingleObject( hMutexThreadInQ, INFINITE ); /* ** Now insert the completed request into the inconming Q. */ GCTRACE(2)("GClanman: inserting incoming req ...\n"); QUinsert( &rq->req_q, &Tptr->incoming_head ); /* ** release mutex for completion Q */ GCTRACE(2)("GClanman: releasing Mutex incoming req ...\n"); ReleaseMutex( hMutexThreadInQ ); /* ** raise the incoming event to wake up the thread. */ GCTRACE(2)("GClanman: Setting event ...\n"); if ( !SetEvent( hEventThreadInQ ) ) { status = GetLastError(); SETWIN32ERR(&parm_list->system_status, status, ER_sevent); GCTRACE(1)("GClanman, SetEvent error = %d\n", status ); } return OK; } else { /* ** MEreqmem failed */ SETWIN32ERR(&parm_list->system_status, errno, ER_alloc); } /* * * Drive the completion routine on error */ err_exit: parm_list->generic_status = generror; (*parm_list->compl_exit) (parm_list->compl_id); return OK; }
SQLRETURN SQL_API SQLSetEnvAttr ( SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength) { RETCODE rc, traceRet = 1; pENV penv = (pENV)EnvironmentHandle; IISETENVATTR_PARAM *iiSetEnvAttrParam; i4 value = (i4)(SCALARP)ValuePtr; if (block_init) ODBC_TRACE_ENTRY(ODBC_TR_TRACE, IITraceSQLSetEnvAttr(EnvironmentHandle, Attribute, ValuePtr, StringLength), traceRet); /* ** Connection pooling is set in the CLI before any drivers are loaded. */ if (!EnvironmentHandle) { if (Attribute != SQL_ATTR_CONNECTION_POOLING) { rc = SQL_INVALID_HANDLE; goto exit_routine; } if (!block_init) { /* ** Initialize the CLI control block if connection pooling is ** specified. */ if (value == SQL_CP_ONE_PER_DRIVER || value == SQL_CP_ONE_PER_HENV) { IIodbc_initControlBlock(); if (IIodbc_cb.timeout != -1) IIodbc_createPoolThread(); block_init = TRUE; } } if (value == SQL_CP_ONE_PER_DRIVER) { ODBC_EXEC_TRACE(ODBC_TR_TRACE) ("SQLSetEnvAttr: driver pool initialized\n"); IIodbc_cb.pooling = DRIVER_POOL; QUinit(&IIodbc_cb.pool_q); } else if (value == SQL_CP_ONE_PER_HENV) { IIodbc_cb.pooling = HENV_POOL; } else if (value != SQL_CP_OFF) { /* ** If the pooling arguments are invalid, only SQL_INVALID_HANDLE ** can be returned because no environment handle exists. */ rc = SQL_INVALID_HANDLE; goto exit_routine; } /* if (!initPool) */ rc = SQL_SUCCESS; goto exit_routine; } /* if (!EnvironmentHandle) */ if (Attribute == SQL_ATTR_CP_MATCH && value == SQL_CP_RELAXED_MATCH) penv->relaxed_match = TRUE; else penv->relaxed_match = FALSE; /* ** If the driver isn't loaded yet, set a placeholder to do this ** later. */ if ( !IISetEnvAttr ) { if (Attribute == SQL_ATTR_ODBC_VERSION) penv->envAttrValue = ValuePtr; iiSetEnvAttrParam = (IISETENVATTR_PARAM *)MEreqmem(0, sizeof(IISETENVATTR_PARAM), TRUE, NULL); penv->setEnvAttr_count++; iiSetEnvAttrParam->Attribute = Attribute; iiSetEnvAttrParam->EnvironmentHandle = EnvironmentHandle; iiSetEnvAttrParam->ValuePtr = ValuePtr; iiSetEnvAttrParam->StringLength = StringLength; QUinsert((QUEUE *)iiSetEnvAttrParam, &penv->setEnvAttr_q); rc = SQL_SUCCESS; goto exit_routine; } if (penv->hdr.state < E2) { resetErrorBuff(penv, SQL_HANDLE_ENV); rc = IISetEnvAttr ( penv->hdr.driverHandle, Attribute, ValuePtr, StringLength); } else rc = SQL_ERROR; applyLock(SQL_HANDLE_ENV, penv); if (rc != SQL_SUCCESS) { penv->hdr.driverError = TRUE; penv->errHdr.rc = rc; } releaseLock(SQL_HANDLE_ENV, penv); exit_routine: ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, rc)); return rc; }
RETCODE SQL_API SQLSetConnectAttr( SQLHDBC hdbc, SQLINTEGER fOption, SQLPOINTER pValue, SQLINTEGER StringLength) { RETCODE rc, traceRet = 1; pDBC pdbc = (pDBC)hdbc; IISETCONNECTATTR_PARAM *iiSetConnectAttrParam; ODBC_TRACE_ENTRY(ODBC_TR_TRACE, IITraceSQLSetConnectAttr(hdbc, fOption, pValue, StringLength), traceRet); if (!hdbc) { ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, SQL_INVALID_HANDLE)); return SQL_INVALID_HANDLE; } /* ** If the driver isn't loaded yet, set a placeholder to do this ** later. */ if (!IISetConnectAttr) { iiSetConnectAttrParam = (IISETCONNECTATTR_PARAM *)MEreqmem(0, sizeof(IISETCONNECTATTR_PARAM), TRUE, NULL); QUinsert((QUEUE *)iiSetConnectAttrParam, &pdbc->setConnectAttr_q); iiSetConnectAttrParam->ConnectionHandle = hdbc; iiSetConnectAttrParam->Attribute = fOption; iiSetConnectAttrParam->Value = pValue; iiSetConnectAttrParam->StringLength = StringLength; pdbc->setConnectAttr_count++; ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, SQL_SUCCESS)); return SQL_SUCCESS; } else { resetErrorBuff( pdbc, SQL_HANDLE_DBC ); rc = IISetConnectAttr( pdbc->hdr.driverHandle, fOption, pValue, StringLength); applyLock(SQL_HANDLE_DBC, pdbc); if (rc != SQL_SUCCESS) { pdbc->errHdr.rc = rc; pdbc->hdr.driverError = TRUE; } else if (fOption == SQL_ATTR_AUTOCOMMIT && StringLength == SQL_IS_INTEGER) { if (((ULONG)pValue) == SQL_AUTOCOMMIT_OFF) pdbc->autocommit = FALSE; else if (((ULONG)pValue) == SQL_AUTOCOMMIT_ON) pdbc->autocommit = TRUE; } releaseLock(SQL_HANDLE_DBC, pdbc); } ODBC_TRACE(ODBC_TR_TRACE, IITraceReturn(traceRet, rc)); return rc; }
main(int argc, char **argv) { STATUS status = OK; VMS_STATUS vStatus; char srcbuf[NAME_FILE_SIZE]; char dstbuf[NAME_FILE_SIZE]; char delFile[NAME_FILE_SIZE]; struct dsc$descriptor_s filename_d = { sizeof (delFile) - 1, DSC$K_DTYPE_T, DSC$K_CLASS_S, delFile }; FILE *srcFile = NULL; FILE *dstFile = NULL; FILE *nameFile = NULL; LOCATION loc; bool clusterArg = FALSE; bool unclusterArg = FALSE; bool writeOutput = FALSE; bool validSyntax; bool clustered = FALSE; bool v1DecryptErr = FALSE; bool rewrite = FALSE; bool isLogin = FALSE; i4 total_recs = 0; char local_host[MAX_LOC+CM_MAXATTRNAME]; char config_host[MAX_LOC+CM_MAXATTRNAME]; i2 i,j; i4 active_rec; i4 offset; char *onOff = NULL; bool srcOpened=FALSE; bool dstOpened=FALSE; bool printable = TRUE; GCN_QUEUE *gcn_q; GCN_QUEUE *merge_q; i4 rec_len = 0; QUEUE *q; u_i1 local_mask[ 8 ]; /* Must be 8 bytes */ char name[MAX_LOC+CM_MAXATTRNAME]; i4 count; char *p = NULL; i4 dcryptFail = 0; i2 pc; char *pv[ 3 ]; GCN_DB_REC0 tmp_rec; SYSTIME timestamp; MEadvise(ME_INGRES_ALLOC); SIeqinit(); GChostname( local_host, sizeof(local_host)); STcopy (PMhost(), config_host); if (argc == 1) validSyntax = TRUE; /* ** Parse input arguments. */ for (i = 1; i < argc; i++) { validSyntax = FALSE; for (j = 0; j < argLen; j++) { if (!STncasecmp(arg[j],argv[i], STlength(argv[i]))) { switch(j) { case HELP1: case HELP2: case HELP3: case HELP4: usage(); break; case VERBOSE: validSyntax = TRUE; verboseArg = TRUE; break; case CLUSTER: validSyntax = TRUE; clusterArg = TRUE; writeOutput = TRUE; break; case UNCLUSTER: validSyntax = TRUE; unclusterArg = TRUE; writeOutput = TRUE; break; } } /* if (!STncasecmp(arg[j],argv[i], STlength(argv[i]))) */ if (validSyntax) break; } /* for (j = 0; j < argLen; j++) */ if (!validSyntax) break; } /* for (i = 1; i < argc; i++) */ if (!validSyntax) { usage(); PCexit(1); } if (clusterArg && unclusterArg) { SIprintf("Cannot specify both -c and -u\n\n"); usage(); PCexit(1); } if (verboseArg) SIprintf("Local host is %s\n", local_host); /* ** Generate key seeds for encoding and decoding. */ STpolycat( 2, GCN_LOGIN_PREFIX, local_host, name ); gcn_init_mask( name, sizeof( local_mask ), local_mask ); QUinit(&gcn_qhead); QUinit(&merge_qhead); PMinit(); /* ** See if this is a clustered installation. If it is, ** the node, login, and attribute files have no file extension. */ if ( PMload( (LOCATION *)NULL, (PM_ERR_FUNC *)NULL ) != OK ) { SIprintf("Error reading config.dat, exiting\n"); goto cvt_exit; } PMsetDefault( 0, SystemCfgPrefix ); PMsetDefault( 1, config_host ); PMsetDefault( 2, ERx("gcn") ); status = PMget( ERx("!.cluster_mode"), &onOff); if (onOff && *onOff) ; else onOff = "OFF"; if (verboseArg) SIprintf("Cluster mode is %s\n", onOff); if (!clusterArg && !unclusterArg) clustered = !STncasecmp(onOff, "ON", STlength(onOff)); /* ** Rewrite the named GCN files. For clustered installations, the ** node, login and attribute files have no hostname extension. */ for ( i = 0; i < NBR_NAMED_FILES; i++ ) { /* ** Ticket files are simply deleted. */ if (i == IILTICKET || i == IIRTICKET) { STprintf(delFile, "II_SYSTEM:[INGRES.FILES.NAME]II%s*;*", named_file[i].file); if (verboseArg) SIprintf("Deleting %s\n", delFile); filename_d.dsc$w_length = STlength(delFile); vStatus = lib$delete_file(&filename_d,0,0,0,0,0,0,0,0,0); if (!vStatus & STS$M_SUCCESS) SIprintf("delete of %s failed, status is 0x%d\n", delFile, vStatus); continue; } rewrite = FALSE; if (!clusterArg && !unclusterArg) writeOutput = FALSE; if ( ( status = NMloc( FILES, PATH & FILENAME, (char *)NULL, &loc ) ) != OK ) { SIprintf("iicvtgcn: Could not find II_SYSTEM:[ingres.files]\n"); goto cvt_exit; } LOfaddpath( &loc, "name", &loc ); if (clustered || unclusterArg) { if (named_file[i].add_cluster_node) STprintf( srcbuf, "II%s_%s", named_file[i].file,config_host); else STprintf(srcbuf, "II%s", named_file[i].file); } else STprintf( srcbuf, "II%s_%s", named_file[i].file,config_host); if (verboseArg) SIprintf("Opening %s for input\n", srcbuf); LOfstfile( srcbuf, &loc ); /* ** Ignore non-existent files. */ if ( LOexist( &loc ) != OK ) { if (verboseArg) SIprintf("%s does not exist\n", srcbuf); continue; } /* ** Open the existing file as "regular" RACC. */ status = SIfopen( &loc, "r", (i4)SI_RACC, sizeof( GCN_DB_REC0 ), &srcFile ); /* ** If the file exists but can't be opened, it's already optimized. */ if (status == E_CL1904_SI_CANT_OPEN && ( LOexist( &loc ) == OK ) ) { /* ** Open the existing file as "optimized" RACC. */ status = SIfopen( &loc, "r", (i4)GCN_RACC_FILE, sizeof( GCN_DB_REC0 ), &srcFile ); if (status != OK) { SIprintf( "iicvtgcn: Error opening %s, status is %x\n", srcbuf, status ); continue; } if (verboseArg) SIprintf("%s is already optimized\n", srcbuf); } else if (status != OK) { SIprintf( "iicvtgcn: Error opening %s, status is %x\n", srcbuf, status ); continue; } /* ** A successful open as SI_RACC means the file is not optimized. ** This file needs a rewrite. */ else { if (verboseArg) SIprintf("Rewriting %s as optimized\n", srcbuf); writeOutput = TRUE; } srcOpened = TRUE; while ( status == OK ) { /* ** Read the source data and store in a queue for analysis. */ status = SIread( srcFile, sizeof( GCN_DB_REC0 ), &count, (PTR)&tmp_rec ); if ( status == ENDFILE ) break; if ( status != OK ) { SIprintf("iicvtgcn: Error reading %s, status is %x\n", srcbuf, status); goto cvt_exit; } else if (tmp_rec.gcn_invalid && tmp_rec.gcn_tup_id != -1) continue; else { gcn_q = (GCN_QUEUE *)MEreqmem(0, sizeof(GCN_QUEUE),0,NULL); if (!gcn_q) { SIprintf("iicvtgcn: Cannot allocate memory, exiting\n"); goto cvt_exit; } MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), (PTR)&gcn_q->buf); QUinsert(&gcn_q->q, &gcn_qhead); /* ** EOF record found. */ if (gcn_q->buf.gcn_tup_id == -1) { gcn_q->buf.gcn_l_uid = 0; gcn_q->buf.gcn_uid[0] = '\0'; gcn_q->buf.gcn_l_obj = 0; gcn_q->buf.gcn_obj[0] = '\0'; gcn_q->buf.gcn_l_val = 0; gcn_q->buf.gcn_val[0] = '\0'; gcn_q->buf.gcn_invalid = TRUE; break; } } } /* while ( status == OK ) */ /* ** Decrypt passwords for IILOGIN files. If any V1 records are found, ** the IILOGIN file will need to be rewritten. */ isLogin = FALSE; for (q = gcn_qhead.q_prev; q != &gcn_qhead; q = q->q_prev) { gcn_q = (GCN_QUEUE *)q; /* ** EOF record found. */ if (gcn_q->buf.gcn_tup_id == -1) { gcn_q->buf.gcn_invalid = TRUE; break; } if (i == IILOGIN) { isLogin = TRUE; MEcopy((PTR)&gcn_q->buf, sizeof(GCN_DB_REC0), (PTR)&tmp_rec); if (verboseArg) SIprintf("\tEncoding vnode %s\n", gcn_q->buf.gcn_obj); if (unclusterArg) status = gcn_recrypt( FALSE, local_mask, gcn_q->buf.gcn_val, &v1DecryptErr, &writeOutput); else if (clusterArg) status = gcn_recrypt( TRUE, local_mask, gcn_q->buf.gcn_val, &v1DecryptErr, &writeOutput); else status = gcn_recrypt( clustered, local_mask, gcn_q->buf.gcn_val, &v1DecryptErr, &writeOutput); if (status != OK) { if (verboseArg) SIprintf("Cannot decrypt password from " \ "vnode %s status %x\n", gcn_q->buf.gcn_obj, status); dcryptFail++; MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), (PTR)&gcn_q->buf); continue; } if (v1DecryptErr) { if (verboseArg) SIprintf("Cannot decrypt password from " \ "vnode %s\n", gcn_q->buf.gcn_obj); dcryptFail++; MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), (PTR)&gcn_q->buf); continue; } } /* if (LOGIN) */ } /* for (q = gcn_qhead.q_prev; q != &gcn_qhead; q = q->q_prev) */ if (dcryptFail && verboseArg && isLogin) { if (clustered || unclusterArg ) SIprintf("\n%d vnode(s) could not be decrypted.\n" \ "Probably some login entries were created on " \ "another node.\nTry executing iicvtgcn on another " \ "node to merge the other node's entries.\n\n", dcryptFail); else SIprintf("\n%d vnode(s) could not be decrypted.\n" \ "Probably the login file was created on " \ "another host.\nTry executing iicvtgcn on " \ "a different host.\n\n", dcryptFail); } if (!writeOutput) { if (srcOpened) SIclose(srcFile); srcOpened = FALSE; cleanup_queues(); continue; } /* ** Open the destination file with special GCN_RACC_FILE flag, for ** optimized writes. */ if (clustered || clusterArg) { if (named_file[i].add_cluster_node) STprintf( dstbuf, "II%s_%s", named_file[i].file, local_host); else STprintf(dstbuf, "II%s", named_file[i].file); } else STprintf( dstbuf, "II%s_%s", named_file[i].file, local_host); if (clusterArg && !named_file[i].add_cluster_node) rewrite = TRUE; LOfstfile( dstbuf, &loc ); if (rewrite) { status = SIfopen( &loc, "rw", (i4)GCN_RACC_FILE, sizeof( GCN_DB_REC0 ), &dstFile ); if ( status != OK ) { status = SIfopen( &loc, "w", (i4)GCN_RACC_FILE, sizeof( GCN_DB_REC0 ), &dstFile ); if (status == OK) { SIclose( dstFile); status = SIfopen( &loc, "rw", (i4)GCN_RACC_FILE, sizeof( GCN_DB_REC0 ), &dstFile ); } } } else status = SIfopen( &loc, "w", (i4)GCN_RACC_FILE, sizeof( GCN_DB_REC0 ), &dstFile ); if ( status != OK ) { SIprintf( "iicvtgcn: Error opening %s, status is %x\n",dstbuf, status ); goto cvt_exit; } dstOpened = TRUE; if (verboseArg) SIprintf("%s %s\n", rewrite ? "Rewriting " : "Writing ", dstbuf); /* ** If this is a merge operation (-c), login, attribute or ** node files may change the location of EOF, since the ** file to be merged may have different records than ** the destination file. ** Before merging, the output file is read and fed into a queue. ** Then each merge record is compared to each output record. ** If the entire records match, nothing is done. ** If a global login record matches only the vnode name ** global or private records will be added if not present; ** otherwise, nothing is done. ** Node or attribute records may be added if only one field ** fails to match. */ status = SIfseek(dstFile, (i4)0, SI_P_START); if (rewrite) { while ( status == OK ) { /* ** Read the source data and store in a queue for analysis. */ status = SIread( dstFile, sizeof( GCN_DB_REC0 ), &count, (PTR)&tmp_rec ); if ( status == ENDFILE ) break; if ( status != OK ) { SIprintf("iicvtgcn: Error reading %s, status is %x\n", dstbuf, status); goto cvt_exit; } else if (tmp_rec.gcn_invalid && tmp_rec.gcn_tup_id != -1) continue; else { merge_q = (GCN_QUEUE *)MEreqmem(0, sizeof(GCN_QUEUE),0,NULL); if (!merge_q) { SIprintf("iicvtgcn: Cannot allocate memory, exiting\n"); goto cvt_exit; } MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), (PTR)&merge_q->buf); QUinsert(&merge_q->q, &merge_qhead); /* ** EOF record found. */ if (merge_q->buf.gcn_tup_id == -1) break; } if ( status == ENDFILE ) break; } /* while ( status == OK ) */ /* ** Go through the input queue. Compare each record with ** the output (merge) queue. If the record is invalid ** or doesn't match, it's ignored. */ dcryptFail = 0; total_recs = 0; for (q = gcn_qhead.q_prev; q != &gcn_qhead; q = q->q_prev) { SYSTIME timestamp; gcn_q = (GCN_QUEUE *)q; if (gcn_q->buf.gcn_tup_id == -1) break; if ( !gcn_merge_rec( gcn_q, isLogin ) ) continue; if (isLogin) { /* ** Login passwords get encrypted as V0 in a cluster ** environment. */ MEcopy((PTR)&gcn_q->buf, sizeof(GCN_DB_REC0), (PTR)&tmp_rec); status = gcn_recrypt( TRUE, local_mask, gcn_q->buf.gcn_val, &v1DecryptErr, &writeOutput); if (status != OK) { if (verboseArg) SIprintf("Cannot decrypt password from " \ "vnode %s status %x\n", gcn_q->buf.gcn_obj, status); dcryptFail++; MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), (PTR)&gcn_q->buf); continue; } if (v1DecryptErr) { if (verboseArg) SIprintf("Cannot decrypt password from " \ "vnode %s\n", gcn_q->buf.gcn_obj); dcryptFail++; MEcopy((PTR)&tmp_rec, sizeof(GCN_DB_REC0), (PTR)&gcn_q->buf); continue; } } merge_q = (GCN_QUEUE *)MEreqmem(0, sizeof(GCN_QUEUE),0,NULL); if (!merge_q) { SIprintf("iicvtgcn: Cannot allocate memory, exiting\n"); goto cvt_exit; } MEcopy((PTR)&gcn_q->buf, sizeof(GCN_DB_REC0), (PTR)&merge_q->buf); total_recs++; QUinsert(&merge_q->q, &merge_qhead); } if (dcryptFail && verboseArg && isLogin) { if (clustered || unclusterArg ) SIprintf("\n%d vnode(s) could not be decrypted.\n" \ "Probably some login entries were created on " \ "another node.\nTry executing iicvtgcn on another " \ "node to merge the other node's entries.\n\n", dcryptFail); else SIprintf("\n%d vnode(s) could not be decrypted.\n" \ "Probably the login file was created on " \ "another host.\nTry executing iicvtgcn on " \ "a different host.\n\n", dcryptFail); } if (verboseArg) SIprintf("Total records merged: %d\n", total_recs); /* ** If no records to merge, clean up and continue. */ if (!total_recs) { cleanup_queues(); continue; } status = SIfseek(dstFile, (i4)0, SI_P_START); active_rec = 0; for (q = merge_qhead.q_prev; q != &merge_qhead; q = q->q_prev) { merge_q = (GCN_QUEUE *)q; if (verboseArg) SIprintf("Rewriting %s record vnode %s val %s\n", !STcasecmp("*", merge_q->buf.gcn_uid) ? "global" : "private", merge_q->buf.gcn_obj, merge_q->buf.gcn_val); if (merge_q->buf.gcn_tup_id == -1) continue; status = SIwrite(sizeof( GCN_DB_REC0 ), (char *)&merge_q->buf, &count, dstFile ); if ( status != OK) { SIprintf( "iicvtgcn: Failed to write file %s, " \ "status is %x\n", srcbuf, status ); goto cvt_exit; } active_rec++; } /* ** Write new EOF record. */ tmp_rec.gcn_tup_id = -1; tmp_rec.gcn_l_uid = 0; tmp_rec.gcn_uid[0] = '\0'; tmp_rec.gcn_l_obj = 0; tmp_rec.gcn_obj[0] = '\0'; tmp_rec.gcn_l_val = 0; tmp_rec.gcn_val[0] = '\0'; tmp_rec.gcn_invalid = TRUE; offset = active_rec * sizeof(GCN_DB_REC0); status = SIfseek(dstFile, (i4)offset, SI_P_START); status = SIwrite(sizeof( GCN_DB_REC0 ), (PTR)&tmp_rec, &count, dstFile ); } else { for (q = gcn_qhead.q_prev; q != &gcn_qhead; q = q->q_prev) { gcn_q = (GCN_QUEUE *)q; gcn_q->buf.gcn_l_val = STlength(gcn_q->buf.gcn_val); if (verboseArg) SIprintf("Writing %s record vnode %s val %s\n", !STcasecmp("*", gcn_q->buf.gcn_uid) ? "global" : "private", gcn_q->buf.gcn_obj, gcn_q->buf.gcn_val); status = SIwrite(sizeof( GCN_DB_REC0 ), (char *)&gcn_q->buf, &count, dstFile ); if ( status != OK) { SIprintf( "iicvtgcn: Failed to write file %s, " \ "status is %x\n", srcbuf, status ); goto cvt_exit; } } } /* if (rewrite) */ cleanup_queues(); SIclose( srcFile ); srcOpened = FALSE; SIclose( dstFile ); dstOpened = FALSE; } /* for (i = 0; i < NBR_NAMED_FILES; i++ ) */ cvt_exit: cleanup_queues(); if (srcOpened) SIclose(srcFile); if (dstOpened) SIclose(dstFile); PCexit( OK ); }