/* decode semaphore error */ void semerr( i4 rv, CS_SEMAPHORE *sp, char *msg) { MY_SCB *scb; #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ SIfprintf( stderr,"Error: unexpected exception in semerr()..."); EXdelete(); return; } #endif CSget_scb( (CS_SCB **)&scb ); SIfprintf(stderr, "%s %p returned %d (%s)\n", msg, sp, rv, maperr(rv) ); SIfprintf(stderr, "\tPhilosopher %d, scb %p\n", scb->phil, scb ); SIfprintf(stderr, "\t%p->cs_value %d\n", sp, sp->cs_value ); SIfprintf(stderr, "\t%p->cs_count %d\n", sp, sp->cs_count ); SIfprintf(stderr, "\t%p->cs_owner %x\n", sp, sp->cs_owner ); SIfprintf(stderr, "\t%p->cs_list %p\n", sp, sp->cs_list ); SIfprintf(stderr, "\t%p->cs_next %p\n", sp, sp->cs_next ); #ifdef EX_DEBUG EXdelete(); #endif }
void logger( i4 errnum, i4 arg1, i4 arg2) { char buf[ ER_MAX_LEN ]; #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ Psem( &SIsem ); SIfprintf( stderr,"Error: unexpected exception in logger()..."); Vsem( &SIsem ); EXdelete(); return; } #endif Psem( &SIsem ); if( ERreport( errnum, buf ) == OK ) SIfprintf(stderr, "%s\n", buf); else SIfprintf(stderr, "ERROR %d (%x), %s %d\n", errnum, errnum, arg1, arg2 ); Vsem( &SIsem ); #ifdef EX_DEBUG EXdelete(); #endif if(errnum != E_CS0018_NORMAL_SHUTDOWN) PCexit(FAIL); PCexit(OK); }
/* Observe that philosopher n is eating */ void eats( i4 n) { #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ Psem( &SIsem ); SIfprintf( stderr,"Error: unexpected exception in eats()..."); Vsem( &SIsem ); EXdelete(); return; } #endif if( Noisy ) { Psem( &SIsem ); SIfprintf(stderr, "%d (%s) eats...\n", n, Names[ n ] ); Vsem( &SIsem ); } CSswitch(); #ifdef EX_DEBUG EXdelete(); #endif }
/* ** Name: ascs_avformat - Show info on the current thread during an AV ** ** Description: ** This routine calls scs_iformat to show what thread was running ** when the server got an AV. ** ** Inputs: ** None. ** ** Outputs: ** Returns: ** STATUS ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 27-feb-1992 (rog) ** Created. ** 29-Jun-1993 (daveb) ** correctly cast arg to CSget_scb(). ** 02-Jul-1993 (daveb) ** prototyped. ** 07-jul-1993 (rog) ** Changed the message from saying a fatal error occurred to just ** saying that an error occurred. [@history_template@]... */ STATUS ascs_avformat(void) { STATUS ret_val; EX_CONTEXT ex; if (EXdeclare(ascs_fhandler, &ex) != OK) { ret_val = FAIL; } else { SCD_SCB *scb; i4 err_code; char *msg_buffer; i4 msg_length; msg_buffer = "An error occurred in the following session:"; msg_length = STlength(msg_buffer); CSget_scb((CS_SCB **)&scb); ule_format(0, 0, ULE_MESSAGE, 0, msg_buffer, msg_length,0,&err_code,0); ret_val = ascs_iformat(scb, 1, 0, 1); } EXdelete(); return(ret_val); }
char * maperr( STATUS rv) { char *ret_val; #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ SIfprintf( stderr,"Error: unexpected exception in maperr()..."); EXdelete(); return ""; } #endif switch( rv ) { case E_CS0017_SMPR_DEADLOCK: ret_val = "E_CS0017_SMPR_DEADLOCK"; break; case E_CS000F_REQUEST_ABORTED: ret_val = "E_CS000F_REQUEST_ABORTED"; break; case E_CS000A_NO_SEMAPHORE: ret_val = "E_CS000A_NO_SEMAPHORE"; break; case OK: ret_val = ""; break; default: ret_val = "Unknown exception"; break; } #ifdef EX_DEBUG EXdelete(); #endif return ret_val; }
/* ** Setup global variables and add threads for each philosopher. ** Called by CSinitialize before threads are started */ STATUS hello( CS_INFO_CB *csib) { i4 i; STATUS stat; CL_ERR_DESC err; #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ SIfprintf( stderr,"Error: unexpected exception in hello()..."); EXdelete(); return FAIL; } #endif SIsem.cs_value = 0; SIsem.cs_count = 0; SIsem.cs_owner = NULL; SIsem.cs_list = NULL; SIsem.cs_next = NULL; Freesem.cs_value = 0; Freesem.cs_count = 0; Freesem.cs_owner = NULL; Freesem.cs_list = NULL; Freesem.cs_next = NULL; for( i = 0, stat = OK; i < n_phils && stat == OK; i++ ) { Freesticks[ i ] = 2; stat = CSadd_thread( 0, (PTR)NULL, i + 1, (CS_SID*)NULL, &err ); } /* no semaphore needed, called before CSdispatch */ if( Noisy ) SIfprintf(stderr, "World begins, philosophers wonder why.\n" ); #ifdef EX_DEBUG EXdelete(); #endif return( stat ); }
/* Called when all thread functions return from the TERMINATE state */ STATUS bye() { #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ SIfprintf( stderr,"Error: unexpected exception in bye()..."); EXdelete(); return FAIL; } #endif /* no semaphore needed, called when all threads are dead */ if( Noisy ) SIfprintf(stderr, "All philosophers are dead. World ends.\n"); #ifdef EX_DEBUG EXdelete(); #endif return( OK ); }
/* Observe that philosopher n is thinking */ void thinks( i4 n) { #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ Psem( &SIsem ); SIfprintf( stderr,"exception raised while thinking, OK...\n"); Vsem( &SIsem ); EXdelete(); return; } #endif if( Noisy ) { Psem( &SIsem ); SIfprintf(stderr, "%d (%s) thinks...\n", n, Names[ n ] ); Vsem( &SIsem ); } CSswitch(); #ifdef EX_DEBUG EXsignal(not_handled, 0); Psem( &SIsem ); SIfprintf( stderr,"Error: should not be reached in thinks()..."); Vsem( &SIsem ); EXdelete(); #endif }
/* release a semaphore */ STATUS Vsem( CS_SEMAPHORE *sp) { STATUS rv; #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ SIfprintf( stderr,"Error: unexpected exception in Vsem()..."); EXdelete(); return FAIL; } #endif if( rv = CSv_semaphore( sp ) ) semerr( rv, sp, "Vsem" ); #ifdef EX_DEBUG EXdelete(); #endif return( rv ); }
/* release sticks held by philosopher n */ void freesticks( i4 n) { #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler2, &context) != OK) { /* free_exc error should never be EX_DECLARE'd. */ Psem( &SIsem ); SIfprintf( stderr,"Error: unexpected exception in freesticks()..."); Vsem( &SIsem ); EXdelete(); return; } #endif Psem( &Freesem ); #ifdef EX_DEBUG EXsignal(free_exc, 1, n); #endif Freesticks[ n ] += 2; ++Freesticks[ LEFT( n ) ]; ++Freesticks[ RIGHT( n ) ]; CSswitch(); /* gratuitous, tests semaphores */ Vsem( &Freesem ); #ifdef EX_DEBUG EXdelete(); #endif }
STATUS ERslookup( i4 msg_number, CL_ERR_DESC *clerror, i4 flags, char *sqlstate, char *msg_buf, i4 msg_buf_size, i4 language, i4 *msg_length, CL_ERR_DESC *err_code, i4 num_param, ER_ARGUMENT *param ) { i4 erindex; /* index of ERmulti table */ i4 status; i4 length = 0; ER_ARGUMENT *p; ER_ARGUMENT hidden[CLE_INFO_ITEMS]; /* to access info in clerror */ char tempbuf[ER_MAX_LEN+ER_MAX_NAME+2]; i4 templen; char *p_msg_buf; char *p_tempbuf; SYSTIME stime; char langbuf[ER_MAX_LANGSTR]; EX_CONTEXT context; ER_SEMFUNCS *sems; #define D_WIDTH 23 #define F_WIDTH 20 #define X_WIDTH 18 /* Validate the parameters. */ if (msg_buf == 0 || msg_buf_size == 0 || msg_length == 0) { return (ER_BADPARAM); } if (language != -1 && ERlangstr(language,langbuf) != OK) { return (ER_BADLANGUAGE); } if (!(flags & ER_NAMEONLY)) { EXdump(msg_number,0); } /* Insert timestamp if requested. */ if (flags & ER_TIMESTAMP) { if (msg_buf_size < 21) { return (ER_TOOSMALL); } TMnow(&stime); TMstr(&stime,msg_buf); length = (i4)STlength(msg_buf); msg_buf[length++] = ' '; } /* ** if (clerror && msg_number) ** look up msg_number, optional parameters in clerror->moreinfo ** else if (clerror) ** { ** if (clerror->intern) ** look up clerror.intern, optional params in clerror->moreinfo ** if (clerror->callid) ** look up system error message ** } */ if (clerror) { if (msg_number) /* Look up message after system error */ { /* ** Set up an ER_ARGUMENT that references system-dependent ** information in `clerror', and point `param' at it. */ i4 i; for (i = 0; i < CLE_INFO_ITEMS; ++i) { /* "...all of whose members begin at offset 0..." (K&R) */ hidden[i].er_value = (PTR)&clerror->moreinfo[i].data._i4; hidden[i].er_size = clerror->moreinfo[i].size; } param = &hidden[0]; num_param = CLE_INFO_ITEMS; } else /* retrieve system-dependent error messages */ { i4 len; ER_ARGUMENT argv[3]; if (clerror->intern) /* look up internal CL error */ { i4 i; for (i = 0; i < CLE_INFO_ITEMS; ++i) { argv[i].er_value = (PTR)&clerror->moreinfo[i].data._i4; argv[i].er_size = clerror->moreinfo[i].size; } /* ** Don't timestamp on recursive call, since it's been done ** already (if requested). */ if ((status = ERslookup((i4) clerror->intern, (CL_ERR_DESC*) NULL, flags & ~ER_TIMESTAMP | ER_TEXTONLY, NULL, &msg_buf[length], msg_buf_size-length, language, &len, err_code, CLE_INFO_ITEMS, argv)) != OK) { return (status); } length += len; if (clerror->callid) msg_buf[length++] = '\n'; } if (clerror->callid) /* look up system error message text */ { DESCRIPTOR msg_desc; msg_desc.desc_length = sizeof(tempbuf) - 1; msg_desc.desc_value = tempbuf; if ((status = cer_sysgetmsg(clerror, &len, &msg_desc, err_code)) != OK) { return(status); } argv[0].er_size = argv[1].er_size = argv[2].er_size = ER_PTR_ARGUMENT; argv[0].er_value = (PTR)&clerror->errnum; argv[1].er_value = (PTR)ERNAME((i4) clerror->callid); argv[2].er_value = (PTR)tempbuf; if ((status = ERslookup(ER_UNIXERROR, (CL_ERR_DESC*) NULL, flags & ~ER_TIMESTAMP | ER_TEXTONLY, NULL, &msg_buf[length], msg_buf_size - length, language, &len,err_code, 3, argv)) != OK) { return (status); } length += len; } msg_buf[*msg_length = length] = EOS; return (OK); } } /* ** Check if error message file is already opened or not yet. ** First see if the language is initialized. If not, initialize ** it and the message files. ** If it is already opened, cer_fndindex function returns the index of ** ERmulti table that internal language code is parameter 'language'. ** If not yet, it returns '-1'. */ if (cer_issem(&sems)) { if (((sems->sem_type & MU_SEM) ? (*sems->er_p_semaphore)(&sems->er_mu_sem) : (*sems->er_p_semaphore)(1, &sems->er_sem)) != OK) { sems = NULL; } } if ((erindex = cer_fndindex(language)) == -1) { if ((status = cer_nxtindex(language,&erindex)) != OK) { /* Error in initializing the language */ if (sems) { if (sems->sem_type & MU_SEM) _VOID_ (*sems->er_v_semaphore)(&sems->er_mu_sem); else _VOID_ (*sems->er_v_semaphore)(&sems->er_sem); } return (status); } } /* If the error message file is not opened, open the message file. */ if (!cer_isopen(erindex,ER_SLOWSIDE)) { if ((status = cer_sinit(language,msg_number,erindex,err_code)) != OK) { if (sems) { if (sems->sem_type & MU_SEM) _VOID_ (*sems->er_v_semaphore)(&sems->er_mu_sem); else _VOID_ (*sems->er_v_semaphore)(&sems->er_sem); } return (status); } } /* If not open then just return. */ if (!cer_isopen(erindex,ER_SLOWSIDE)) { if (sems) { if (sems->sem_type & MU_SEM) _VOID_ (*sems->er_v_semaphore)(&sems->er_mu_sem); else _VOID_ (*sems->er_v_semaphore)(&sems->er_sem); } /* ** As internal file id is '0', openning file will fail. ** In her,return status 'ER_BADOPEN' to show open fail. */ return (ER_BADOPEN); } /* ** Search message string from file and set to buffer. ** Error status on system call set to 'err_code'. */ status = cer_sstr(msg_number, sqlstate, tempbuf, msg_buf_size - length, erindex, err_code, flags & ER_TEXTONLY? ER_GET : ER_LOOKUP); if (sems) { if (sems->sem_type & MU_SEM) _VOID_ (*sems->er_v_semaphore)(&sems->er_mu_sem); else _VOID_ (*sems->er_v_semaphore)(&sems->er_sem); } if (status != OK) { return (status); } /* ** Format the text with parameters into the callers buffer. ** The message is truncated if it will not fit. */ /* Insert part of name from temporary buffer to buffer */ status = OK; templen = (i4)STlength(tempbuf); p_msg_buf = &msg_buf[length]; p_tempbuf = tempbuf; if (!(flags & ER_TEXTONLY)) { while(*p_tempbuf != '\t') { CMcpyinc(p_tempbuf,p_msg_buf); } CMcpyinc(p_tempbuf,p_msg_buf); } /* ============================================ */ /* Copy text to message substituting arguments. */ /* -------------------------------------------- */ /* (But first, declare an exception handler to */ /* catch bad params that may access violate.) */ /* ============================================ */ if (EXdeclare(er_exhandler, &context)) { u_i4 res_len; u_i4 bytes_left_in_buf; bytes_left_in_buf = (u_i4)(msg_buf_size - (p_msg_buf - msg_buf)); res_len = STlen( STncpy(p_msg_buf, ERx("*** ERslookup() ERROR: Missing or bad parameter for this message. ***"), bytes_left_in_buf )); p_msg_buf[ bytes_left_in_buf - 1 ] = EOS; p_msg_buf += res_len; *msg_length = (i4)(p_msg_buf - msg_buf); EXdelete(); return (OK); } for( ;p_tempbuf - tempbuf < templen; CMnext(p_tempbuf)) { long number; u_long unumber; double fnumber; i4 i; i4 pnum; if ( (*p_tempbuf != '%') || (flags & ER_NOPARAM) ) { if ((p_msg_buf - msg_buf) >= msg_buf_size) break; CMcpychar(p_tempbuf,p_msg_buf); CMnext(p_msg_buf); continue; } if (p_tempbuf - tempbuf + 2 >= templen) continue; CMnext(p_tempbuf); if (*p_tempbuf == '!') { if ((p_msg_buf - msg_buf) + 3 >= msg_buf_size) continue; CMcpychar(ERx("\r"),p_msg_buf); CMnext(p_msg_buf); CMcpychar(ERx("\n"),p_msg_buf); CMnext(p_msg_buf); CMcpychar(ERx("\t"),p_msg_buf); CMnext(p_msg_buf); continue; } /* ** Only works for up to 10 parameters, and makes character set ** assumptions - should be fixed. */ if ( *p_tempbuf < '0' || *p_tempbuf > '9' ) { /* treat any other character as a literal */ if ((p_msg_buf - msg_buf) >= msg_buf_size) break; if ( *p_tempbuf != '%' ) { CMcpychar("%",p_msg_buf); CMnext(p_msg_buf); } CMcpychar(p_tempbuf,p_msg_buf); CMnext(p_msg_buf); continue; } pnum = *p_tempbuf - '0'; if (pnum >= num_param) { EXdelete(); return(ER_BADPARAM); } p = ¶m[pnum]; CMnext(p_tempbuf); switch (*p_tempbuf) { case 'd': /* Convert an integer into the buffer with width D_WIDTH */ if (p->er_size == ER_PTR_ARGUMENT) /* this is ptr to i4 */ number = *(i4 *)p->er_value; else if (p->er_size == 0) /* this is a i4 */ number = (i4)(SCALARP)p->er_value; else if (p->er_size == 1) number = *(i1 *)p->er_value; else if (p->er_size == 2) number = *(i2 *)p->er_value; else if (p->er_size == 4) number = *(i4 *)p->er_value; else if (p->er_size == 8) number = *(i8 *)p->er_value; else continue; if (p_msg_buf - msg_buf + D_WIDTH >= msg_buf_size) continue; if (p->er_size == 8) { CVla8(number, p_msg_buf); } else { CVla((i4)number, p_msg_buf); } while (*p_msg_buf) CMnext(p_msg_buf); continue; case 'u': /* Convert an integer into the buffer with width D_WIDTH */ if (p->er_size == ER_PTR_ARGUMENT) /* this is ptr to u_i4 */ number = *(u_i4 *)p->er_value; else if (p->er_size == 0) /* this is a u_i4 */ number = (u_i4)(SCALARP)p->er_value; else if (p->er_size == 1) number = *(u_i1 *)p->er_value; else if (p->er_size == 2) number = *(u_i2 *)p->er_value; else if (p->er_size == 4) number = *(u_i4 *)p->er_value; else if (p->er_size == 8) number = *(u_i8 *)p->er_value; else continue; if (p_msg_buf - msg_buf + D_WIDTH >= msg_buf_size) continue; if (p->er_size == 8) { CVula8(number, p_msg_buf); } else { CVula((u_i4)number, p_msg_buf); } while (*p_msg_buf) CMnext(p_msg_buf); continue; case 'f': { i2 res_width; /* Convert a float into the buffer with width F_WIDTH */ if (p->er_size == ER_PTR_ARGUMENT) /* Pointer to a double */ fnumber = *(double *)p->er_value; else if (p->er_size == 4) fnumber = *(f4 *)p->er_value; else if (p->er_size == 8) fnumber = *(f8 *)p->er_value; else continue; if (p_msg_buf - msg_buf + F_WIDTH >= msg_buf_size) continue; /* Always convert to 'e' format. */ CVfa(fnumber, (i4) 20, (i4) 5, 'e', '.', p_msg_buf, &res_width); p_msg_buf += F_WIDTH; continue; } case 'c': /* Convert a character array into buffer. */ if (p->er_value == 0) p->er_value = (PTR)ERx("<missing>"); if ((p->er_size == 0) || (p->er_size == ER_PTR_ARGUMENT)) { for (i = 0; ((char *)p->er_value)[i]; i++) ; p->er_size = i; } if (p_msg_buf - msg_buf + p->er_size >= msg_buf_size) continue; if (p->er_size > msg_buf_size - (p_msg_buf - msg_buf)) p->er_size = (i4)(msg_buf_size - (p_msg_buf - msg_buf)); /* p->er_size=STtrmwhite(p_msg_buf);*/ MEcopy(p->er_value, p->er_size, p_msg_buf); p->er_size = (i4)STtrmnwhite(p_msg_buf, p->er_size); p_msg_buf += p->er_size; continue; case 'x': /* Convert an integer into the buffer with width D_WIDTH */ if (p->er_size == ER_PTR_ARGUMENT) unumber = *(u_i4 *)p->er_value; else if (p->er_size == 0) unumber = (u_i4)(SCALARP)p->er_value; else if (p->er_size == 1) unumber = *(u_i1 *)p->er_value; else if (p->er_size == 2) unumber = *(u_i2 *)p->er_value; else if (p->er_size == 4) unumber = *(u_i4 *)p->er_value; else if (p->er_size == 8) unumber = *(u_i8 *)p->er_value; if (p_msg_buf - msg_buf + X_WIDTH >= msg_buf_size) continue; for (i = 8; --i >= 0; ) { /* {@fix_me@} ** This is *NOT* machine independent. This relys on an ** ASCII-like character set, where the digits '0'-'9' are ** contiguous and sequential, and the characters 'A'-'F' ** are contiguous and sequential. Both ASCII and EBCDIC ** happen to be this way. */ if ((*(p_msg_buf + i) = (unumber & 0x0f) + '0') > '9') *(p_msg_buf + i) += 'A' - '9' - 1; unumber >>= 4; } p_msg_buf += 8; continue; default: continue; } } *msg_length = (i4)(p_msg_buf - msg_buf); *p_msg_buf = EOS; EXdelete(); return (OK); }
/* A philosopher thread function, called out of CSdispatch */ STATUS philosopher( i4 mode, MY_SCB *scb, i4 *next_mode) { i4 bites = 0; #ifdef EX_DEBUG EX_CONTEXT context; if (EXdeclare(ex_handler, &context) != OK) { /* some exception was raised */ Psem( &SIsem ); SIfprintf( stderr,"Error: unexpected exception in philosopher()..."); Vsem( &SIsem ); EXdelete(); return FAIL; } #endif switch( mode ) { case CS_INITIATE: /* A new philsopher is born */ scb->phil = Threads++; status[scb->phil] = mode; while( bites < NBITES ) { getsticks( scb->phil ); eats( scb->phil ); bites++; freesticks( scb->phil ); thinks( scb->phil ); } /* fall into: */ default: *next_mode = CS_TERMINATE; break; case CS_TERMINATE: if( Noisy ) { # ifdef EX_SIG_DEBUG signal(SIGUSR1, intfunc); if (scb->phil == 1) { SIfprintf(stderr, "Send a signal #%d to process #%d\n", SIGUSR1, getpid()); pause(); } # endif /* EX_SIG_DEBUG */ Psem( &SIsem ); SIfprintf(stderr, "%d (%s) dies, RIP.\n", scb->phil, Names[ scb->phil ] ); if ( status[scb->phil] == mode ) { SIfprintf(stderr, "Oops this philosopher is already dead?\n"); SIfprintf(stderr, "\t\t CS code is non-functional\n"); } Vsem( &SIsem ); } *next_mode = CS_TERMINATE; /* If no more threads, shutdown */ status[scb->phil] = mode; if( --Threads == 0 ) { /* Everyone else should be dead, no semaphore needed. */ SIflush( stderr ); CSterminate( CS_KILL, (i4 *)NULL ); } break; } #ifdef EX_DEBUG EXdelete(); #endif return( OK ); }
/*{ ** Name: sxf_call - The main SXF entry point. ** ** Description: ** The routine checks that the arguments to sxf_call look reasonable. ** The implementing function is then called and operation completion ** status is returned to the caller. ** ** Inputs: ** op_code The SXF operation code. ** rcb The SXF request control block for the operation. ** ** Outputs: ** Returns: ** DB_STATUS ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 9-July-1992 (markg) ** Initial creation. ** 03-sep-1992 (pholman) ** Give calls NULL functionlaity for initial integration ** 20-oct-1992 (markg) ** Updated to have entry points for all SXF operations. */ DB_STATUS sxf_call( SXF_OPERATION op_code, SXF_RCB *rcb) { DB_STATUS status = E_DB_OK; EX_CONTEXT context; i4 error; CLRDBERR(&rcb->sxf_error); /* Make a cursury check for bad parameters. */ if (op_code < SXF_MIN_OPCODE || op_code > SXF_MAX_OPCODE || rcb->sxf_cb_type != SXFRCB_CB || rcb->sxf_length != sizeof (SXF_RCB) || (Sxf_svcb == NULL && op_code != SXC_STARTUP)) { /* Figure out the error in more detail. */ if (op_code < SXF_MIN_OPCODE || op_code > SXF_MAX_OPCODE) SETDBERR(&rcb->sxf_error, 0, E_SX0001_BAD_OP_CODE); else if (rcb->sxf_cb_type != SXFRCB_CB) SETDBERR(&rcb->sxf_error, 0, E_SX0002_BAD_CB_TYPE); else if (rcb->sxf_length != sizeof (SXF_RCB)) { TRdisplay("Bad SXF CB length. Input length %d expected %d\n", rcb->sxf_length, sizeof(SXF_RCB)); SETDBERR(&rcb->sxf_error, 0, E_SX0003_BAD_CB_LENGTH); } else SETDBERR(&rcb->sxf_error, 0, E_SX000F_SXF_NOT_ACTIVE); return (E_DB_ERROR); } if (EXdeclare(ex_handler, &context) == OK && (Sxf_svcb == NULL || (Sxf_svcb->sxf_svcb_status & SXF_CHECK) == 0)) { switch (op_code) { /* Control operations. */ case SXC_STARTUP: status = sxc_startup(rcb); break; case SXC_SHUTDOWN: status = sxc_shutdown(rcb); break; case SXC_BGN_SESSION: status = sxc_bgn_session(rcb); break; case SXC_END_SESSION: status = sxc_end_session(rcb); break; case SXC_ALTER_SESSION: status = sxc_alter_session(rcb); break; case SXC_AUDIT_THREAD: status = sxac_audit_thread(rcb); break; case SXC_AUDIT_WRITER_THREAD: status = sxac_audit_writer_thread(rcb); break; /* Audit file oerations */ case SXA_OPEN: status = sxaf_open(rcb); break; case SXA_CLOSE: status = sxaf_close(rcb); break; /* Audit record operations */ case SXR_WRITE: status = sxar_write(rcb); break; case SXR_POSITION: status = sxar_position(rcb); break; case SXR_READ: status = sxar_read(rcb); break; case SXR_FLUSH: status = sxar_flush(rcb); break; /* Audit state operations */ case SXS_ALTER: status = sxas_alter(rcb); break; case SXS_SHOW: status = sxas_show(rcb); break; } EXdelete(); return (status); } /* ** If exception handler declares or the SXF_SVCB has already been ** marked inconsistent, this is a server fatal condition. In most ** cases it is sufficient to return a server fatal error, and let the ** caller handle the rest. ** ** However, if this is an audit record write operation we have to ** nuke the server ourselves. The reason for this is that if the ** client code does not handle the return status correctly the ** security of the system could be compromised. */ EXdelete(); if (op_code == SXR_WRITE) { _VOID_ ule_format(E_SX0005_INTERNAL_ERROR, NULL, ULE_LOG, NULL, NULL, 0L, NULL, &error, 0); _VOID_ ule_format(E_SX1048_SERVER_TERMINATE, NULL, ULE_LOG, NULL, NULL, 0L, NULL, &error, 0); _VOID_ CSterminate(CS_KILL, NULL); } SETDBERR(&rcb->sxf_error, 0, E_SX0005_INTERNAL_ERROR); return (E_DB_FATAL); }
/*{ ** Name: opn_ceval - evaluate the cost of the join operator tree ** ** Description: ** Entry point for routines which evaluate cost of a join operator tree. ** Contains checks for timeouts within the optimizer. ** ** Inputs: ** subquery ptr to subquery being analyzed ** ->ops_estate.opn_sroot ptr to root of join operator tree ** ** Outputs: ** subquery->ops_bestco ptr to best plan found ** subquery->ops_cost cost of best plan found ** Returns: ** VOID ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 11-jun-86 (seputis) ** initial creation from costeval ** 2-nov-88 (seputis) ** changed CSstatistics interface ** 2-nov-88 (seputis) ** add trace flag to timeout on number of plans being evaluated ** 15-aug-89 (seputis) ** add trace flag to adjust timeout factor which converts cost to time ** used to help isolate early timeout problems ** 16-may-90 (seputis) ** - b21582, move timeout checking to opn_timeout routine so it can be ** called from opn_arl ** 17-oct-90 (seputis) ** - b33386 - print error is no qep is found ** 22-apr-91 (seputis) ** - fix floating point exception handling problems ** 19-nov-99 (inkdo01) ** Changes to remove EXsignal from opn_exit processing. ** 18-oct-02 (inkdo01) ** Changes to enable new enumeration. ** 30-mar-2004 (hayke02) ** Call opn_exit() with a FALSE longjump. ** 30-Jun-2006 (kiria01) b116309 ** Capture memory exhaustion error to errlog.log. ** 11-Mar-2008 (kschendel) b122118 ** Remove unused ops_tempco. Fix up bfexception stuff so that we ** stop calling recover pointlessly at the start of every query. [@history_line@]... */ OPN_STATUS opn_ceval( OPS_SUBQUERY *subquery) { EX_CONTEXT excontext; /* context block for exception ** handler*/ OPN_SUBTREE *opn_ssubtp; /* dummy var ignored at this level ** - list of subtrees with possible cost ** orderings (including reformats) ** - all element in the list have same ** relations but in different order or ** use a different tree structure. */ OPN_RLS *opn_srlmp; /* dummy var ignored at this level ** - list of list of subtrees, with a ** different set of relations for each ** OPN_RLS element */ OPN_EQS *opn_seqp; /* dummy var ignored at this level ** - used to create a list of different ** OPN_SUBTREE (using indexes) if ** an index exists. */ OPN_STATUS sigstat = OPN_SIGOK; if ( EXdeclare(opn_mhandler, &excontext) == EX_DECLARE ) /* set ** up exception handler to ** recover from out of memory ** errors */ { /* this point will only be reached if the enumeration processing has ** run out of memory. The optimizer will try to continue by copying ** the best CO tree found so far, out of enumeration memory, and ** reinitializing the enumeration stream, and continuing. ** The out-of-memory error will be reported if a complete pass of ** cost evaluation cannot be completed. */ (VOID)EXdelete(); /* cancel exception handler prior ** to exiting routine */ if (subquery->ops_global->ops_gmask & OPS_FLINT) { subquery->ops_global->ops_gmask &= ~OPS_FLINT; /* reset exception ** indicator */ return(OPN_SIGOK); /* skip this plan if a float ** or integer exception has occurred ** during processing */ } if ( EXdeclare(opn_mhandler, &excontext) == EX_DECLARE ) /* set ** exception handler to catch case in ** which no progress is made */ { (VOID)EXdelete(); /* cancel exception handler prior ** to exiting routine */ if (subquery->ops_bestco) opx_verror(E_DB_WARN, E_OP0400_MEMORY, (OPX_FACILITY)0); /* report ** warning message to caller */ else { opx_lerror(E_OP0400_MEMORY, 0); /* Output to errlog.log as well kiria01-b116309 */ opx_error(E_OP0400_MEMORY); /* exit with a user error if the query ** cannot find at least one acceptable ** query plan */ } opn_exit(subquery, FALSE); /* exit with current query plan */ return(OPN_SIGEXIT); } opn_recover(subquery); /* routine will copy best CO tree ** and reinitialize memory stream */ } subquery->ops_global->ops_gmask &= (~OPS_FPEXCEPTION); /* reset fp exception ** indicator before evaluating ** plan */ if (subquery->ops_global->ops_gmask & OPS_BFPEXCEPTION && subquery->ops_bestco != NULL) opn_recover(subquery); /* if the current best plan occurred with ** exceptions then enumeration memory needs ** to be flushed, so that subsequent plans ** do not use subtrees which may have ** been created with exceptions, this means ** that the OPF cache of sub-trees is not ** used if one exception has occurred and ** the current best plan was created with ** exceptions */ (VOID) opn_nodecost ( subquery, subquery->ops_global->ops_estate.opn_sroot, (subquery->ops_mask & OPS_LAENUM) ? subquery->ops_laeqcmap : &subquery->ops_eclass.ope_maps.opo_eqcmap, &opn_ssubtp, &opn_seqp, &opn_srlmp, &sigstat); if (sigstat != OPN_SIGEXIT && !(subquery->ops_mask & OPS_LAENUM) && opn_timeout(subquery)) /* check for timeout (but only for ** old style enumeration) */ { (VOID)EXdelete(); /* cancel exception handler prior ** to exiting routine, call after ** opn_timeout in case out of memory ** errors occur */ opn_exit(subquery, FALSE); /* at this point we ** return the subquery->opn_bestco ** tree, this ** could also happen in freeco ** and enumerate */ return(OPN_SIGEXIT); } (VOID)EXdelete(); /* cancel exception handler prior ** to exiting routine */ return(sigstat); }
int main( int argc, char **argv ) { EX_CONTEXT context; char name[ GCC_L_PORT + 1 ]; u_i2 apivers; PTR hndl; #ifdef LNX PCsetpgrp(); #endif MEadvise( ME_INGRES_ALLOC ); if ( EXdeclare( GCX_exit_handler, &context ) != OK ) { gcu_erlog( 0, 1, E_GC480F_EXCEPTION, NULL, 0, NULL ); PCexit( OK ); return( 0 ); } GChostname( GCD_global.host, sizeof( GCD_global.host ) ); gcu_erinit( GCD_global.host, GCD_LOG_ID, "" ); if ( initialize( argc, argv ) != OK ) gcd_exit(); gcd_init_mib(); if ( gcd_gca_init( ) != OK ) gcd_exit(); gcu_erinit( GCD_global.host, GCD_LOG_ID, GCD_global.gcd_lcl_id ); if ( gcd_adm_init() != OK ) gcd_exit(); apivers = gcd_msg_version( MSG_DFLT_PROTO ); if ( gcd_get_env( apivers, &hndl ) != OK ) gcd_exit(); if ( gcd_pool_init() != OK ) gcd_exit(); if ( gcd_gcc_init() != OK ) gcd_exit(); /* ** Log Server startup. */ { char server_flavor[256], server_type[32]; char *tmpbuf = PMgetDefault(3); ER_ARGUMENT erlist[2]; SIstd_write(SI_STD_OUT, "PASS\n"); if ( ! STbcompare( tmpbuf, 0, "*", 0, TRUE ) ) STcopy( "(DEFAULT)", server_flavor ); else STcopy( tmpbuf, server_flavor ); STcopy(PMgetDefault(2), server_type); CVupper(server_type); erlist[0].er_value = server_flavor; erlist[0].er_size = STlength(server_flavor); erlist[1].er_value = server_type; erlist[1].er_size = STlength(server_type); gcu_erlog( 0, GCD_global.language, E_GC4802_LOAD_CONFIG, NULL, 2, (PTR)&erlist ); gcu_erlog( 0, GCD_global.language, E_GC4800_STARTUP, NULL, 0, NULL ); } GCexec(); gcd_gcc_term(); gcd_pool_term(); gcd_rel_env(0); gcd_adm_term(); gcd_gca_term(); gcu_erlog( 0, GCD_global.language, E_GC4801_SHUTDOWN, NULL, 0, NULL ); EXdelete(); PCexit( OK ); return( 0 ); }
/* ** Name: PCexec_suid - Execute a command as the ingres user. ** ** Description: ** This procedure works with the Ingres service to run the given ** command as the ingres user. It mimicks the "setuid" bit in UNIX. ** ** Inputs: ** cmdbuf - command to execute as the ingres user ** ** Outputs: ** none ** ** Returns: ** OK ** FAIL ** ** Side Effects: ** none ** ** History: ** 08-jan-1998 (somsa01) ** Created. ** 19-feb-1998 (somsa01) ** We need to pass to the service the current working directory ** as well. (Bug #89006) ** 25-feb-1998 (somsa01) ** We now have an input file for the process' stdin which ** runs through the OpenIngres service. ** 19-jun-1998 (somsa01) ** Use SYSTEM_PRODUCT_NAME for the name of the service. ** 10-jul-1998 (kitch01) ** Bug 91362. If user is 'system' run through OpenIngres service ** despite having access to server shared memory 'system' does not ** have required privilege to access semaphores/mutexes. ** 11-jun-1999 (somsa01) ** If the command is a startup command, then it is always run through ** the Ingres service. ** 03-nov-1999 (somsa01) ** A failure from ControlService() should be treated as a severe ** error which should not let us continue. ** 22-jan-2000 (somsa01) ** Return the exit code of the spawned process. Also, if the ** files exist, truncate them. The service name is now keyed off ** of II_INSTALLATION. ** 05-jun-2000 (somsa01) ** The Ingres installation may be started as the SYSTEM account, ** in which the 'ingres' user will not automatically have access ** to the shared memory segments. Therefore, even if the real ** user is 'ingres', check to see if he has access. ** 24-oct-2000 (somsa01) ** Removed the check on shared memory access. Access to the shared ** memory segment does not necessarily mean that the user running ** the process does not need to run the specified process as the ** Ingres owner. Also, generalized the check of the user with ** IDname_service(). ** 18-dec-2000 (somsa01) ** Modified the cases to run the command "as is" without the Ingres ** service. ** 20-mar-2002 (somsa01) ** If all is well, return the exit code of the child process that ** was executed. ** 29-mar-2002 (somsa01) ** Properly return the child process exit code. ** 11-apr-2003 (somsa01) ** While waiting for "pending" to not be set, give some CPU back ** to the OS. ** 29-Jul-2005 (drivi01) ** Allow user to run the command if he/she owns a shared ** segment and ingres is not running as a service. ** 06-Dec-2006 (drivi01) ** Adding support for Vista, Vista requires "Global\" prefix for ** shared objects as well. Replacing calls to GVosvers with ** GVshobj which returns the prefix to shared objects. ** Added PCadjust_SeDebugPrivilege to allow quering of ** System processes. ** 25-Jul-2007 (drivi01) ** On Vista, PCexec_suid is unable to use SE_DEBUG Privilege ** to query process status and retireve its exit code. ** The routine for monitoring a process and retrieving ** its exit code has been moved to Ingres Service. ** 05-Nov-2009 (wanfr01) b122847 ** Don't do a PCsleep unless you are waiting for more input */ STATUS PCexec_suid(char *cmdbuf) { EX_CONTEXT context; SERVICE_STATUS ssServiceStatus; LPSERVICE_STATUS lpssServiceStatus = &ssServiceStatus; struct SETUID setuid; DWORD ProcID; HANDLE SaveStdout; SECURITY_ATTRIBUTES sa; CHAR szRealUserID[25] = ""; CHAR *pszRealUserID = szRealUserID; CHAR szServiceUserID[25] = ""; CHAR *pszServiceUserID = szServiceUserID; DWORD BytesWritten, BytesRead = 0; CHAR *inst_id; CHAR SetuidShmName[64]; CHAR *temp_loc; CHAR InBuf[256], OutBuf[256]; static CHAR SetuidPipeName[32]; CL_ERR_DESC err_code; CHAR ServiceName[255]; DWORD ExitCode = 0; CHAR tchII_INSTALLATION[3]; BOOL SetuidDbCmd = FALSE, ServiceCommand = FALSE; int i, cmdlen; char *ObjectPrefix; u_i4 drType; SC_HANDLE schSCManager, OpIngSvcHandle; BOOL bServiceStarted = FALSE; if (EXdeclare(ex_handler, &context) != OK) { EXdelete(); PCexit(FAIL); } NMgtAt("II_INSTALLATION", &inst_id); STcopy(inst_id, tchII_INSTALLATION); /* ** See if this is a command that MUST be run through the Ingres ** service. */ cmdlen = (i4)STlength(cmdbuf); for (i = 0; ServiceCommands[i] ; i++) { if (STbcompare( cmdbuf, cmdlen, ServiceCommands[i], (i4)STlength(ServiceCommands[i]), FALSE ) == 0) { ServiceCommand = TRUE; break; } } /* ** If the user is the same as the user who started the Ingres ** service, just spawn the command. */ if (!ServiceCommand) { IDname(&pszRealUserID); if (!IDname_service(&pszServiceUserID) && STcompare(pszServiceUserID, pszRealUserID) == 0 && PCisAdmin()) { /* ** Attempt to just execute the command. */ return( PCcmdline( (LOCATION *) NULL, cmdbuf, PC_WAIT, (LOCATION *) NULL, &err_code) ); } else { /* ** If current user is not the same as service user and ingres is not ** running as a service, check if shared memory segment is owned ** by current user, if user has access to shared segment allow him ** to run the command. */ PTR shmem; SIZE_TYPE allocated_pages=0; STATUS status; if((status = MEget_pages(ME_MSHARED_MASK, 1, "lglkdata.mem", &shmem, &allocated_pages, &err_code)) == OK) { STprintf(ServiceName, "%s_Database_%s", SYSTEM_SERVICE_NAME, tchII_INSTALLATION); if ((schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) != NULL) { if ((OpIngSvcHandle = OpenService(schSCManager, ServiceName, SERVICE_QUERY_STATUS)) != NULL) { if (QueryServiceStatus(OpIngSvcHandle,lpssServiceStatus)) { if (ssServiceStatus.dwCurrentState != SERVICE_STOPPED) bServiceStarted = TRUE; } } } if (!bServiceStarted) return(PCcmdline( (LOCATION *) NULL, cmdbuf, PC_WAIT, (LOCATION *) NULL, &err_code) ); } } /* ** See if this command is an Ingres command which needs to interact ** with at least one database. */ for (i = 0; validSetuidDbCmds[i] ; i++) { if (STbcompare( cmdbuf, cmdlen, validSetuidDbCmds[i], (i4)STlength(validSetuidDbCmds[i]), FALSE ) == 0) { SetuidDbCmd = TRUE; break; } } /* ** If the user has access to the Ingres shared memory segment, ** just spawn the command provided that it is not in the ** validSetuidDbCmds list. */ if (!SetuidDbCmd) { PTR shmem; SIZE_TYPE allocated_pages=0; STATUS status; if (((status = MEget_pages(ME_MSHARED_MASK, 1, "lglkdata.mem", &shmem, &allocated_pages, &err_code)) == OK) || (status == ME_NO_SUCH_SEGMENT)) { if (status != ME_NO_SUCH_SEGMENT) MEfree_pages(shmem, allocated_pages, &err_code); return( PCcmdline( (LOCATION *) NULL, cmdbuf, PC_WAIT, (LOCATION *) NULL, &err_code) ); } } } /* ** We must run the command through the Ingres service. */ if ( STstrindex(cmdbuf, "-silent", 0, FALSE ) ) SilentMode = TRUE; iimksec(&sa); GVshobj(&ObjectPrefix); STprintf(SetuidShmName, "%s%sSetuidShm", ObjectPrefix, tchII_INSTALLATION); if ( (SetuidShmHandle = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, SetuidShmName)) == NULL ) { error_exit(GetLastError()); return(FAIL); } if ( (SetuidShmPtr = MapViewOfFile(SetuidShmHandle, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, sizeof(struct SETUID_SHM))) == NULL ) { error_exit(GetLastError()); return(FAIL); } /* Set up the information to send to the service. */ STcopy(cmdbuf, setuid.cmdline); GetCurrentDirectory(sizeof(setuid.WorkingDirectory), setuid.WorkingDirectory); NMgtAt("II_TEMPORARY", &temp_loc); drType = GetDriveType(NULL); if (drType == DRIVE_REMOTE) { STcopy(temp_loc, setuid.WorkingDirectory); } SaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); CVla(GetCurrentProcessId(), setuid.ClientProcID); STprintf(SetuidPipeName, "\\\\.\\PIPE\\INGRES\\%s\\SETUID", inst_id); /* Set up the stdout file for the command. */ STprintf(OutfileName, "%s\\%sstdout.tmp", temp_loc, setuid.ClientProcID); if ( (OutFile = CreateFile(OutfileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE ) { error_exit(GetLastError()); return(FAIL); } /* Set up the stdin file for the command. */ STprintf(InfileName, "%s\\%sstdin.tmp", temp_loc, setuid.ClientProcID); if ( (InFile = CreateFile(InfileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL)) == INVALID_HANDLE_VALUE ) { error_exit(GetLastError()); return(FAIL); } /* Wait until the service is ready to process our request. */ while (SetuidShmPtr->pending == TRUE) PCsleep(100); SetuidShmPtr->pending = TRUE; /* Trigger the "setuid" event of the service. */ if ( (schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL) { error_exit(GetLastError()); return(FAIL); } STprintf(ServiceName, "%s_Database_%s", SYSTEM_SERVICE_NAME, tchII_INSTALLATION ); OpIngSvcHandle = OpenService(schSCManager, ServiceName, SERVICE_USER_DEFINED_CONTROL); if (OpIngSvcHandle == NULL) { STprintf(ServiceName, "%s_DBATools_%s", SYSTEM_SERVICE_NAME, tchII_INSTALLATION ); OpIngSvcHandle = OpenService(schSCManager, ServiceName, SERVICE_USER_DEFINED_CONTROL); } if ( OpIngSvcHandle == NULL) { error_exit(GetLastError()); return(FAIL); } if (!ControlService(OpIngSvcHandle, RUN_COMMAND_AS_INGRES, lpssServiceStatus)) { error_exit(GetLastError()); CloseServiceHandle(schSCManager); return(FAIL); } WaitNamedPipe(SetuidPipeName, NMPWAIT_WAIT_FOREVER); /* Send the information to the service. */ if ( (Setuid_Handle = CreateFile(SetuidPipeName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE ) { error_exit(GetLastError()); return(FAIL); } if (!WriteFile(Setuid_Handle, &setuid, sizeof(struct SETUID), &BytesWritten, NULL)) { error_exit(GetLastError()); return(FAIL); } /* ** Retrieve information back from the service, and then ** disconnect from the pipe. */ if (!ReadFile(Setuid_Handle, &setuid, sizeof(struct SETUID), &BytesRead, NULL)) { error_exit(GetLastError()); return(FAIL); } ProcID = setuid.CreatedProcID; SetuidShmPtr->pending = FALSE; UnmapViewOfFile(SetuidShmPtr); SetuidShmPtr = NULL; CloseHandle(SetuidShmHandle); if ( (ProcID != -1) && (ProcID != -2) ) { /* ** Wait for the "spawned" process to exit, reading its output ** from the stdout file. */ for (;;) { if ( ((!ReadFile(OutFile, OutBuf, sizeof(OutBuf), &BytesRead, NULL) || (BytesRead == 0)) && setuid.ExitCode != STILL_ACTIVE )) break; if ( BytesRead && (!WriteFile(SaveStdout, OutBuf, BytesRead, &BytesWritten, NULL)) && setuid.ExitCode != STILL_ACTIVE) break; else if (BytesRead < sizeof(OutBuf)) PCsleep(200); /* ** Currently, the only DBA program which can require ** user input is verifydb. Therefore, when it spits out ** the appropriate messages asking for user input, get ** it from the end user and pass it along to the spawned ** process. */ if ( (STrstrindex(OutBuf, "S_DU04FF_CONTINUE_PROMPT", 0, FALSE) != NULL) || (STrstrindex(OutBuf, "S_DU0300_PROMPT", 0, FALSE) != NULL) ) { SIflush(stdout); MEfill(sizeof(OutBuf), ' ', &OutBuf); MEfill(sizeof(InBuf), ' ', &InBuf); SIgetrec(InBuf, 255, 0); WriteFile(InFile, InBuf, sizeof(OutBuf), &BytesWritten, NULL); } } ExitCode = setuid.ExitCode; CloseHandle(Setuid_Handle); CloseHandle(InFile); DeleteFile(InfileName); CloseHandle(OutFile); DeleteFile(OutfileName); CloseServiceHandle(OpIngSvcHandle); CloseServiceHandle(schSCManager); return(ExitCode); } else { error_exit(GetLastError()); return(FAIL); } }
i4 main( i4 argc, char **argv ) { STATUS generic_status = OK; CL_ERR_DESC system_status; EX_CONTEXT context; STATUS status; GCC_ERLIST erlist; STATUS (*call_list[7])(); i4 i, call_count; i4 cmd_args = 0; char usage[] = { "Usage: iigcb -from <protocol>" }; char usage1[] = { " -to <protocol> <hostname> < listen_address>" }; #ifdef LNX PCsetpgrp(); #endif MEfill( sizeof( system_status ), 0, (PTR)&system_status ); MEadvise( ME_INGRES_ALLOC ); EXdeclare( GCX_exit_handler, &context ); SIeqinit(); /* ** Parse command line. */ for( i = 1; i < argc; i++ ) if ( ! STcompare( argv[i], "-from" ) ) { if ( ++i >= argc ) { SIfprintf( stderr, "\n%s%s\n\n", usage, usage1 ); SIflush( stderr ); SIstd_write(SI_STD_OUT, "\nFAIL\n"); EXdelete(); PCexit( FAIL ); } STcopy( argv[i], gcb_from_addr.n_sel ); CVupper( gcb_from_addr.n_sel ); ++cmd_args; } else if ( ! STcompare( argv[ i ], "-to" ) ) { if ( (i + 3) >= argc ) { SIfprintf( stderr, "\n%s%s\n\n", usage, usage1 ); SIflush( stderr ); SIstd_write(SI_STD_OUT, "\nFAIL\n"); EXdelete(); PCexit( FAIL ); } STcopy( argv[ ++i ], gcb_to_addr.n_sel ); STcopy( argv[ ++i ], gcb_to_addr.node_id ); STcopy( argv[ ++i ], gcb_to_addr.port_id ); CVupper( gcb_to_addr.n_sel ); ++cmd_args; } if ( cmd_args ) if ( cmd_args == 2 ) gcb_pm_reso.cmd_line = TRUE; else { SIfprintf( stderr, "\n%s%s\n\n", usage, usage1 ); SIflush( stderr ); SIstd_write(SI_STD_OUT, "\nFAIL\n"); EXdelete(); PCexit( FAIL ); } /* ** Perform general initialization. The bridge may be run ** for async lines as a part of Ingres/Net. Otherwise, ** Bridge authorization is required. */ if ( gcb_pm_reso.cmd_line && ! STcasecmp( gcb_from_addr.n_sel, ERx("async") ) ) status = gcc_init( FALSE, CI_INGRES_NET, argc, argv, &generic_status, &system_status ); else { #ifdef CI_INGRES_BRIDGE status = gcc_init( FALSE, CI_INGRES_BRIDGE, argc, argv, &generic_status, &system_status ); #else generic_status = E_GC2A0F_NO_AUTH_BRIDGE; status = FAIL; #endif } if ( status != OK ) { gcc_er_log( &generic_status, &system_status, NULL, NULL ); generic_status = E_GC2A01_INIT_FAIL; gcc_er_log( &generic_status, NULL, NULL, NULL ); SIstd_write(SI_STD_OUT, "\nFAIL\n"); EXdelete(); PCexit( FAIL ); } /* ** Perform standalong Bridge Server initialization. */ IIGCc_global->gcc_flags |= GCC_STANDALONE; gcb_init_mib(); /* ** Initialize the protocol layers. */ call_list[0] = GCcinit; call_list[1] = gcb_alinit; call_list[2] = gcc_pbinit; call_count = 3; if ( gcc_call( &call_count, call_list, &generic_status, &system_status ) != OK ) { gcc_er_log( &generic_status, &system_status, NULL, NULL ); generic_status = E_GC2A01_INIT_FAIL; gcc_er_log( &generic_status, NULL, NULL, NULL ); SIstd_write(SI_STD_OUT, "\nFAIL\n"); } else { { /* ** Obtain and fix up the configuration name, then log it. */ char server_flavor[256], server_type[32]; char *tmpbuf = PMgetDefault(3); if (!STbcompare( tmpbuf, 0, "*", 0, TRUE )) STcopy("(DEFAULT)", server_flavor); else STcopy(tmpbuf, server_flavor); STcopy(PMgetDefault(2), server_type); CVupper(server_type); erlist.gcc_parm_cnt = 2; erlist.gcc_erparm[0].value = server_flavor; erlist.gcc_erparm[0].size = STlength(server_flavor); erlist.gcc_erparm[1].value = server_type; erlist.gcc_erparm[1].size = STlength(server_type); generic_status = E_GC2A10_LOAD_CONFIG; gcc_er_log( &generic_status, (CL_ERR_DESC *)NULL, (GCC_MDE *)NULL, &erlist); } erlist.gcc_parm_cnt = 1; erlist.gcc_erparm[0].size = STlength( IIGCc_rev_lvl ); erlist.gcc_erparm[0].value = IIGCb_rev_lvl; generic_status = E_GC2A03_STARTUP; gcc_er_log( &generic_status, NULL, NULL, &erlist ); /* ** Invoke GCexec to enter the main phase of Protocol bridge ** execution. GCexec does not return until bridge shutdown ** is initiated by invoking GCshut. */ GCexec(); generic_status = E_GC2A04_SHUTDOWN; gcc_er_log( &generic_status, &system_status, NULL, NULL ); } /* ** GCexec has returned. Bridge shutdown is in process. ** Initialize the call list to specify termination rotutines. ** Call in reverse order of initialization but don't call ** termination routines whose initialization routines were ** not called (call_count has the number of successful ** initialization calls). */ call_list[0] = gcb_alterm; call_list[1] = gcc_pbterm; call_list[2] = GCcterm; if ( gcc_call( &call_count, &call_list[ 3 - call_count ], &generic_status, &system_status ) ) gcc_er_log( &generic_status, &system_status, NULL, NULL ); /* ** Do general server termination. */ if ( gcc_term( &generic_status, &system_status ) != OK ) gcc_er_log( &generic_status, &system_status, NULL, NULL ); EXdelete(); PCexit( OK ); } /* end main */