Example #1
0
VOID
CloseAsc(ASSOC_IPC * asipc)
{
        int i = 0;

	/*
	** If we are a gcc let the client disconnect first. If ten seconds 
	** elapse then disconnect anyways.
	*/ 
	while( is_gcc && asipc->IpcInternal.AssocInfo->bPipesClosed == FALSE 
			&& i++ < 200 )
		PCsleep(50);

	if (asipc->SndStdChan)
        CloseHandle(asipc->SndStdChan);
	if (asipc->RcvStdChan)
	{
        WriteFile(asipc->RcvStdChan, "", 1, &i, NULL);
        Sleep(0);
        CloseHandle(asipc->RcvStdChan);
	}
	if (asipc->SndExpChan)
        CloseHandle(asipc->SndExpChan);
	if (asipc->RcvExpChan)
	{
        WriteFile(asipc->RcvExpChan, "", 1, &i, NULL);
        Sleep(0);
        CloseHandle(asipc->RcvExpChan);
	}
	if (asipc->ClientReadHandle)
	    CloseHandle(asipc->ClientReadHandle);
	
	/* Mark pipes as being closed. */
	if ( asipc->IpcInternal.AssocInfo )
	{
	    asipc->IpcInternal.AssocInfo->bPipesClosed = TRUE;
	    asipc->IpcInternal.AssocInfo->refs--; /* decrement reference ct */ 
	    asipc->IpcInternal.AssocInfo = NULL; 
	}
	
	asipc->SndStdChan = NULL;
	asipc->RcvStdChan = NULL;
	asipc->SndExpChan = NULL;
	asipc->RcvExpChan = NULL;
	asipc->ClientReadHandle = NULL;
	
	if ( asipc->IpcInternal.server )	
	{
		asipc->IpcInternal.server->nConnections--;
		if ( 0 == asipc->IpcInternal.server->nConnections )
			 RemoveServer( asipc->IpcInternal.server );
	}

	return;
}
Example #2
0
STATUS
create_canon_fe(SEPFILE *res_ptr)
{
    STATUS                 ret_val = OK ;   /* if OK, refresh FE screen */
    char                   do_com_result ;

#ifdef VMS
    if (SEPtcsubs < 4)
	PCsleep(1000);
#endif
    show_cursor();

    do_com_result = do_comments();
    append_line(OPEN_CANON,1);
    switch (do_com_result)
    {
       case 'R':
       case 'r':
		append_sepfile(res_ptr);
		break;
       case 'E':
       case 'e':
		break;
       case 'I':
       case 'i':
		append_line(SKIP_SYMBOL,1);
		break;
    }
    append_line(CLOSE_CANON,1);
    kfe_ptr = kfebuffer;                /* reset counter for key buffer */

    if (canonAns == EOS)
    {
	disp_prompt(NULLSTR,NULL,NULL);	/* erase prompt */
    }
    else
    {
	CMnext(kfe_ptr);
	ret_val = FAIL;			/* don't refresh FE screen */
    }
    return (ret_val);
}
Example #3
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);
    }
}
Example #4
0
ADF_CB *
FEadfcb ()
{
    if (!done)
    {
	char		*cp;
	DB_STATUS	rval;
	PTR		srv_cb_ptr;
	SIZE_TYPE	srv_size;
	SIZE_TYPE	dbinfo_size;
	PTR		dbinfoptr;
        STATUS          tmtz_status;
        STATUS          date_status;
	char		date_type_alias[100];
        char            col[] = "udefault";
    	STATUS          status = OK;
    	CL_ERR_DESC     sys_err;
	ADUUCETAB	*ucode_ctbl; /* unicode collation information */
        PTR         	ucode_cvtbl;


	
    	done = TRUE;

	/* first, get the size of the ADF's server control block */
	srv_size = adg_srv_size();

	/* allocate enough memory for it */
	if ((srv_cb_ptr = MEreqmem(0, srv_size, FALSE, (STATUS *)NULL)) == NULL)
	{
    	    EXsignal(EXFEBUG, 1, ERx("FEadfcb(alloc)"));
	}

	/*
	**  Fix up code so that "now" works properly for frontends.
	**  Only allocating enough for one (1) dbmsinfo() request.
	*/
	dbinfo_size = sizeof(ADF_TAB_DBMSINFO);
	if ((dbinfoptr = MEreqmem(0, dbinfo_size, TRUE, (STATUS*)NULL)) == NULL)
	{
		IIUGbmaBadMemoryAllocation(ERx("FEadfcb"));
	}

	dbinfo = (ADF_TAB_DBMSINFO *) dbinfoptr;

	dbinfo->tdbi_next = NULL;
	dbinfo->tdbi_prev = NULL;
	dbinfo->tdbi_length = dbinfo_size;
	dbinfo->tdbi_type = ADTDBI_TYPE;
	dbinfo->tdbi_s_reserved = -1;
	dbinfo->tdbi_l_reserved = (PTR)-1;
	dbinfo->tdbi_owner = (PTR)-1;
	dbinfo->tdbi_ascii_id = ADTDBI_ASCII_ID;
	dbinfo->tdbi_numreqs = 1;

	/*
	**  Now define request.
	*/
	dbinfo->tdbi_reqs[0].dbi_func = IIUGnfNowFunc;
	dbinfo->tdbi_reqs[0].dbi_num_inputs = 0;
	dbinfo->tdbi_reqs[0].dbi_lenspec.adi_lncompute = ADI_FIXED;
	STcopy("_BINTIM", dbinfo->tdbi_reqs[0].dbi_reqname);
	dbinfo->tdbi_reqs[0].dbi_reqcode = 1;
	dbinfo->tdbi_reqs[0].dbi_lenspec.adi_fixedsize = 4;
	dbinfo->tdbi_reqs[0].dbi_dtr = DB_INT_TYPE;

	/*
	** set timezone in ADF cb  - Any errors must be reported
        ** after adg_init() called.
	*/

	if ( (tmtz_status = TMtz_init(&cb.adf_tzcb)) == OK)
        {
	   tmtz_status = TMtz_year_cutoff(&cb.adf_year_cutoff);
        }

	/* Always use INGRESDATE by default, and check 
	** 'ii.<node>.config.date_alias' (kibro01) b118702
	*/
	cb.adf_date_type_alias = AD_DATE_TYPE_ALIAS_INGRES;
	STprintf(date_type_alias,ERx("ii.%s.config.date_alias"),PMhost());
	date_status = PMget(date_type_alias, &cp);
	if (date_status == OK && cp != NULL && STlength(cp))
	{
	    if (STbcompare(cp, 0, ERx("ansidate"), 0, 1) == 0)
		cb.adf_date_type_alias = AD_DATE_TYPE_ALIAS_ANSI;
	    else if (STbcompare(cp, 0, ERx("ingresdate"), 0, 1) == 0)
		cb.adf_date_type_alias = AD_DATE_TYPE_ALIAS_INGRES;
	    else
		cb.adf_date_type_alias = AD_DATE_TYPE_ALIAS_NONE;
	}

	/* set timezone table to NULL in ADF cb, adg_init() will fill it */
	/* cb.adf_tz_table = NULL; - not needed, done in declaration above */

	/* Start up ADF */
    	rval = adg_startup(srv_cb_ptr, srv_size, dbinfo, 0);
	if (DB_FAILURE_MACRO(rval))
	{
	    /*
	    ** Before bailing out, try to be helpful. Since the environment
	    ** is likely not set up correctly, write hard coded messages
	    ** since error message fetch will likely fail in this situation.
	    */
	    char	*tempchar;
	    i4		dummy;
	    LOCATION	temploc;
	    NMgtAt("II_SYSTEM", &tempchar);
	    if (tempchar && *tempchar)
	    {
		LOfroms(PATH, tempchar, &temploc);
		if (LOexist(&temploc))
		{
		    tempchar = ERx("FEadfcb: II_SYSTEM DOES NOT EXIST\n");
		    SIwrite(STlength(tempchar), tempchar, &dummy, stderr);
		}
		else
		{
		    NMloc(ADMIN, FILENAME, ERx("config.dat"), &temploc);
		    if (LOexist(&temploc))
		    {
			tempchar = ERx("FEadfcb: II_SYSTEM IS NOT SET CORRECTLY\n");
			SIwrite(STlength(tempchar), tempchar, &dummy, stderr);
		    }
		}
	    }
	    else
	    {
		tempchar = ERx("FEadfcb: II_SYSTEM IS NOT SET\n");
		SIwrite(STlength(tempchar), tempchar, &dummy, stderr);
	    }
    	    EXsignal(EXFEBUG, 1, ERx("FEadfcb(start)"));
	}

	/* put the pointer to ADF's server control block in the ADF_CB */
	cb.adf_srv_cb = srv_cb_ptr;

	/* set up the error message buffer */
    	cb.adf_errcb.ad_ebuflen = DB_ERR_SIZE;
    	cb.adf_errcb.ad_errmsgp = ebuffer;

	/* initialize the ADF_CB */
    	rval = adg_init(&cb);
	if (DB_FAILURE_MACRO(rval))
	{
    	    EXsignal(EXFEBUG, 1, ERx("FEadfcb(init)"));
	}

	/* find out which natural language we should speak */
	cb.adf_slang = iiuglcd_langcode();

	/* Always QUEL; for SQL explictly change this with 'IIAFdsDmlSet()'. */
	cb.adf_qlang = DB_QUEL;

	/* lets get the multinational info */

	/* 
	** Defaults for all of these are initially set statically, above.
	*/
	NMgtAt(ERx("II_DATE_FORMAT"), &cp);
    	if ( cp != NULL && *cp != EOS )
    	{
	    FEapply_date_format(&cb,cp);
    	}

	NMgtAt(ERx("II_MONEY_FORMAT"), &cp);
    	if ( cp != NULL && *cp != EOS )
    	{
	    FEapply_money_format(&cb,cp);
    	}

	NMgtAt(ERx("II_MONEY_PREC"), &cp);
    	if ( cp != NULL && *cp != EOS )
    	{
	    FEapply_money_prec(&cb,cp);
    	}

	NMgtAt(ERx("II_DECIMAL"), &cp);
    	if ( cp != NULL && *cp != EOS )
    	{
	    FEapply_decimal(&cb,cp);
    	}

	NMgtAt(ERx("II_UNICODE_SUBS"), &cp);
	if ( !cp )
	{
	    cb.adf_unisub_status = AD_UNISUB_OFF;
	}
	else
	{
	    /* As with SET unicode_substitution take the first char */
	    cb.adf_unisub_status = AD_UNISUB_ON;
	    *cb.adf_unisub_char = cp[0];
	}

	NMgtAt(ERx("II_NULL_STRING"), &cp);
	if ( cp != NULL && *cp != EOS )
	{
	    FEapply_null(&cb,cp);
	}

	/* If there was a Timezone error other than the expected ingbuild
	** error TM_PMFILE_OPNERR, then lets report it now. */

        if (tmtz_status && (tmtz_status != TM_PMFILE_OPNERR))
        {
	    LOCATION    loc_root;
	    STATUS status = OK;
	    status = NMloc(FILES, PATH, ERx("zoneinfo"), &loc_root);
#if defined(conf_BUILD_ARCH_32_64) && defined(BUILD_ARCH64)
            status = LOfaddpath(&loc_root, ERx("lp64"), &loc_root);
#endif
#if defined(conf_BUILD_ARCH_64_32) && defined(BUILD_ARCH32)
    {
        /*
        ** Reverse hybrid support must be available in ALL
        ** 32bit binaries
        */
        char    *rhbsup;
        NMgtAt("II_LP32_ENABLED", &rhbsup);
        if ( (rhbsup && *rhbsup) &&
       ( !(STbcompare(rhbsup, 0, "ON", 0, TRUE)) ||
         !(STbcompare(rhbsup, 0, "TRUE", 0, TRUE))))
            status = LOfaddpath(&loc_root, "lp32", &loc_root);
    }
#endif /* ! LP64 */

            if ( status == OK )
            {
		status = LOexist(&loc_root);
            }
            if ( status == OK )
	    {
                   IIUGerr(tmtz_status, 0, 0);

                   /* As this may disappear from the screen quickly,
                   ** let's pause to allow the users to reflect on the
                   ** fact that the timezone info is (probably) wrong.
                   */
                   if (!IIugefa_err_function) PCsleep(5000);
	    }
        }

	/* Initialize unicode collation for UTF8 installations */
	if (CMischarset_utf8())
	{
          if (status = aduucolinit(col, MEreqmem, 
			&ucode_ctbl, &ucode_cvtbl, &sys_err))
          {
    	    EXsignal(EXFEBUG, 1, ERx("FEadfcb(alloc)"));
          }

          cb.adf_ucollation = (PTR) ucode_ctbl;

	  /* Set unicode normalization to NFC just in case 
	  ** Front end will need it.
	  */
          if ((status = adg_setnfc(&cb)) != E_DB_OK)
    	    EXsignal(EXFEBUG, 1, ERx("FEadfcb(alloc)"));
	}
	/* lets not do this again! */
    }

    return &cb;
}
Example #5
0
/*{
** Name: LGK_initialize()	-  initialize the lg/lk shared mem segment.
**
** Description:
**	This routine is called by the LGinitialize or LKinitialize routine.  IT
**	assumes that a previous caller has allocated the shared memory segment.
**
**	If it discovers that the shared memory segment has not yet been
**	initialized, it calls the LG and LK initialize-memory routines to do so.
**
** Inputs:
**	flag		- bit mask of:
**			  LOCK_LGK_MEMORY to lock the shared data segment
**			  LGK_IS_CSP if process is CSP process this node.
**
** Outputs:
**	sys_err		- place for system-specific error information.
**
**	Returns:
**	    OK	- success
**	    !OK - failure (CS*() routine failure, segment not mapped, ...)
**	
**  History:
**	Summer, 1992 (bryanp)
**	    Working on the new portable logging and locking system.
**	19-oct-1992 (bryanp)
**	    Check memory version number when attaching.
**	22-oct-1992 (bryanp)
**	    Change LGLKDATA.MEM to lglkdata.mem.
**	23-Oct-1992 (daveb)
**	    name the semaphore too.
**	13-feb-1993 (keving)
**	    Remove support for II_LGK_MEMORY_SIZE. If II_LG_MEMSIZE
**	    is not set then calculate memory size from PM values. 
**	24-may-1993 (bryanp)
**	    If the shared memory is the wrong version, don't install the
**	    at_exit handlers (the rundown routines won't be able to interpret
**	    the memory properly).
**	26-jul-1993 (jnash)
**	    Add 'flag' param lock the LGK data segment.
**	20-sep-1993 (bryanp)
**	    In addition to calling PCatexit, call (on VMS) sys$dclexh, since
**		there are some situations (image death and image rundown without
**		process rundown) which are caught neither by PCatexit (since
**		PCexit isn't run) nor by check-dead threads (since process
**		rundown never happened). This fixes a hole where an access-
**		violating ckpdb or auditdb command never got cleaned up.
**	31-jan-1994 (bryanp)
**	    Back out a few "features" which are proving countereffective:
**	    1) Don't bother checking mem_creator_pid to see if the previous
**		creator of the shared memory has died. This was an attempt to
**		gracefully re-use sticky shared memory following a system crash,
**		but it is suspected as being the culprit in a series of system
**		failures by re-initializing the shared memory at inopportune
**		times.
**	    2) Don't complain if the shared memory already exists but is of a
**		different size than you expected. Just go ahead and try to use
**		it anyway.
**	21-feb-1994 (bryanp)
**	    Reverse item (1) of the above 31-jan-1994 change and re-enable the
**		graceful re-use of shared memory. People weren't happy with
**		having to run ipcclean and csinstall all the time.
**	23-may-1994 (bryanp)
**	    On VMS, disable ^Y for LG/LK-aware processes. We don't want to allow
**		^Y because you might interrupt the process right in the middle
**		of an LG or LK operation, while holding the shared memory
**		semaphore, and this would then wedge the whole installation.
**          
**      17-May-1994 (daveb) 59127
**          Attach lgk_mem semaphore if we're attaching to the segment.
**      30-jan-1995 (lawst01) bug 61984
**          Use memory needed calculation from the 'lgk_calculate_size'
**          function to determine the size of the shared memory pool for
**          locking and locking. If the II_LG_MEMSIZE variable is specified
**          with a value larger than needed use the supplied value. If
**          lgk_calculate_size is unable to calculate a size then use the
**          magic number of 400000.  In addition issue a warning message
**          and continue executing in the event the number of pages
**          allocated is less than the number requested. 
**	24-apr-1997 (nanpr01)
**	    Reinstate Bryanp's change. In the process of fixing bug 61984
**	    by Steve Lawrence and subsequent undo of Steve's fix by Nick
**	    Ireland on 25-jun-96 (nick) caused the if 0 code removed.
**	    Part of the Steve's change was not reinstated such as not returning
**	    the status and exit and continue.
**	    1. Don't complain if the shared memory already exists but is of a
**	    different size than you expected. Just go ahead and try to use
**	    it.
**     18-aug-1998 (hweho01)
**          Reclaim the kernel resource if LG/LK shared memory segment is  
**          reinitialized. If the shared segment is re-used (the previous creator 
**          of the shared segment has died), the cross-process semaphores get 
**          initialized more than once at the same locations. That cause the
**          kernel resource leaks on DG/UX (OS release 4.11MU04). To fix the 
**          problem, CS_cp_sem_cleanup() is called to destroy all the 
**          semaphores before LG/LK shraed segment get recreated. 
**          CS_cp_sem_cleanup() is made dependent on xCL_NEED_SEM_CLEANUP and
**          OS_THREADS_USED, it returns immediately for most platforms.  
**	27-Mar-2000 (jenjo02)
**	    Added test for crossed thread types, refuse connection
**	    to LGK memory with E_DMA811_LGK_MT_MISMATCH.
**	18-apr-2001 (devjo01)
**	    s103715 (Portable cluster support)
**	    - Add CX mem requirement calculations.
**	    - Add LGK_IS_CSP flag to indicate that LGK memory is being
**	      initialized for a CSP process.
**	    - Add basic CX initialization.
**      19-sep-2002 (devjo01)
**          If running NUMA clustered allocate memory out of local RAD.
**	30-Apr-2003 (jenjo02)
**	    Rearchitected to silence long-tolerated race conditions.
**	    BUG 110121.
**	27-feb-2004 (devjo01)
**	    Rework allocation of CX shared memory to be compatible
**	    with race condition fix introduced for bug 110121.
**	29-Dec-2008 (jonj)
**	    If lgk_calculate_size() returns FAIL, the total memory
**	    needed exceeds MAX_SIZE_TYPE and we can't continue, but
**	    tell what we can about the needs of the various bits of
**	    memory before quitting.
**	06-Aug-2009 (wanfr01)
**	    Bug 122418 - Return E_DMA812 if LOCK_LGK_MUST_ATTACH is
**	    is passed in and memory segment does not exist
**      20-Nov-2009 (maspa05) bug 122642
**          In order to synchronize creation of UUIDs across servers added
**          a semaphore and a 'last time' variable into LGK memory. 
**      14-Dec-2009 (maspa05) bug 122642
**          #ifdef out the above change for Windows. The rest of the change
**          does not apply to Windows so the variables aren't defined.
*/
STATUS
LGK_initialize(
i4	  	flag,
CL_ERR_DESC	*sys_err,
char		*lgk_info)
{
    PTR		ptr;
    SIZE_TYPE	memleft;
    SIZE_TYPE	size;
    STATUS	ret_val;
    STATUS	mem_exists;
    char	mem_name[15];
    SIZE_TYPE	allocated_pages;
    i4		me_flags;
    i4		me_locked_flag;
    SIZE_TYPE	memory_needed;
    char	*nm_string;
    SIZE_TYPE	pages;
    LGK_MEM	*lgk_mem;
    i4		err_code;
    SIZE_TYPE   min_memory;
    i4		retries;
    i4		i;
    i4		attached;
    PID		*my_pid_slot;
    i4		clustered;
    u_i4	nodes;
    SIZE_TYPE	cxmemreq;
    PTR		pcxmem;
    LGLK_INFO	lgkcount;
    char	instid[4];

    CL_CLEAR_ERR(sys_err);

    /*
    ** if LGK_base is set then this routine has already been called.  It is
    ** set up so that both LGiniitalize and LKinitialize calls it, but only
    ** the first call does anything.
    */

    if (LGK_base.lgk_mem_ptr)
	return(OK);

    PCpid( &LGK_my_pid );

    memory_needed = 0;
    NMgtAt("II_LG_MEMSIZE", &nm_string);
    if (nm_string && *nm_string)
#if defined(LP64)
	if (CVal8(nm_string, (long*)&memory_needed))
#else
	if (CVal(nm_string, (i4 *)&memory_needed))
#endif /* LP64 */
	    memory_needed = 0;

    /* Always calculate memory needed from PM resource settings  */
    /* and compare with supplied value, if supplied value is less */
    /* than minimum then use minimum                             */

    min_memory = 0;
    if ( OK == lgk_get_counts(&lgkcount, FALSE))
    {
	if ( lgk_calculate_size(FALSE, &lgkcount, &min_memory) )
	{
	    /*
	    ** Memory exceeds MAX_SIZE_TYPE, can't continue.
	    ** 
	    ** Do calculation again, this time with "wordy"
	    ** so user can see allocation bits, then quit.
	    */
	    lgk_calculate_size(TRUE, &lgkcount, &min_memory);
	    return (E_DMA802_LGKINIT_ERROR); 
	}
    }
    if (min_memory)
       memory_needed = (memory_needed < min_memory) ? min_memory
                                                    : memory_needed;
    else
       memory_needed = (memory_needed < 400000 ) ? 400000 
                                                 : memory_needed;

    clustered = (i4)CXcluster_enabled();
    cxmemreq = 0;
    if ( clustered )
    {

	if ( OK != CXcluster_nodes( &nodes, NULL ) )
	    nodes = 0;
	cxmemreq = CXshm_required( 0, nodes, lgkcount.lgk_max_xacts,
		    lgkcount.lgk_max_locks, lgkcount.lgk_max_resources );
	if ( MAX_SIZE_TYPE - memory_needed < cxmemreq )
	{
	    /*
	    ** Memory exceeds MAX_SIZE_TYPE, can't continue.
	    ** 
	    ** Do calculation again, this time with "wordy"
	    ** so user can see allocation bits, then quit.
	    */
	    SIprintf("Total LG/LK/CX allocation exceeds max of %lu bytes by %lu\n"
	    	     "Adjust logging/locking configuration values and try again\n",
		         MAX_SIZE_TYPE, cxmemreq - (MAX_SIZE_TYPE - memory_needed));
	    lgk_calculate_size(TRUE, &lgkcount, &min_memory);
	    return (E_DMA802_LGKINIT_ERROR); 
	}
	memory_needed += cxmemreq;
    }

    if ( memory_needed < MAX_SIZE_TYPE - ME_MPAGESIZE )
	pages = (memory_needed + ME_MPAGESIZE - 1) / ME_MPAGESIZE;
    else
        pages = memory_needed / ME_MPAGESIZE;

    /*
    ** Lock the LGK segment if requested to do so
    */
    if (flag & LOCK_LGK_MEMORY)
	me_locked_flag = ME_LOCKED_MASK;
    else
	me_locked_flag = 0;

    me_flags = (me_locked_flag | ME_MSHARED_MASK | ME_IO_MASK | 
		ME_CREATE_MASK | ME_NOTPERM_MASK | ME_MZERO_MASK);
    if (CXnuma_user_rad())
        me_flags |= ME_LOCAL_RAD;

    STcopy("lglkdata.mem", mem_name);

    /*
    ** In general, we just want to attach to the shared memory and detect if
    ** we are the first process to do so. However, there are ugly race
    ** conditions to consider, as well as complications because the shared
    ** memory may be left around following a system crash.
    **
    ** First we attempt to create the shared memory. Usually it already exists,
    ** so we check for and handle the case of "already exists".
    */

    /*
    ** (jenjo02)
    **
    ** Restructured to better handle all those ugly race conditions
    ** which are easily reproduced by running two scripts, one that
    ** continuously executes "lockstat" while the other is starting
    ** and stopping Ingres.
    **
    ** For example,
    **
    **		lockstat A	acquires and init's the memory
    **		RCP		attaches to "A" memory
    **		lockstat A	terminates normally
    **		lockstat B	attaches to "A" memory, sees that
    **				"A"s pid is no longer alive, and
    **				reinitializes the memory, much to
    **				the RCP's chagrin.
    ** or (more commonly)
    **
    **		lockstat A	acquires and begins to init the mem
    **		RCP		attaches to "A" memory which is
    **				still being zero-filled by lockstat,
    **				checks the version number (zero),
    **				and fails with a E_DMA434 mismatch.
    **
    ** The fix utilizes the mem_ext_sem to synchronize multiple
    ** processes; if the semaphore hasn't been initialized or
    ** if mem_version_no is zero, we'll wait one second and retry,
    ** up to 60 seconds before giving up. This gives the creating
    ** process time to complete initialization of the memory.
    **
    ** Up to LGK_MAX_PIDS are allowed to attach to the shared
    ** memory. When a process attaches it sets its PID in the
    ** first vacant slot in lgk_mem->mem_pid[]; if there are
    ** no vacant slots, the attach is refused. When the process
    ** terminates normally by calling LGK_rundown(), it zeroes
    ** its PID slot.
    **
    ** When attaching to an existing segment, we check if  
    ** there are any live processes still using the memory;
    ** if so, we can't destroy it (no matter who created it).
    ** If there are no live processes attached to the memory,
    ** we destroy and reallocate it (based on current config.dat
    ** settings).
    */

    for ( retries = 0; ;retries++ )
    {
	LGK_base.lgk_mem_ptr = (PTR)NULL;
	
	/* Give up if unable to get memory in one minute */
#if defined(conf_CLUSTER_BUILD)
        if (retries > 1)
#else
	if ( retries )
#endif
	{
	    if ( retries < 60 )
		PCsleep(1000);
	    else
	    {
		/* Another process has it blocked way too long */
		uleFormat(NULL, E_DMA800_LGKINIT_GETMEM, (CL_ERR_DESC *)NULL,
				ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0);
		/* Unable to attach allocated shared memory segment. */
		return (E_DMA802_LGKINIT_ERROR); 
	    }
	}

	ret_val = MEget_pages(me_flags,
				pages, mem_name, (PTR*)&lgk_mem,
				&allocated_pages, sys_err);

	if ( mem_exists = ret_val )
	{
	    if (ret_val == ME_ALREADY_EXISTS)
	    {
		ret_val = MEget_pages((me_locked_flag | 
				       ME_MSHARED_MASK | ME_IO_MASK),
				      pages, mem_name, (PTR*)&lgk_mem,
				      &allocated_pages, sys_err);
#if defined(conf_CLUSTER_BUILD)
                if (ret_val && !retries)
                    continue;  /* try one more time */
#endif
	    }
	    if (ret_val)
	    {
		uleFormat(NULL, ret_val, sys_err,
				ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0);
		uleFormat(NULL, E_DMA800_LGKINIT_GETMEM, (CL_ERR_DESC *)NULL,
				ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0);
		/* Unable to attach allocated shared memory segment. */
		return (E_DMA802_LGKINIT_ERROR); 
	    }
	}
	else if (flag & LOCK_LGK_MUST_ATTACH)
	{	
	    /* Do not use the shared segment you just allocated */
	    MEfree_pages((PTR)lgk_mem, allocated_pages, sys_err);
	    return (E_DMA812_LGK_NO_SEGMENT); 
	}

	size = allocated_pages * ME_MPAGESIZE;

	/* Expose this process to the memory */
	LGK_base.lgk_mem_ptr = (PTR)lgk_mem;

	if ( mem_exists )
	{
	    /*
	    ** Memory exists.
	    **
	    ** Try to acquire the semaphore. If it's
	    ** uninitialzed, retry from the top.
	    **
	    ** If the version is zero, then another
	    ** process is initializing the memory;
	    ** keep retrying until the version is 
	    ** filled in.
	    **
	    */
	    if ( ret_val = CSp_semaphore(1, &lgk_mem->mem_ext_sem) )
	    {
		if ( ret_val != E_CS000A_NO_SEMAPHORE )
		{
		    uleFormat(NULL, ret_val, sys_err,
				ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0);
		    ret_val = E_DMA802_LGKINIT_ERROR;
		    break;
		}
		continue;
	    }

	    /* Retry if still being init'd by another process */
	    if ( !lgk_mem->mem_version_no )
	    {
		CSv_semaphore(&lgk_mem->mem_ext_sem);
		continue;
	    }

	    /*
	    ** Check pids which appear to be attached to
	    ** the memory:
	    **
	    ** If any process is still alive, then we
	    ** assume the memory is consistent and use it.
	    **
	    ** If a process is now dead, it terminated
	    ** without going through LGK_rundown
	    ** to zero its PID slot, zero it now.
	    **
	    ** If there are no live PIDs attached to 
	    ** the memory, we destroy and recreate it.
	    */
	    my_pid_slot = (PID*)NULL;
	    attached = 0;

	    for ( i = 0; i < LGK_MAX_PIDS; i++ )
	    {
		if ( lgk_mem->mem_pid[i] && 
		     PCis_alive(lgk_mem->mem_pid[i]) )
		{
		    attached++;
		}
		else
		{
		    /* Vacate the slot */
		    if (lgk_mem->mem_pid[i])
		    {
			uleFormat(NULL, E_DMA499_DEAD_PROCESS_INFO, (CL_ERR_DESC *)NULL,
				ULE_LOG, NULL, NULL, 0, NULL, &err_code, 2,
				0, lgk_mem->mem_pid[i],
				0, lgk_mem->mem_info[i].info_txt);
		    }
		    lgk_mem->mem_pid[i] = (PID)0;
		    lgk_mem->mem_info[i].info_txt[0] = EOS;

		    /* Use first vacant slot for this process */
		    if ( !my_pid_slot )
		    {
			my_pid_slot = &lgk_mem->mem_pid[i];
			LGK_base.lgk_pid_slot = i;
		    }
		}
		/* Quit when both questions answered */
		if ( attached && my_pid_slot )
		    break;
	    }

	    /* If no living pids attached, destroy/reallocate */
	    if ( !attached )
	    {
		CSv_semaphore(&lgk_mem->mem_ext_sem);
		if ( LGK_destroy(allocated_pages, sys_err) )
		{
		    ret_val = E_DMA802_LGKINIT_ERROR;
		    break;
		}
		continue;
	    }

	    /* All attached pids alive? */
	    if ( !my_pid_slot )
	    {
		/* ... then there's no room for this process */
		uleFormat(NULL, E_DMA80A_LGK_ATTACH_LIMIT, (CL_ERR_DESC *)NULL,
		    ULE_LOG, NULL, NULL, 0, NULL, &err_code, 1,
		    0, attached);
	        ret_val = E_DMA802_LGKINIT_ERROR;
	    }
	    else if (lgk_mem->mem_version_no != LGK_MEM_VERSION_CURRENT)
	    {
		uleFormat(NULL, E_DMA434_LGK_VERSION_MISMATCH, (CL_ERR_DESC *)NULL,
		    ULE_LOG, NULL, NULL, 0, NULL, &err_code, 2,
		    0, lgk_mem->mem_version_no, 0, LGK_MEM_VERSION_CURRENT);
		ret_val = E_DMA435_WRONG_LGKMEM_VERSION;
	    }
	    /*
	    ** Don't allow mixed connections of MT/non-MT processes.
	    ** Among other things, the mutexing mechanisms are 
	    ** incompatible!
	    */
	    else if ( (CS_is_mt() && (lgk_mem->mem_status & LGK_IS_MT) == 0) ||
		     (!CS_is_mt() &&  lgk_mem->mem_status & LGK_IS_MT) )
	    {
		uleFormat(NULL, E_DMA811_LGK_MT_MISMATCH, (CL_ERR_DESC *)NULL,
		    ULE_LOG, NULL, NULL, 0, NULL, &err_code, 2,
		    0, (lgk_mem->mem_status & LGK_IS_MT) ? "OS"
							 : "INTERNAL",
		    0, (CS_is_mt()) ? "OS"
				    : "INTERNAL");
		ret_val = E_DMA802_LGKINIT_ERROR;
	    }
	    else
	    {
		/*
		** CX memory (if any) will lie immediately past LGK header.
		*/
		pcxmem = (PTR)(lgk_mem + 1);
		pcxmem = (PTR)ME_ALIGN_MACRO(pcxmem, sizeof(ALIGN_RESTRICT));

		LGK_base.lgk_lkd_ptr = (char *)LGK_base.lgk_mem_ptr +
					lgk_mem->mem_lkd;
		LGK_base.lgk_lgd_ptr = (char *)LGK_base.lgk_mem_ptr +
					lgk_mem->mem_lgd;
		
		/* Stuff our pid in first vacant slot */
		*my_pid_slot = LGK_my_pid;
		STlcopy(lgk_info, lgk_mem->mem_info[i].info_txt, LGK_INFO_SIZE-1);
	    }

#if defined(VMS) || defined(UNIX)
	    /* set up pointers to reference the uuid mutex and last time
	     * variable */

	    if (!ID_uuid_sem_ptr)
           	ID_uuid_sem_ptr=&lgk_mem->id_uuid_sem;

	    if (!ID_uuid_last_time_ptr)
                ID_uuid_last_time_ptr=&lgk_mem->uuid_last_time;

	    if (!ID_uuid_last_cnt_ptr)
                ID_uuid_last_cnt_ptr=&lgk_mem->uuid_last_cnt;
#endif

	    CSv_semaphore(&lgk_mem->mem_ext_sem);
	}
	else
	{

	    /* Memory did not exist */
	    /* Zero the version to keep other processes out */
	    lgk_mem->mem_version_no = 0;

#if defined(VMS) || defined(UNIX)
	    /* set up the uuid mutex and last time pointers to
	     * reference the objects in shared memory */

	    {
	        STATUS id_stat;

	        ID_uuid_sem_ptr=&lgk_mem->id_uuid_sem;
                ID_uuid_last_time_ptr=&lgk_mem->uuid_last_time;
                ID_uuid_last_cnt_ptr=&lgk_mem->uuid_last_cnt;
	        *ID_uuid_last_cnt_ptr=0;
	        ID_UUID_SEM_INIT(ID_uuid_sem_ptr,CS_SEM_MULTI,"uuid sem",
				&id_stat);
	    }
#endif

	    /* ... then initialize the mutex */
	    CSw_semaphore(&lgk_mem->mem_ext_sem, CS_SEM_MULTI,
	    			    "LGK mem ext sem" );

	    /* Record if memory created for MT or not */
	    if ( CS_is_mt() )
		lgk_mem->mem_status = LGK_IS_MT;

	    /*
	    ** memory is as follows:
	    **
	    **	-----------------------------------------------------------|
	    **	| LGK_MEM struct (keep track of this mem)	           |
	    **	|							   |
	    **	-----------------------------------------------------------|
	    **	| If a clustered installation memory reserved for CX       |
	    **	|							   |
	    **	------------------------------------------------------------
	    **	| LKD - database of info for lk system			   |
	    **	|							   |
	    **	------------------------------------------------------------
	    **	| LGD - database of info for lg system			   |
	    **	|							   |
	    **	------------------------------------------------------------
	    **	| memory manipulated by LGKm_* routines for structures used |
	    **	| by both the lk and lg systems.			   |
	    **	|							   |
	    **	------------------------------------------------------------
	    */

	    /* put the LGK_MEM struct at head of segment leaving ptr pointing 
	    ** at next aligned piece of memory
	    */

	    /*
	    ** CX memory (if any) will lie immediately past LGK header.
	    */
	    pcxmem = (PTR)(lgk_mem + 1);
	    pcxmem = (PTR)ME_ALIGN_MACRO(pcxmem, sizeof(ALIGN_RESTRICT));

	    LGK_base.lgk_lkd_ptr = pcxmem + cxmemreq;
	    LGK_base.lgk_lkd_ptr = (PTR) ME_ALIGN_MACRO(LGK_base.lgk_lkd_ptr,
						sizeof(ALIGN_RESTRICT));
	    lgk_mem->mem_lkd = (i4)((char *)LGK_base.lgk_lkd_ptr -
					 (char *)LGK_base.lgk_mem_ptr);

	    LGK_base.lgk_lgd_ptr = (PTR) ((char *) LGK_base.lgk_lkd_ptr +
					    sizeof(LKD));
	    LGK_base.lgk_lgd_ptr = (PTR) ME_ALIGN_MACRO(LGK_base.lgk_lgd_ptr,
						sizeof(ALIGN_RESTRICT));
	    lgk_mem->mem_lgd = (i4)((char *)LGK_base.lgk_lgd_ptr -
					 (char *)LGK_base.lgk_mem_ptr);

	    /* now initialize the rest of memory for allocation */

	    /* how much memory is left? */

	    ptr = ((char *)LGK_base.lgk_lgd_ptr + sizeof(LGD));
	    memleft = size - (((char *) ptr) - ((char *) LGK_base.lgk_mem_ptr));

	    if ( (ret_val = lgkm_initialize_mem(memleft, ptr)) == OK &&
		 (ret_val = LG_meminit(sys_err)) == OK &&
		 (ret_val = LK_meminit(sys_err)) == OK )
	    {
		/* Clear array of attached pids and pid info */
		for ( i = 0; i < LGK_MAX_PIDS; i++ )
		{
		    lgk_mem->mem_pid[i] = (PID)0;
		    lgk_mem->mem_info[i].info_txt[0] = EOS;
		}

		/* Set the creator pid */
		LGK_base.lgk_pid_slot = 0;
		lgk_mem->mem_creator_pid = LGK_my_pid;

		/* Set the version, releasing other processes */
		lgk_mem->mem_version_no = LGK_MEM_VERSION_CURRENT;
	    }
	    else
	    {
		uleFormat(NULL, ret_val, (CL_ERR_DESC *)NULL,
			    ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0);
		ret_val = E_DMA802_LGKINIT_ERROR;

		/* Destroy the shared memory */
		LGK_destroy(allocated_pages, sys_err);
	    }
	}

	if ( ret_val == OK )
	{
	    PCatexit(LGK_rundown);

	    if ( clustered )
	    {
		/*
		** Perform preliminary cluster connection and CX memory init.
		*/

		/* Get installation code */
		NMgtAt("II_INSTALLATION", &nm_string);
		if ( nm_string )
		{
		    instid[0] = *(nm_string);
		    instid[1] = *(nm_string+1);
		}
		else
		{
		    instid[0] = 'A';
		    instid[1] = 'A';
		}
		instid[2] = '\0';
		ret_val = CXinitialize( instid, pcxmem, flag & LGK_IS_CSP );
		if ( ret_val )
		{
		    /* Report error returned from CX */
		    uleFormat(NULL, ret_val, (CL_ERR_DESC *)NULL,
			ULE_LOG, NULL, NULL, 0, NULL, &err_code, 0 );
		    break;
		}
	    }

#ifdef VMS
	    {
	    static $EXHDEF	    exit_block;
	    i4			ctrl_y_mask = 0x02000000;

	    /*
	    ** On VMS, programs like the dmfjsp and logstat run as images in
	    ** the shell process. That is, the system doesn't start and stop
	    ** a process for each invocation of the program, it just starts
	    ** and stops an image in the same process. This means that if
	    ** the program should die, the image may be rundown but the process
	    ** will remain, which means that the check-dead threads of other
	    ** processes in the installation will not feel that they need to
	    ** rundown this process, since it's still alive.
	    **
	    ** By declaring an exit handler, which will get a chance to run
	    ** even if PCexit isn't called, we improve our chances of getting
	    ** to perform rundown processing if we should die unexpectedly.
	    **
	    ** Furthermore, we ask DCL to disable its ^Y processing, which
	    ** lessens the chance that the user will interrupt us while we
	    ** are holding the semaphore.
	    */
	    exit_block.exh$g_func = LGK_rundown;
	    exit_block.exh$l_argcount = 1;
	    exit_block.exh$gl_value = &exit_block.exh$l_status;

	    if (sys$dclexh(&exit_block) != SS$_NORMAL)
		ret_val = FAIL;

	    lib$disable_ctrl(&ctrl_y_mask, 0);
	    }
#endif
	}
	break;
    }

    if ( ret_val )
	LGK_base.lgk_mem_ptr = NULL;

    return(ret_val);
}
Example #6
0
void IIodbc_timeOutThread()
{
    QUEUE *q, *p, *pq;
    pENV penv;
    pDBC pdbc;
    RETCODE rc;
    SYSTIME expire_time;
    TM_STAMP stamp;
    char stampStr[TM_SIZE_STAMP];

    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
        ("IIodbc_timeOutThread() with timeout %d\n", IIodbc_cb.timeout);
    while(TRUE)
    {
        /*
        ** Search the pool every thirty seconds and check for expired
        ** connections.  Force disconnect and free from the pool
        ** if the connection handle has passed the expiration time.  
        ** Note that the CLI and driver connection handles are not
        ** freed.  
        */
        PCsleep(30000);
        TMget_stamp(&stamp);
        TMstamp_str(&stamp, stampStr);
        ODBC_EXEC_TRACE(ODBC_EX_TRACE)
            ("IIodbc_timeOutThread woke up at %s\n", stampStr);
        TMnow(&expire_time);
        
        if (IIodbc_cb.pooling == DRIVER_POOL)
        {
            applyLock(SQL_HANDLE_IIODBC_CB, NULL);
            for (q = IIodbc_cb.pool_q.q_prev; q!= &IIodbc_cb.pool_q;
                q = p)
            {
                ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                    ("IIodbc_timeOutThread: driver pool count is %d\n", 
                    IIodbc_cb.pool_count);
                p = q->q_prev;
                pdbc = (pDBC)((pPOOL)q)->pdbc;
                ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                    ("IIodbc_timeOutThread: found conn handle %p with time diff %d\n",pdbc,
                    expire_time.TM_secs - pdbc->expire_time.TM_secs);
                if (expire_time.TM_secs - pdbc->expire_time.TM_secs > 
                    IIodbc_cb.timeout)
                {
                    /*
                    **  Note that the connection handle is not freed, only
                    **  removed from the pool. 
                    */
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("IIodbc_timeOutThread: EXPIRED.  pdbc time is %d vs %d\n",
                        pdbc->expire_time.TM_secs, expire_time.TM_secs);
                    rc = IIDisconnect(pdbc->hdr.driverHandle);
                    QUremove(q);
                    MEfree((PTR)q);
                    IIodbc_cb.pool_count -= 1;
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("new pool count is %d\n",IIodbc_cb.pool_count);
                    applyLock(SQL_HANDLE_DBC, pdbc);
                    pdbc->hdr.state = C2;
                    releaseLock(SQL_HANDLE_DBC, pdbc);
                }
            }
            releaseLock(SQL_HANDLE_IIODBC_CB, NULL);
        }
        else
        {
            for (q = IIodbc_cb.env_q.q_prev; q!= &IIodbc_cb.env_q;
                q = q->q_prev)
            {
                penv = (pENV)q;
                TRdisplay("Found env handle %p\n",penv);
                applyLock(SQL_HANDLE_ENV, penv);
                for (pq = penv->pool_q.q_prev; pq != &penv->pool_q;
                    pq = p)
                {
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("Env pool count is %d\n",penv->pool_count);
                    p = q->q_prev;
                    pdbc = (pDBC)((pPOOL)pq)->pdbc;
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("IIodbc_TimeOutThread: Found conn handle %p with time diff %d\n",pdbc,
                        expire_time.TM_secs - pdbc->expire_time.TM_secs);
                    if (expire_time.TM_secs - pdbc->expire_time.TM_secs
                        > 1)
                    {
                        ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                            ("IIodbc_timeOutThread: EXPIRED.  pdbc time is %d vs %d\n",
                            pdbc->expire_time.TM_secs,   
                            expire_time.TM_secs);
                        rc = IIDisconnect(pdbc->hdr.driverHandle);
                        QUremove(q);
                        MEfree((PTR)q);
                        penv->pool_count -= 1;
                        ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                            ("IIodbc_timeOutThread: new pool count is %d\n",
                            penv->pool_count);
                    }
                }
                releaseLock(SQL_HANDLE_ENV, penv);
            } /* for (q = IIodbc_cb.env_q.q_prev; q!= &IIodbc_cb.env_q;
                q = q->q_prev) */
        } /* if (IIodbc_cb.pooling == DRIVER_POOL) */
    } /* while (TRUE) */
}
Example #7
0
/* IIReadfile --- reads data from specified channel
** Inputs:
**	asipc		ASSOC_IPC for connection.
**	hChan		Handle to channel from which to read.
**	nNumberToRead	number of bytes to read.
**	lpNUmberRead	number of bytes actually read.
**	LPOVERLAPPED	for compatiblity with win32 ReadFile.
**	timeout		timeout.
**			
** IIReadfile attempts to read from the pipe. It returns OK if the read succeeds
** ~OK if it fails, or GC_TIME_OUT if it times out.
**
** IIReadfile and IIWritefile must maintain a count of how many bytes are in
** the channel in order to implement the timeout functionality because anonymous
** pipes don't provide a wait function like named pipes. Database events 
** require the timeout functionality.
**
** History:
**      04-Sep-97 (fanra01)
**          Add return of OS error if read 0 bytes.
**      10-Dec-98 (lunbr01) Bug 94183
**          Use PeekNamedPipe rather than shared memory counter (*ct) to check
**          if data is avail to read (for RECEIVES with a non-INFINITE
**          timeout parm only). The shared memory counter was occasionally
**          getting corrupted because IIReadFile and IIWriteFile would update
**          it at the same time; InterlockedExchange was not sufficient...
**          a mutex was needed before the current value of *ct is "gotten"
**          for the increment/decrement.  The result was that IIReadFile
**          would "think" that there was something to read but there wasn't;
**          he would then issue the blocked read and wait forever or until
**          a dbevent happened to come in. The symptom was an application hang.
**          Rather than adding mutexes, PeekNamedPipe was used and the 
**          shared memory counters eliminated.
*/
ULONG	
IIReadFile( ASSOC_IPC *asipc,
	    HANDLE hChan, 
	    LPVOID lpBuffer, 
	    DWORD nNumberToRead, 
	    LPDWORD lpNumberRead, 
	    LPOVERLAPPED lpOverlapped, 
	    DWORD timeout )
{
	DWORD ct = 0;   
	int i = 0;
	int intervals = 0;
	BOOL rval = FALSE;
	BOOL tout = TRUE;
        DWORD dwError = 0;

	timeout = timeout == GC_WAIT_FOREVER ? INFINITE : timeout; 

	*lpNumberRead = 0;
	
	if ( timeout != INFINITE )
	{
	    rval = PeekNamedPipe(hChan, NULL, 0, NULL, &ct, NULL);
	    if ( rval != TRUE )
	    {
	        dwError = GetLastError();
		return rval ? OK : dwError;
	    }
	    if ( ct == 0 )
	    {
		if ( timeout == 0 )
			return GC_TIME_OUT;
		
		intervals = timeout == INFINITE ? 1:timeout/IPC_TIMEOUT_SLEEP ;	
			
		for( i = 0; i < intervals ; i++ )
		{
			PCsleep ( IPC_TIMEOUT_SLEEP );
	    		rval = PeekNamedPipe(hChan, NULL, 0, NULL, &ct, NULL);
	    		if ( rval != TRUE )
	    		{
	       			dwError = GetLastError();
				return rval ? OK : dwError;
	    		}
			if ( ct != 0 )
			{
				tout = FALSE;
				break;
			}
		}
		if ( tout )
			return GC_TIME_OUT;
			
	    } /* end if ct (bytes in read pipe) == 0 */
	}
	rval = ReadFile( hChan, lpBuffer, nNumberToRead, 
			 	lpNumberRead, lpOverlapped );
        dwError = GetLastError();
        if (rval)
        {               /* did successful data retrieval */  
            if (asipc)
            {
                /* set bPipesClosed to false - may have been set to TRUE 
                ** by the 'Server'.
	        */
                if (asipc->IpcInternal.AssocInfo)
                    asipc->IpcInternal.AssocInfo->bPipesClosed = FALSE;
            }
        }               /* did successful data retrieval */
	if( rval && 
	    (!asipc || !asipc->IpcInternal.AssocInfo ||
	    asipc->IpcInternal.AssocInfo->bPipesClosed) ) 
	{
		return ERROR_BROKEN_PIPE;
	}
	return rval ? OK : dwError;
	
}