894 lines
26 KiB
C
894 lines
26 KiB
C
/****************************************************************
|
||
* *
|
||
* Copyright 2001, 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"
|
||
|
||
#include "gtm_string.h"
|
||
|
||
#include <stdarg.h>
|
||
#include "gtm_stdio.h"
|
||
#include "gtm_syslog.h"
|
||
#include <errno.h>
|
||
|
||
#include "io.h"
|
||
#include "error.h"
|
||
#include "fao_parm.h"
|
||
#include "min_max.h"
|
||
#include "hashtab_mname.h"
|
||
#include "util.h"
|
||
#include "util_format.h"
|
||
#include "util_out_print_vaparm.h"
|
||
#include "gtmimagename.h"
|
||
|
||
#include "gdsroot.h"
|
||
#include "gtm_facility.h"
|
||
#include "fileinfo.h"
|
||
#include "gdsbt.h"
|
||
#include "gdsfhead.h"
|
||
#include "filestruct.h"
|
||
#include "repl_msg.h"
|
||
#include "repl_shutdcode.h"
|
||
#include "gtmsource.h"
|
||
#include "gtmrecv.h"
|
||
#include "repl_instance.h"
|
||
#include "trans_log_name.h"
|
||
#include "gtmio.h"
|
||
#include "gtm_logicals.h"
|
||
#include "have_crit.h"
|
||
|
||
#ifdef UNICODE_SUPPORTED
|
||
#include "gtm_icu_api.h"
|
||
#include "gtm_utf8.h"
|
||
#endif
|
||
|
||
GBLDEF boolean_t first_syslog = TRUE; /* Global for a process - not thread specific */
|
||
GBLDEF char facility[MAX_INSTNAME_LEN + 100];
|
||
|
||
GBLREF io_pair io_std_device;
|
||
GBLREF boolean_t blocksig_initialized;
|
||
GBLREF sigset_t block_sigsent;
|
||
GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
|
||
GBLREF jnlpool_addrs jnlpool;
|
||
GBLREF boolean_t is_src_server;
|
||
GBLREF boolean_t is_rcvr_server;
|
||
GBLREF boolean_t is_updproc;
|
||
GBLREF boolean_t is_updhelper;
|
||
GBLREF recvpool_addrs recvpool;
|
||
GBLREF uint4 process_id;
|
||
GBLREF void (*op_write_ptr)(mval *v);
|
||
GBLREF void (*op_wteol_ptr)(int4 n);
|
||
|
||
error_def(ERR_REPLINSTACC);
|
||
error_def(ERR_TEXT);
|
||
|
||
#define GETFAOVALDEF(faocnt, var, type, result, defval) \
|
||
if (faocnt > 0) {result = (type)va_arg(var, type); faocnt--;} else result = defval;
|
||
|
||
#define INSERT_MARKER \
|
||
{ \
|
||
STRNCPY_STR(offset, "-", STRLEN("-")); \
|
||
offset += STRLEN("-"); \
|
||
}
|
||
|
||
#define BUILD_FACILITY(strptr) \
|
||
{ \
|
||
STRNCPY_STR(offset, strptr, STRLEN(strptr)); \
|
||
offset += STRLEN(strptr); \
|
||
INSERT_MARKER; \
|
||
}
|
||
|
||
/*
|
||
* This routine implements a SUBSET of FAO directives, namely:
|
||
*
|
||
* !/ !_ !^ !!
|
||
*
|
||
|
||
* !mAC !mAD !mAF !mAS !mAZ
|
||
*
|
||
* !mSB !mSW !mSL
|
||
*
|
||
* !mUB !mUW !mUL !m@UJ !m@UQ
|
||
*
|
||
* !mXB !mXW !mXL !mXJ !m@XJ !m@XQ
|
||
*
|
||
* !mZB !mZW !mZL
|
||
*
|
||
* !n*c
|
||
*
|
||
* !@ZJ !@XJ !@ZJ !@ZQ
|
||
#
|
||
* Where `m' is an optional field width, `n' is a repeat count, and `c' is a single character.
|
||
* `m' or `n' may be specified as the '#' character, in which case the value is taken from the next parameter.
|
||
*
|
||
* FAO stands for "formatted ASCII output". The FAO directives may be considered equivalent to format
|
||
* specifications and are documented with the VMS Lexical Fuction F$FAO in the OpenVMS DCL Dictionary.
|
||
*
|
||
* The @XH and @XJ types need special mention. XH and XJ are ascii formatting of addresses and integers respectively. BOTH are
|
||
* ASCII formatted hexdecimal output of a 64 bit sign-extended value. The present implementation of util_output does not
|
||
* support 'H'. This support was new in VMS 7.2 (and is one reason why GTM 4.2 requires VMS 7.2). The "@" designates an
|
||
* "indirect" request meaning that the address of the 8 byte item is passed rather than the item itself. This is what allows
|
||
* us to print 8 byte values in the non-Alpha 32 bit parameter worlds. These types are documented in the VMS System services
|
||
* manual under SYS$FAO. There are several other types that are supported on VMS but only these two were added on Unix.
|
||
*
|
||
* Another variant of the 'J' type is !mXJ which the routine implements. This variant is used to print 'addresses' in platform
|
||
* independent way. For examples of this type, see the definition and usages of the following messages:
|
||
*
|
||
* CALLERID
|
||
* KILLBYSIGSINFO1
|
||
* KILLBYSIGSINFO2
|
||
*
|
||
* One important caveat in using !mXJ variant is that the input value is expected to be 4-byte on 32-bit platforms and 8-byte
|
||
* on 64-bit platforms. Passing an 8-byte quantity on a 32-bit platform can cause SIGSEGV. If a field is always 8-bytes on both
|
||
* the 32 and 64 bit platforms (like transaction numbers), use 0x!16@XQ variant instead.
|
||
*
|
||
* In addition, this routine also implements another set of directives
|
||
*
|
||
* !RmAC !RmAD !RmAF !RmAS !RmAZ
|
||
*
|
||
* This implements the !mAx equivalent but does right-justification of the string instead of left-justification.
|
||
*/
|
||
|
||
/*
|
||
* util_format - convert FAO format string to C PRINTF format string.
|
||
*
|
||
* input arguments:
|
||
* message - one of the message strings from, for example, merrors.c
|
||
* fao - list of values to be inserted into message according to
|
||
* the FAO directives
|
||
* size - size of buff
|
||
*
|
||
* output argument:
|
||
* buff - will contain C PRINTF-style format statement with any
|
||
* "A" (character) fields filled in from fao list
|
||
*
|
||
* output global value:
|
||
* outparm[] - array of numeric arguments from fao list (character
|
||
* arguments already incorporated into buff
|
||
*
|
||
*/
|
||
|
||
caddr_t util_format(caddr_t message, va_list fao, caddr_t buff, ssize_t size, int faocnt)
|
||
{
|
||
desc_struct *d;
|
||
signed char schar;
|
||
unsigned char type, type2;
|
||
caddr_t c, ctop, outptr, outtop, outtop1, message_next, message_top;
|
||
uchar_ptr_t ret_ptr;
|
||
unsigned char uchar;
|
||
short sshort, *s;
|
||
unsigned short ushort;
|
||
int i, nexti, length, field_width, repeat_count, int_val, chwidth, orig_chwidth, cwidth;
|
||
unsigned int ch;
|
||
UINTPTR_T addr_val;
|
||
ssize_t chlen;
|
||
boolean_t indirect;
|
||
qw_num_ptr_t val_ptr;
|
||
unsigned char numa[22];
|
||
unsigned char *numptr;
|
||
boolean_t right_justify, isprintable;
|
||
DCL_THREADGBL_ACCESS;
|
||
|
||
SETUP_THREADGBL_ACCESS;
|
||
VAR_COPY(TREF(last_va_list_ptr), fao);
|
||
outptr = buff;
|
||
outtop = outptr + size - 5; /* 5 bytes to prevent writing across border */
|
||
while (outptr < outtop)
|
||
{
|
||
/* Look for the '!' that starts an FAO directive */
|
||
while ((schar = *message++) != '!')
|
||
{
|
||
if (schar == '\0')
|
||
{
|
||
va_end(TREF(last_va_list_ptr)); /* reset before using as dest in copy */
|
||
VAR_COPY(TREF(last_va_list_ptr), fao);
|
||
return outptr;
|
||
}
|
||
*outptr++ = schar;
|
||
if (outptr >= outtop)
|
||
{
|
||
va_end(TREF(last_va_list_ptr)); /* reset before using as dest in copy */
|
||
VAR_COPY(TREF(last_va_list_ptr), fao);
|
||
return outptr;
|
||
}
|
||
}
|
||
field_width = 0; /* Default values */
|
||
repeat_count = 1;
|
||
right_justify = FALSE;
|
||
if ('R' == *message)
|
||
{
|
||
right_justify = TRUE;
|
||
++message;
|
||
}
|
||
/* Look for a field width (or repeat count) */
|
||
if (*message == '#')
|
||
{
|
||
if (0 < faocnt)
|
||
field_width = repeat_count = va_arg(fao, int4);
|
||
++message;
|
||
} else
|
||
{
|
||
for (c = message; *c >= '0' && *c <= '9'; ++c)
|
||
;
|
||
if ((length = (int)(c - message)) > 0)
|
||
{
|
||
field_width = repeat_count
|
||
= asc2i((uchar_ptr_t)message, length);
|
||
message = c;
|
||
}
|
||
}
|
||
if ('@' == *message) /* Indirectly addressed operand */
|
||
{
|
||
indirect = TRUE;
|
||
message++;
|
||
} else
|
||
indirect = FALSE;
|
||
switch (type = *message++)
|
||
{
|
||
case '/':
|
||
assert(!indirect);
|
||
*outptr++ = '\n';
|
||
continue;
|
||
case '_':
|
||
assert(!indirect);
|
||
*outptr++ = '\t';
|
||
continue;
|
||
case '^':
|
||
assert(!indirect);
|
||
*outptr++ = '\f';
|
||
continue;
|
||
case '!':
|
||
assert(!indirect);
|
||
*outptr++ = '!';
|
||
continue;
|
||
case '*':
|
||
assert(!indirect);
|
||
if (repeat_count > 0)
|
||
{
|
||
message_top = message + strlen(message);
|
||
assert(message < message_top);
|
||
chlen = (!gtm_utf8_mode) ? 1 :
|
||
((caddr_t)UTF8_MBNEXT(message, message_top) - message);
|
||
} else
|
||
chlen = 0;
|
||
while ((repeat_count-- > 0) && (outptr < outtop))
|
||
{
|
||
memcpy(outptr, message, chlen);
|
||
outptr += chlen;
|
||
}
|
||
message += chlen;
|
||
continue;
|
||
case 'A':
|
||
assert(!indirect);
|
||
switch(type2 = *message++)
|
||
{
|
||
case 'C': /* a string with length in the first byte */
|
||
GETFAOVALDEF(faocnt, fao, caddr_t, c, NULL);
|
||
length = c ? *c++ : 0;
|
||
break;
|
||
case 'D':
|
||
case 'F': /* string with length and addr parameters */
|
||
GETFAOVALDEF(faocnt, fao, int4, length, 0);
|
||
GETFAOVALDEF(faocnt, fao, caddr_t, c, NULL);
|
||
break;
|
||
case 'S':
|
||
if (faocnt)
|
||
{
|
||
d = (desc_struct *)va_arg(fao, caddr_t);
|
||
faocnt--;
|
||
c = d->addr;
|
||
length = d->len;
|
||
} else
|
||
{
|
||
c = NULL;
|
||
length = 0;
|
||
}
|
||
break;
|
||
case 'Z': /* null teminated string */
|
||
GETFAOVALDEF(faocnt, fao, caddr_t, c, NULL);
|
||
length = c ? STRLEN(c) : 0;
|
||
}
|
||
/* Since gtmsecshr does not load ICU libraries (since dlopen() with LD_LIBRARY_PATH
|
||
* does not work for root setuid executables), avoid calling gtm_wcswidth() and
|
||
* U_ISPRINT() from gtmsecshr and thus non-zero widths used in util_out_print()
|
||
* from gtmsecshr will not be treated as column widths but as character lengths.
|
||
* This is a safe limitation since no message from gtmsecshr specifies width yet.
|
||
*/
|
||
assert(!gtm_utf8_mode || IS_GTMSECSHR_IMAGE || (NULL != gtm_wcswidth_fnptr));
|
||
cwidth = (!gtm_utf8_mode || IS_GTMSECSHR_IMAGE)
|
||
? length : (*gtm_wcswidth_fnptr)((unsigned char *)c, length, FALSE, 1);
|
||
if (0 < field_width && cwidth > field_width)
|
||
cwidth = field_width;
|
||
assert(0 <= cwidth); /* since all unprintable and illegal characters are ignored */
|
||
assert(0 <= field_width);
|
||
outtop1 = outtop - 1;
|
||
if (right_justify)
|
||
{
|
||
for (i = field_width - cwidth; i > 0 && outptr < outtop1; --i)
|
||
*outptr++ = ' ';
|
||
}
|
||
if (!gtm_utf8_mode)
|
||
{
|
||
chwidth = 1; /* for both printable and unprintable characters */
|
||
chlen = 1;
|
||
}
|
||
for (i = 0, ctop = c + length; c < ctop; c += chlen)
|
||
{
|
||
if (!gtm_utf8_mode)
|
||
{
|
||
ch = *c;
|
||
isprintable = ((' ' <= ch) || ('~' >= ch)); /* Ignored in M mode for FAO !AD */
|
||
} else
|
||
{
|
||
chlen = (caddr_t)UTF8_MBTOWC(c, ctop, ch) - c;
|
||
if (!IS_GTMSECSHR_IMAGE)
|
||
{
|
||
chwidth = (int)UTF8_WCWIDTH(ch);
|
||
/* Note down chwidth (for debugging) from ICU before tampering with it */
|
||
DEBUG_ONLY(orig_chwidth = chwidth;)
|
||
if (-1 != chwidth)
|
||
isprintable = TRUE;
|
||
else
|
||
{
|
||
isprintable = U_ISSPACE(ch);
|
||
chwidth = 1; /* treat unprintable characters as having width=1 */
|
||
}
|
||
} else
|
||
{ /* Assume printability for GTMSECSHR */
|
||
chwidth = (int)chlen;
|
||
isprintable = TRUE;
|
||
}
|
||
}
|
||
assert('\0' != ch); /* we dont expect <null> bytes in the middle of the string */
|
||
assert((c + chlen) <= ctop);
|
||
assert(0 < chlen);
|
||
assert((0 < chwidth) || (0 == chwidth) && gtm_utf8_mode);
|
||
nexti = i + chwidth;
|
||
if (nexti > cwidth) /* adding next input char will cross requested width */
|
||
break;
|
||
if ((outptr + chlen) > outtop1) /* adding next input char will cross output buffer limit */
|
||
break;
|
||
if (!isprintable && (('F' == type2) UNICODE_ONLY(|| (('D' == type2) && gtm_utf8_mode))))
|
||
{ /* Since HPUX stops printing lines (via FPRINTF) when it
|
||
* encounters a bad character, all platforms in utf8 mode
|
||
* will behave as if !AF were specified and put a "." in place
|
||
* of non-printable characters. SE 01/2007
|
||
*/
|
||
*outptr++ = '.';
|
||
i = nexti;
|
||
} else if ('\0' != ch) /* skip NULL bytes in the middle of the string */
|
||
{
|
||
if (1 == chlen)
|
||
*outptr++ = *c;
|
||
else
|
||
{
|
||
memcpy(outptr, c, chlen);
|
||
outptr += chlen;
|
||
}
|
||
i = nexti;
|
||
}
|
||
}
|
||
/* Ensure we are still within limits */
|
||
assert(outptr <= outtop1);
|
||
assert(i <= cwidth);
|
||
assert(c <= ctop);
|
||
if (!right_justify)
|
||
{
|
||
for (i = field_width - i; i > 0 && outptr < outtop1; --i)
|
||
*outptr++ = ' ';
|
||
}
|
||
continue;
|
||
default: /* Rest of numeric types come here */
|
||
assert('S' == type || 'U' == type || 'X' == type || 'Z' == type);
|
||
numptr = numa;
|
||
type2 = *message++;
|
||
if (!indirect)
|
||
{
|
||
if ('S' == type)
|
||
switch(type2)
|
||
{
|
||
case 'B':
|
||
GETFAOVALDEF(faocnt, fao, int4, schar, 0);
|
||
int_val = schar;
|
||
break;
|
||
case 'W':
|
||
GETFAOVALDEF(faocnt, fao, int4, sshort, 0);
|
||
int_val = sshort;
|
||
break;
|
||
case 'L':
|
||
GETFAOVALDEF(faocnt, fao, int4, int_val, 0);
|
||
break;
|
||
case 'J':
|
||
GTM64_ONLY(
|
||
GETFAOVALDEF(faocnt, fao, UINTPTR_T, addr_val, 0);
|
||
)
|
||
NON_GTM64_ONLY(
|
||
GETFAOVALDEF(faocnt, fao, int4, int_val, 0);
|
||
)
|
||
break;
|
||
default:
|
||
assert(FALSE);
|
||
}
|
||
else
|
||
{
|
||
GTM64_ONLY(
|
||
if ('J' == type2)
|
||
{GETFAOVALDEF(faocnt, fao, UINTPTR_T, addr_val, 0);}
|
||
else
|
||
{GETFAOVALDEF(faocnt, fao, int4, int_val, 0);}
|
||
)
|
||
NON_GTM64_ONLY(GETFAOVALDEF(faocnt, fao, int4, int_val, 0);)
|
||
switch(type2)
|
||
{
|
||
case 'B':
|
||
int_val = int_val & 0xFF;
|
||
break;
|
||
case 'W':
|
||
int_val = int_val & 0xFFFF;
|
||
break;
|
||
case 'L':
|
||
int_val = int_val & 0xFFFFFFFF;
|
||
break;
|
||
case 'J':
|
||
NON_GTM64_ONLY(int_val = int_val & 0xFFFFFFFF;)
|
||
break;
|
||
default:
|
||
assert(FALSE);
|
||
}
|
||
}
|
||
switch (type)
|
||
{
|
||
case 'S': /* Signed value. Give sign if need to */
|
||
if ('J' == type2)
|
||
{
|
||
GTM64_ONLY(
|
||
if (0 > (INTPTR_T)addr_val)
|
||
{
|
||
*numptr++ = '-';
|
||
addr_val = -(addr_val);
|
||
}
|
||
)
|
||
NON_GTM64_ONLY(
|
||
if (0 > int_val)
|
||
{
|
||
*numptr++ = '-';
|
||
int_val = -(int_val);
|
||
}
|
||
)
|
||
} else if (0 > int_val)
|
||
{
|
||
*numptr++ = '-';
|
||
int_val = -(int_val);
|
||
} /* note fall into unsigned */
|
||
case 'U':
|
||
case 'Z': /* zero filled */
|
||
NON_GTM64_ONLY(numptr = i2asc(numptr, int_val);)
|
||
GTM64_ONLY(
|
||
if ('J' == type2)
|
||
numptr = i2ascl(numptr, addr_val);
|
||
else
|
||
numptr = i2asc(numptr, int_val);
|
||
)
|
||
break;
|
||
case 'X': /* Hex */
|
||
switch (type2)
|
||
{ /* length is number of ascii hex chars */
|
||
case 'B':
|
||
length = SIZEOF(short);
|
||
break;
|
||
case 'W':
|
||
length = SIZEOF(int4);
|
||
break;
|
||
case 'L':
|
||
length = 2 * SIZEOF(int4);
|
||
break;
|
||
case 'J':
|
||
length = 2 * SIZEOF(INTPTR_T);
|
||
break;
|
||
default:
|
||
assert(FALSE);
|
||
}
|
||
NON_GTM64_ONLY(i2hex(int_val, numptr, length);)
|
||
GTM64_ONLY(i2hex(('J' == type2) ? addr_val : int_val, numptr, length);)
|
||
|
||
numptr += length;
|
||
break;
|
||
default:
|
||
assert(FALSE);
|
||
}
|
||
} else
|
||
{
|
||
if ('X' == type) /* Support XJ and XQ */
|
||
{
|
||
assert('J' == type2 || 'Q' == type2);
|
||
GETFAOVALDEF(faocnt, fao, qw_num_ptr_t, val_ptr, NULL); /* Addr of long type */
|
||
if (val_ptr)
|
||
{
|
||
if (0 != field_width)
|
||
{
|
||
i2hexl(*val_ptr, numptr, field_width);
|
||
numptr += field_width;
|
||
} else
|
||
{
|
||
length = i2hexl_nofill(*val_ptr, numptr, HEX16);
|
||
numptr += length;
|
||
}
|
||
}
|
||
} else /* support ZJ, ZQ, UQ and UJ */
|
||
{
|
||
assertpro(('Z' == type) || ('U' == type));
|
||
assert('J' == type2 || 'Q' == type2);
|
||
GETFAOVALDEF(faocnt, fao, qw_num_ptr_t, val_ptr, NULL); /* Addr of long type */
|
||
if (val_ptr)
|
||
{
|
||
ret_ptr = i2ascl(numptr, *val_ptr);
|
||
length =(int)(ret_ptr - (uchar_ptr_t)numptr);
|
||
if (0 != field_width)
|
||
numptr += MIN(length, field_width);
|
||
else
|
||
numptr += length;
|
||
}
|
||
}
|
||
}
|
||
length = (int)(numptr - numa); /* Length of asciified number */
|
||
if (length < field_width)
|
||
{
|
||
memset(outptr, (('Z' == type) ? '0' : ' '), field_width - length);
|
||
outptr += field_width - length;
|
||
}
|
||
if ((field_width > 0) && (field_width < length))
|
||
{
|
||
GTM64_ONLY(
|
||
/* If this is an integer to be printed using format specifier X, display the
|
||
least 4 bytes */
|
||
if (type == 'X' && type2 == 'J' && (length == (2 * SIZEOF(INTPTR_T))))
|
||
memcpy(outptr, numa + SIZEOF(INTPTR_T), length/2);
|
||
else
|
||
memset(outptr, '*', field_width);
|
||
)
|
||
NON_GTM64_ONLY(memset(outptr, '*', field_width);)
|
||
outptr += field_width;
|
||
} else
|
||
{
|
||
memcpy(outptr, numa, length);
|
||
outptr += length;
|
||
}
|
||
}
|
||
}
|
||
va_end(TREF(last_va_list_ptr)); /* reset before using as dest in copy */
|
||
VAR_COPY(TREF(last_va_list_ptr), fao);
|
||
return outptr;
|
||
}
|
||
|
||
void util_out_close(void)
|
||
{
|
||
DCL_THREADGBL_ACCESS;
|
||
|
||
SETUP_THREADGBL_ACCESS;
|
||
if ((NULL != TREF(util_outptr)) && (TREF(util_outptr) != TREF(util_outbuff_ptr)))
|
||
util_out_print("", FLUSH);
|
||
}
|
||
|
||
void util_out_send_oper(char *addr, unsigned int len)
|
||
/* 1st arg: address of system log message */
|
||
/* 2nd arg: length of system long message (not used in Unix implementation) */
|
||
{
|
||
sigset_t savemask;
|
||
char *img_type, *offset, *proc_type=NULL, *helper_type=NULL;
|
||
char temp_inst_fn[MAX_FN_LEN + 1], fn[MAX_FN_LEN + 1];
|
||
mstr log_nam, trans_name;
|
||
uint4 ustatus;
|
||
int4 status;
|
||
unsigned int bufsize, file_name_len, *fn_len;
|
||
boolean_t ret;
|
||
repl_inst_hdr replhdr;
|
||
int fd;
|
||
upd_helper_ctl_ptr_t upd_helper_ctl;
|
||
upd_helper_entry_ptr_t helper, helper_top;
|
||
|
||
if (first_syslog)
|
||
{
|
||
first_syslog = FALSE;
|
||
|
||
offset = facility;
|
||
BUILD_FACILITY("GTM");
|
||
switch (image_type)
|
||
{
|
||
case GTM_IMAGE:
|
||
img_type = "MUMPS";
|
||
break;
|
||
case MUPIP_IMAGE:
|
||
img_type = "MUPIP";
|
||
break;
|
||
case DSE_IMAGE:
|
||
img_type = "DSE";
|
||
break;
|
||
case LKE_IMAGE:
|
||
img_type = "LKE";
|
||
break;
|
||
case DBCERTIFY_IMAGE:
|
||
img_type = "DBCERTIFY";
|
||
break;
|
||
case GTM_SVC_DAL_IMAGE:
|
||
img_type = "GTM_SVC_DAL";
|
||
break;
|
||
case GTCM_SERVER_IMAGE:
|
||
img_type = "GTCM";
|
||
break;
|
||
case GTCM_GNP_SERVER_IMAGE:
|
||
img_type = "GTCM_GNP";
|
||
break;
|
||
case GTMSECSHR_IMAGE:
|
||
img_type = "SECSHR";
|
||
break;
|
||
default:
|
||
assertpro(FALSE);
|
||
}
|
||
STRNCPY_STR(offset, img_type, STRLEN(img_type));
|
||
offset += STRLEN(img_type);
|
||
if (jnlpool_ctl)
|
||
{ /* Read instace file name from jnlpool */
|
||
if (image_type == MUPIP_IMAGE)
|
||
{
|
||
if (is_src_server)
|
||
proc_type = "SRCSRVR";
|
||
else if (is_rcvr_server)
|
||
proc_type = "RCVSRVR";
|
||
else if (is_updproc)
|
||
proc_type = "UPDPROC";
|
||
}
|
||
if (proc_type)
|
||
{
|
||
offset -= STRLEN(img_type);
|
||
BUILD_FACILITY(proc_type);
|
||
}
|
||
else
|
||
INSERT_MARKER;
|
||
STRNCPY_STR(offset, (char *)jnlpool.repl_inst_filehdr->inst_info.this_instname,
|
||
STRLEN((char *)jnlpool.repl_inst_filehdr->inst_info.this_instname));
|
||
} else
|
||
{ /* Read instance name from instance file */
|
||
if (is_updhelper)
|
||
{ /* Determine helper type from recvpool */
|
||
upd_helper_ctl = recvpool.upd_helper_ctl;
|
||
for (helper = upd_helper_ctl->helper_list, helper_top = helper + MAX_UPD_HELPERS;
|
||
helper < helper_top; helper++)
|
||
{
|
||
if (helper->helper_pid_prev == process_id) /* found my entry */
|
||
{
|
||
if ( UPD_HELPER_READER == helper->helper_type )
|
||
helper_type = "UPDREAD";
|
||
else if (UPD_HELPER_WRITER == helper->helper_type)
|
||
helper_type = "UPDWRITE";
|
||
break;
|
||
}
|
||
}
|
||
offset -= STRLEN(img_type);
|
||
if (helper_type) /*Otherwise entry for helper is not present in the receiver pool*/
|
||
{
|
||
BUILD_FACILITY(helper_type);
|
||
}
|
||
else {
|
||
proc_type = "UPDHELP";
|
||
BUILD_FACILITY(proc_type);
|
||
}
|
||
}
|
||
fn_len = &file_name_len;
|
||
bufsize = MAX_FN_LEN + 1;
|
||
log_nam.addr = GTM_REPL_INSTANCE;
|
||
log_nam.len = SIZEOF(GTM_REPL_INSTANCE) - 1;
|
||
trans_name.addr = temp_inst_fn;
|
||
ret = FALSE;
|
||
GET_INSTFILE_NAME(dont_sendmsg_on_log2long, return_on_error);
|
||
/* We want the instance name as part of operator log messages, but if we can’t get it,
|
||
* we will get by without it, so ignore any errors we might encounter trying to find the name
|
||
*/
|
||
if (ret)
|
||
{
|
||
OPENFILE(fn, O_RDONLY, fd);
|
||
if (FD_INVALID != fd)
|
||
{
|
||
LSEEKREAD(fd, 0, &replhdr, SIZEOF(repl_inst_hdr), status);
|
||
if (0 == status)
|
||
{
|
||
if (!is_updhelper)
|
||
{
|
||
INSERT_MARKER;
|
||
}
|
||
STRNCPY_STR(offset, (char *)replhdr.inst_info.this_instname,
|
||
STRLEN((char *)replhdr.inst_info.this_instname));
|
||
}
|
||
CLOSEFILE_RESET(fd, status);
|
||
}
|
||
}
|
||
}
|
||
DEFER_INTERRUPTS(INTRPT_IN_LOG_FUNCTION);
|
||
(void)OPENLOG(facility, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_USER);
|
||
ENABLE_INTERRUPTS(INTRPT_IN_LOG_FUNCTION);
|
||
}
|
||
/*
|
||
* When syslog is processing and a signal occurs, the signal processing might eventually lead to another syslog
|
||
* call. But in libc the first syslog has grabbed a lock (syslog_lock), and now the other syslog call will
|
||
* block waiting for that lock which can't be released since the first syslog was interrupted by the signal.
|
||
* We address this issue by deferring signals for the duration of the call; generic_signal_handler.c will also
|
||
* skip send_msg invocations if the interrupt comes while INTRPT_IN_LOG_FUNCTION is set.
|
||
*/
|
||
DEFER_INTERRUPTS(INTRPT_IN_LOG_FUNCTION);
|
||
SYSLOG(LOG_USER | LOG_INFO, "%s", addr);
|
||
ENABLE_INTERRUPTS(INTRPT_IN_LOG_FUNCTION);
|
||
}
|
||
|
||
void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt)
|
||
{
|
||
char fmt_buff[OUT_BUFF_SIZE]; /* needs to be same size as that of the util out buffer */
|
||
caddr_t fmtc;
|
||
int rc, count;
|
||
char *fmt_top1, *fmt_top2; /* the top of the buffer after leaving 1 (and 2 bytes respectively) at the end */
|
||
int util_avail_len;
|
||
DCL_THREADGBL_ACCESS;
|
||
|
||
SETUP_THREADGBL_ACCESS;
|
||
if (IS_GTMSECSHR_IMAGE && (FLUSH == flush))
|
||
flush = OPER; /* All gtmsecshr origin msgs go to operator log */
|
||
if (NULL == TREF(util_outptr))
|
||
TREF(util_outptr) = TREF(util_outbuff_ptr);
|
||
if (NULL != message)
|
||
{
|
||
util_avail_len = INTCAST(TREF(util_outbuff_ptr) + OUT_BUFF_SIZE - TREF(util_outptr) - 2);
|
||
assert(0 <= util_avail_len);
|
||
if (0 < util_avail_len)
|
||
TREF(util_outptr) = util_format(message, var, TREF(util_outptr), util_avail_len, faocnt);
|
||
}
|
||
switch (flush)
|
||
{
|
||
case NOFLUSH:
|
||
break;
|
||
case RESET:
|
||
break;
|
||
case FLUSH:
|
||
*(TREF(util_outptr))++ = '\n';
|
||
case OPER:
|
||
case SPRINT:
|
||
/* For all three of these actions we need to do some output buffer translation. In all cases a '%'
|
||
* is translated to the escape version '%%'. For OPER and SPRINT, we also translate '\n' to a ', '
|
||
* since some syslog() implementations (like Tru64) stop processing the passed message on a newline.
|
||
* Note that since the '%' -> '%%' or '\n' to ', ' translations imply an expansion in the buffer size
|
||
* requirements, we could potentially overflow the buffer after the translation. In that case we will
|
||
* stop copying just before the point of overflow is reached even though it means loss of the tail data.
|
||
*/
|
||
*(TREF(util_outptr)) = '\0';
|
||
fmt_top1 = fmt_buff + SIZEOF(fmt_buff) - 1;
|
||
fmt_top2 = fmt_top1 - 1;
|
||
for (TREF(util_outptr) = TREF(util_outbuff_ptr), fmtc = fmt_buff;
|
||
(0 != *(TREF(util_outptr))) && (fmtc < fmt_top1); )
|
||
{
|
||
if ('%' == *(TREF(util_outptr)))
|
||
{
|
||
if (fmtc >= fmt_top2) /* Check if there is room for 2 bytes. If not stop copying */
|
||
break;
|
||
if (flush == SPRINT)
|
||
*fmtc++ = '%'; /* give buffered users what they expect %% */
|
||
*fmtc++ = '%';
|
||
(TREF(util_outptr))++;
|
||
} else if ('\n' == *(TREF(util_outptr)) && (OPER == flush || SPRINT == flush))
|
||
{
|
||
if (fmtc >= fmt_top2) /* Check if there is room for 2 bytes. If not stop copying */
|
||
break;
|
||
*fmtc++ = ',';
|
||
*fmtc++ = ' ';
|
||
(TREF(util_outptr))++;
|
||
} else
|
||
*fmtc++ = *(TREF(util_outptr))++;
|
||
}
|
||
assert(fmtc <= fmt_top1);
|
||
*fmtc++ = '\0';
|
||
switch (flush)
|
||
{
|
||
case FLUSH:
|
||
FPRINTF(stderr, "%s", fmt_buff);
|
||
break;
|
||
case OPER:
|
||
util_out_send_oper(fmt_buff, UINTCAST(fmtc - fmt_buff));
|
||
break;
|
||
case SPRINT:
|
||
memcpy(TREF(util_outbuff_ptr), fmt_buff, fmtc - fmt_buff);
|
||
break;
|
||
}
|
||
break;
|
||
default:
|
||
assert(FALSE);
|
||
}
|
||
switch (flush)
|
||
{
|
||
case NOFLUSH:
|
||
break;
|
||
case FLUSH:
|
||
case RESET:
|
||
case OPER:
|
||
case SPRINT:
|
||
/* Reset buffer information. */
|
||
TREF(util_outptr) = TREF(util_outbuff_ptr);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void util_out_print(caddr_t message, int flush, ...)
|
||
{
|
||
va_list var;
|
||
DCL_THREADGBL_ACCESS;
|
||
|
||
SETUP_THREADGBL_ACCESS;
|
||
va_start(var, flush);
|
||
util_out_print_vaparm(message, flush, var, MAXPOSINT4);
|
||
va_end(TREF(last_va_list_ptr));
|
||
va_end(var);
|
||
}
|
||
|
||
/* Used primarily by MUPIP in the MUPIP TRIGGER routines where output can either be output "normally" there or
|
||
* when the same trigger parsing/loading functions are called from within GTM, the output is done with GTM IO
|
||
* routines.
|
||
*/
|
||
void util_out_print_gtmio(caddr_t message, int flush, ...)
|
||
{
|
||
int flush_it;
|
||
boolean_t usestdio;
|
||
va_list var;
|
||
mval flushtxt;
|
||
DCL_THREADGBL_ACCESS;
|
||
|
||
SETUP_THREADGBL_ACCESS;
|
||
va_start(var, flush);
|
||
usestdio = IS_MCODE_RUNNING;
|
||
assert((FLUSH == flush) || (NOFLUSH == flush));
|
||
flush_it = ((FLUSH == flush) && !usestdio) ? FLUSH : NOFLUSH;
|
||
util_out_print_vaparm(message, flush_it, var, MAXPOSINT4);
|
||
if (usestdio && (FLUSH == flush))
|
||
{ /* Message should be in buffer and we just need to flush it */
|
||
assert(NULL != op_write_ptr);
|
||
flushtxt.mvtype = MV_STR;
|
||
flushtxt.str.addr = TREF(util_outbuff_ptr);
|
||
flushtxt.str.len = INTCAST(TREF(util_outptr) - TREF(util_outbuff_ptr));
|
||
(*op_write_ptr)(&flushtxt);
|
||
(*op_wteol_ptr)(1);
|
||
TREF(util_outptr) = TREF(util_outbuff_ptr); /* Signal text is flushed */
|
||
}
|
||
va_end(TREF(last_va_list_ptr));
|
||
va_end(var);
|
||
}
|
||
|
||
/* If $x of the standard output device is non-zero, and we are going to flush a buffer,
|
||
* put out a new line and then do the buffer flush. Called and used only by PRN_ERROR
|
||
* macro.
|
||
*/
|
||
void util_cond_flush(void)
|
||
{
|
||
DCL_THREADGBL_ACCESS;
|
||
|
||
SETUP_THREADGBL_ACCESS;
|
||
if (NULL != io_std_device.out && 0 < io_std_device.out->dollar.x && TREF(util_outptr) != TREF(util_outbuff_ptr))
|
||
FPRINTF(stderr, "\n");
|
||
if (TREF(util_outptr) != TREF(util_outbuff_ptr))
|
||
util_out_print(NULL, FLUSH);
|
||
}
|
||
|
||
#ifdef DEBUG
|
||
/* White-box test only! Start a timer that prints something to the operator log with a period of
|
||
* UTIL_OUT_SYSLOG_INTERVAL in attempt to interrupt util_outbuff construction and overwrite the
|
||
* buffer's contents.
|
||
*/
|
||
void util_out_syslog_dump(void)
|
||
{
|
||
util_out_print("Just some white-box test message long enough to ensure that "
|
||
"whatever under-construction util_out buffer is not damaged.\n", OPER);
|
||
/* Resubmit itself for the purposes of the white-box test which expects periodic writes to the syslog. */
|
||
start_timer((TID)&util_out_syslog_dump, UTIL_OUT_SYSLOG_INTERVAL, util_out_syslog_dump, 0, NULL);
|
||
}
|
||
#endif
|