fis-gtm/sr_unix/gtm_env_init_sp.c

354 lines
13 KiB
C

/****************************************************************
* *
* Copyright 2004, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#ifdef __MVS__
#include <env.h>
#endif
#include <errno.h>
#include <sys/sem.h>
#include "gtm_string.h"
#include "gtm_strings.h"
#include "gtm_ctype.h"
#include "gtm_unistd.h"
#include "gtm_stdio.h"
#include "gtm_stdlib.h"
#include "gtmimagename.h"
#include "gtm_logicals.h"
#include "trans_numeric.h"
#include "trans_log_name.h"
#include "logical_truth_value.h"
#include "iosp.h" /* for SS_ */
#include "nametabtyp.h" /* for namelook */
#include "namelook.h"
#include "io.h"
#include "iottdef.h"
#include "gtm_env_init.h" /* for gtm_env_init() and gtm_env_init_sp() prototype */
#include "gtm_utf8.h" /* UTF8_NAME */
#include "gtm_zlib.h"
#include "error.h"
#include "gtm_limits.h"
#include "compiler.h"
#include "gdsroot.h"
#include "gdsbt.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "jnl.h"
#include "replgbl.h"
#include "gtm_semutils.h"
#ifdef __linux__
#include "hugetlbfs_overrides.h"
#endif
#define DEFAULT_NON_BLOCKED_WRITE_RETRIES 10 /* default number of retries */
#ifdef __MVS__
# define PUTENV_BPXK_MDUMP_PREFIX "_BPXK_MDUMP="
#endif
#ifdef DEBUG
/* Note the var below is NOT located in gtm_logicals because it is DEBUG-only which would screw-up
* regresion test v53003/D9I10002703.
*/
# define GTM_USESECSHR "$gtm_usesecshr"
/* GTM_TEST_FAKE_ENOSPC is used only in debug code so it does not have to go in gtm_logicals.h */
# define GTM_TEST_FAKE_ENOSPC "$gtm_test_fake_enospc"
#endif
#define DEFAULT_MUPIP_TRIGGER_ETRAP "IF $ZJOBEXAM()"
/* Only for this function, define MAX_TRANS_NAME_LEN to be equal to GTM_PATH_MAX as some of the environment variables can indicate
* path to files which is limited by GTM_PATH_MAX.
*/
#ifdef MAX_TRANS_NAME_LEN
#undef MAX_TRANS_NAME_LEN
#endif
#define MAX_TRANS_NAME_LEN GTM_PATH_MAX
GBLREF int4 gtm_shmflags; /* Shared memory flags for shmat() */
GBLREF uint4 gtm_principal_editing_defaults; /* ext_cap flags if tt */
GBLREF boolean_t is_gtm_chset_utf8;
GBLREF boolean_t utf8_patnumeric;
GBLREF boolean_t badchar_inhibit;
GBLREF boolean_t gtm_quiet_halt;
GBLREF int gtm_non_blocked_write_retries; /* number for retries for non_blocked write to pipe */
GBLREF char *gtm_core_file;
GBLREF char *gtm_core_putenv;
GBLREF mval dollar_etrap;
GBLREF mval dollar_ztrap;
ZOS_ONLY(GBLREF char *gtm_utf8_locale_object;)
ZOS_ONLY(GBLREF boolean_t gtm_tag_utf8_as_ascii;)
GTMTRIG_ONLY(GBLREF mval gtm_trigger_etrap;)
#ifdef GTM_TRIGGER
LITDEF mval default_mupip_trigger_etrap = DEFINE_MVAL_LITERAL(MV_STR, 0 , 0 , (SIZEOF(DEFAULT_MUPIP_TRIGGER_ETRAP) - 1),
DEFAULT_MUPIP_TRIGGER_ETRAP , 0 , 0 );
#endif
static readonly nametabent editing_params[] =
{
{7, "EDITING"},
{7, "EMPTERM"},
{6, "INSERT"},
{9, "NOEDITING"},
{9, "NOEMPTERM"},
{8, "NOINSERT"}
};
static readonly unsigned char editing_index[27] =
{
0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 3,
3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6
};
static readonly unsigned char init_break[1] = {'B'};
void gtm_env_init_sp(void)
{ /* Unix only environment initializations */
mstr val, trans;
int4 status, index, len, hrtbt_cntr_delta;
size_t cwdlen;
boolean_t ret, is_defined;
char buf[MAX_TRANS_NAME_LEN], *token, cwd[GTM_PATH_MAX];
char *cwdptr, *trigger_etrap;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
# ifdef HUGETLB_SUPPORTED
libhugetlbfs_init();
# endif
# ifdef __MVS__
/* For now OS/390 only. Eventually, this will be added to all UNIX platforms along with the
* capability to specify the desired directory to put a core file in.
*/
if (NULL == gtm_core_file)
{
token = getcwd(cwd, SIZEOF(cwd));
if (NULL != token)
{
cwdlen = strlen(cwd);
gtm_core_putenv = malloc(cwdlen + ('/' == cwd[cwdlen - 1] ? 0 : 1) + SIZEOF(GTMCORENAME)
+ strlen(PUTENV_BPXK_MDUMP_PREFIX));
MEMCPY_LIT(gtm_core_putenv, PUTENV_BPXK_MDUMP_PREFIX);
gtm_core_file = cwdptr = gtm_core_putenv + strlen(PUTENV_BPXK_MDUMP_PREFIX);
memcpy(cwdptr, &cwd, cwdlen);
cwdptr += cwdlen;
if ('/' != cwd[cwdlen - 1])
*cwdptr++ = '/';
memcpy(cwdptr, GTMCORENAME, SIZEOF(GTMCORENAME)); /* Also copys in trailing null */
} /* else gtm_core_file/gtm_core_putenv remain null and we likely cannot generate proper core files */
}
# endif
val.addr = GTM_SHMFLAGS;
val.len = SIZEOF(GTM_SHMFLAGS) - 1;
gtm_shmflags = (int4)trans_numeric(&val, &is_defined, TRUE); /* Flags vlaue (0 is undefined or bad) */
val.addr = GTM_QUIET_HALT;
val.len = SIZEOF(GTM_QUIET_HALT) - 1;
ret = logical_truth_value(&val, FALSE, &is_defined);
if (is_defined)
gtm_quiet_halt = ret;
/* Initialize local variable null subscripts allowed flag */
val.addr = GTM_LVNULLSUBS;
val.len = SIZEOF(GTM_LVNULLSUBS) - 1;
ret = trans_numeric(&val, &is_defined, TRUE); /* Not initialized enuf for errors yet so silent rejection of invalid vals */
TREF(lv_null_subs) = ((is_defined && (LVNULLSUBS_FIRST < ret) && (LVNULLSUBS_LAST > ret)) ? ret : LVNULLSUBS_OK);
# ifdef GTM_TRIGGER
token = GTM_TRIGGER_ETRAP;
trigger_etrap = GETENV(++token); /* Point past the $ in gtm_logicals definition */
if (trigger_etrap)
{
len = STRLEN(trigger_etrap);
gtm_trigger_etrap.str.len = len;
gtm_trigger_etrap.str.addr = malloc(len); /* Allocates special null addr if length is 0 which we can key on */
if (0 < len)
memcpy(gtm_trigger_etrap.str.addr, trigger_etrap, len);
gtm_trigger_etrap.mvtype = MV_STR;
} else if (IS_MUPIP_IMAGE)
gtm_trigger_etrap = default_mupip_trigger_etrap;
# endif
/* ZLIB library compression level */
val.addr = GTM_ZLIB_CMP_LEVEL;
val.len = SIZEOF(GTM_ZLIB_CMP_LEVEL) - 1;
gtm_zlib_cmp_level = trans_numeric(&val, &is_defined, TRUE);
if (GTM_CMPLVL_OUT_OF_RANGE(gtm_zlib_cmp_level))
gtm_zlib_cmp_level = ZLIB_CMPLVL_MIN; /* no compression in this case */
gtm_principal_editing_defaults = 0;
val.addr = GTM_PRINCIPAL_EDITING;
val.len = SIZEOF(GTM_PRINCIPAL_EDITING) - 1;
if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long)))
{
assert(trans.len < SIZEOF(buf));
trans.addr[trans.len] = '\0';
token = strtok(trans.addr, ":");
while (NULL != token)
{
if (ISALPHA_ASCII(token[0]))
index = namelook(editing_index, editing_params, STR_AND_LEN(token));
else
index = -1; /* ignore this token */
if (0 <= index)
{
switch (index)
{
case 0: /* EDITING */
gtm_principal_editing_defaults |= TT_EDITING;
break;
case 1: /* EMPTERM */
gtm_principal_editing_defaults |= TT_EMPTERM;
break;
case 2: /* INSERT */
gtm_principal_editing_defaults &= ~TT_NOINSERT;
break;
case 3: /* NOEDITING */
gtm_principal_editing_defaults &= ~TT_EDITING;
break;
case 4: /* NOEMPTERM */
gtm_principal_editing_defaults &= ~TT_EMPTERM;
break;
case 5: /* NOINSERT */
gtm_principal_editing_defaults |= TT_NOINSERT;
break;
}
}
token = strtok(NULL, ":");
}
}
val.addr = GTM_CHSET_ENV;
val.len = STR_LIT_LEN(GTM_CHSET_ENV);
if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long))
&& STR_LIT_LEN(UTF8_NAME) == trans.len)
{
if (!strncasecmp(buf, UTF8_NAME, STR_LIT_LEN(UTF8_NAME)))
{
is_gtm_chset_utf8 = TRUE;
# ifdef __MVS__
val.addr = GTM_CHSET_LOCALE_ENV;
val.len = STR_LIT_LEN(GTM_CHSET_LOCALE_ENV);
if ((SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long))) &&
(0 < trans.len))
{ /* full path to 64 bit ASCII UTF-8 locale object */
gtm_utf8_locale_object = malloc(trans.len + 1);
strcpy(gtm_utf8_locale_object, buf);
}
val.addr = GTM_TAG_UTF8_AS_ASCII;
val.len = STR_LIT_LEN(GTM_TAG_UTF8_AS_ASCII);
if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long)))
{ /* We to tag UTF8 files as ASCII so we can read them, this var disables that */
if (status = logical_truth_value(&val, FALSE, &is_defined) && is_defined)
gtm_tag_utf8_as_ascii = FALSE;
}
# endif
/* Initialize $ZPATNUMERIC only if $ZCHSET is "UTF-8" */
val.addr = GTM_PATNUMERIC_ENV;
val.len = STR_LIT_LEN(GTM_PATNUMERIC_ENV);
if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long))
&& STR_LIT_LEN(UTF8_NAME) == trans.len
&& !strncasecmp(buf, UTF8_NAME, STR_LIT_LEN(UTF8_NAME)))
{
utf8_patnumeric = TRUE;
}
val.addr = GTM_BADCHAR_ENV;
val.len = STR_LIT_LEN(GTM_BADCHAR_ENV);
status = logical_truth_value(&val, TRUE, &is_defined);
if (is_defined)
badchar_inhibit = status ? TRUE : FALSE;
}
}
/* Initialize variable that controls number of retries for non-blocked writes to a pipe on unix */
val.addr = GTM_NON_BLOCKED_WRITE_RETRIES;
val.len = SIZEOF(GTM_NON_BLOCKED_WRITE_RETRIES) - 1;
gtm_non_blocked_write_retries = trans_numeric(&val, &is_defined, TRUE);
if (!is_defined)
gtm_non_blocked_write_retries = DEFAULT_NON_BLOCKED_WRITE_RETRIES;
/* Initialize variable that controls the behavior on journal error */
val.addr = GTM_ERROR_ON_JNL_FILE_LOST;
val.len = SIZEOF(GTM_ERROR_ON_JNL_FILE_LOST) - 1;
TREF(error_on_jnl_file_lost) = trans_numeric(&val, &is_defined, FALSE);
if (MAX_JNL_FILE_LOST_OPT < TREF(error_on_jnl_file_lost))
TREF(error_on_jnl_file_lost) = JNL_FILE_LOST_TURN_OFF; /* default behavior */
/* Initialize variable that controls jnl release timeout */
val.addr = GTM_JNL_RELEASE_TIMEOUT;
val.len = SIZEOF(GTM_JNL_RELEASE_TIMEOUT) - 1;
(TREF(replgbl)).jnl_release_timeout = trans_numeric(&val, &is_defined, TRUE);
if (!is_defined)
(TREF(replgbl)).jnl_release_timeout = DEFAULT_JNL_RELEASE_TIMEOUT;
else if (0 > (TREF(replgbl)).jnl_release_timeout) /* consider negative timeout value as zero */
(TREF(replgbl)).jnl_release_timeout = 0;
else if (MAXPOSINT4 / MILLISECS_IN_SEC < (TREF(replgbl)).jnl_release_timeout) /* max value supported for timers */
(TREF(replgbl)).jnl_release_timeout = MAXPOSINT4 / MILLISECS_IN_SEC;
/* Initialize variable that controls the maximum time that a process should spend while waiting for semaphores in db_init */
val.addr = GTM_DB_STARTUP_MAX_WAIT;
val.len = SIZEOF(GTM_DB_STARTUP_MAX_WAIT) - 1;
hrtbt_cntr_delta = trans_numeric(&val, &is_defined, FALSE);
if (!is_defined)
TREF(dbinit_max_hrtbt_delta) = DEFAULT_DBINIT_MAX_HRTBT_DELTA;
else if ((INDEFINITE_WAIT_ON_EAGAIN != hrtbt_cntr_delta) && (NO_SEMWAIT_ON_EAGAIN != hrtbt_cntr_delta))
TREF(dbinit_max_hrtbt_delta) = (ROUND_UP2(hrtbt_cntr_delta, 8)) / 8;
else
TREF(dbinit_max_hrtbt_delta) = hrtbt_cntr_delta;
/* Initialize variable that controls the location of GT.M custom errors file (used for anticipatory freeze) */
val.addr = GTM_CUSTOM_ERRORS;
val.len = SIZEOF(GTM_CUSTOM_ERRORS) - 1;
if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long)))
{
assert(GTM_PATH_MAX > trans.len);
(TREF(gtm_custom_errors)).addr = malloc(trans.len + 1); /* +1 for '\0'; This memory is never freed */
(TREF(gtm_custom_errors)).len = trans.len;
/* For now, we assume that if the environment variable is defined to NULL, anticipatory freeze is NOT in effect */
if (0 < trans.len)
{
memcpy((TREF(gtm_custom_errors)).addr, buf, trans.len);
((TREF(gtm_custom_errors)).addr)[trans.len] = '\0';
}
}
/* Initialize which ever error trap we are using (ignored in the utilities except the update process) */
val.addr = GTM_ETRAP;
val.len = SIZEOF(GTM_ETRAP) - 1;
if (SS_NORMAL == (status = TRANS_LOG_NAME(&val, &trans, buf, SIZEOF(buf), do_sendmsg_on_log2long)))
{
if (MAX_SRCLINE >= trans.len)
{ /* Only set $ETRAP if the length is usable (may be NULL) */
dollar_etrap.str.addr = malloc(trans.len + 1); /* +1 for '\0'; This memory is never freed */
memcpy(dollar_etrap.str.addr, trans.addr, trans.len);
*(dollar_etrap.str.addr + trans.len + 1) = '\0';
dollar_etrap.str.len = trans.len;
dollar_etrap.mvtype = MV_STR;
}
} else if (0 == dollar_etrap.mvtype)
{ /* If didn't setup $ETRAP, set default $ZTRAP instead */
dollar_ztrap.mvtype = MV_STR;
dollar_ztrap.str.len = SIZEOF(init_break);
dollar_ztrap.str.addr = (char *)init_break;
}
# ifdef DEBUG
/* DEBUG-only option to bypass 'easy' methods of things and always use gtmsecshr for IPC cleanups, wakeups, file removal,
* etc. Basically use gtmsecshr for anything where it is an option - helps with testing gtmsecshr for proper operation.
*/
val.addr = GTM_USESECSHR;
val.len = SIZEOF(GTM_USESECSHR) - 1;
TREF(gtm_usesecshr) = logical_truth_value(&val, FALSE, &is_defined);
if (!is_defined)
TREF(gtm_usesecshr) = FALSE;
/* DEBUG-only option to enable/disable anticipatory freeze fake ENOSPC testing */
val.addr = GTM_TEST_FAKE_ENOSPC;
val.len = SIZEOF(GTM_TEST_FAKE_ENOSPC) - 1;
TREF(gtm_test_fake_enospc) = logical_truth_value(&val, FALSE, &is_defined);
if (!is_defined)
TREF(gtm_test_fake_enospc) = FALSE;
# endif
# ifdef GTMDBGFLAGS_ENABLED
val.addr = GTMDBGFLAGS;
val.len = SIZEOF(GTMDBGFLAGS) - 1;
TREF(gtmdbgflags) = trans_numeric(&val, &is_defined, TRUE);
val.addr = GTMDBGFLAGS_FREQ;
val.len = SIZEOF(GTMDBGFLAGS_FREQ) - 1;
TREF(gtmdbgflags_freq) = trans_numeric(&val, &is_defined, TRUE);
# endif
}