487 lines
18 KiB
C
487 lines
18 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 <stddef.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/time.h>
|
|
#include <sys/un.h>
|
|
#include <sys/sem.h>
|
|
#include <sys/shm.h>
|
|
#include <sys/param.h>
|
|
#include "gtm_ctype.h"
|
|
#include "gtm_stdlib.h" /* for exit() */
|
|
#include "gtm_string.h"
|
|
#include "gtm_socket.h"
|
|
#include "gtm_fcntl.h"
|
|
#include "gtm_unistd.h"
|
|
#include "gtm_stdio.h"
|
|
#include "gtm_stat.h"
|
|
#include "gt_timer.h"
|
|
#include "gtm_limits.h"
|
|
#include "gtm_syslog.h"
|
|
|
|
#include "gtmio.h"
|
|
#include "io.h"
|
|
#include "gtmsecshr.h"
|
|
#include "iosp.h"
|
|
#include "error.h"
|
|
#include "eintr_wrappers.h"
|
|
#include "util.h"
|
|
#include "send_msg.h"
|
|
#include "gtmmsg.h"
|
|
#include "wcs_backoff.h"
|
|
#include "trans_log_name.h"
|
|
#include "gdsroot.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "filestruct.h"
|
|
#include "gtm_logicals.h"
|
|
#include "secshr_client.h"
|
|
#include "gtm_semutils.h"
|
|
#include "hashtab.h" /* for STR_HASH macro */
|
|
#include "fork_init.h"
|
|
|
|
GBLREF struct sockaddr_un gtmsecshr_sock_name;
|
|
GBLREF key_t gtmsecshr_key;
|
|
GBLREF int gtmsecshr_sockpath_len;
|
|
GBLREF int gtmsecshr_sockfd;
|
|
GBLREF mstr gtmsecshr_pathname;
|
|
GBLREF int server_start_tries;
|
|
GBLREF boolean_t gtmsecshr_sock_init_done;
|
|
GBLREF uint4 process_id;
|
|
GBLREF ipcs_mesg db_ipcs;
|
|
|
|
LITREF char gtm_release_name[];
|
|
LITREF int4 gtm_release_name_len;
|
|
|
|
static int secshr_sem;
|
|
static boolean_t gtmsecshr_file_check_done;
|
|
static mstr gtmsecshr_logname;
|
|
static char gtmsecshr_path[GTM_PATH_MAX];
|
|
static volatile boolean_t client_timer_popped;
|
|
static unsigned long cur_seqno;
|
|
|
|
/* The below messages match up with the gtmsecshr_mesg_type codes */
|
|
const static char readonly *secshr_fail_mesg_code[] = {
|
|
"",
|
|
"Wake Message Failed",
|
|
"Remove Semaphore failed",
|
|
"Remove Shared Memory segment failed",
|
|
"Remove File failed",
|
|
"Continue Process failed",
|
|
};
|
|
/* The below messages match up with gtmsecshr exit codes from gtmsecshr.h. */
|
|
const static char readonly *secshrstart_error_code[] = {
|
|
"",
|
|
"gtmsecshr unable to set-uid to root",
|
|
"The environmental variable gtm_dist is pointing to an invalid path",
|
|
"Unable to exec gtmsecshr",
|
|
"gtmsecshr unable to create a child process",
|
|
"Error with gtmsecshr semaphore",
|
|
"gtmsecshr already running - invalid invocation",
|
|
"See syslog for cause of failure",
|
|
"gtmsecshr startup failed - gtmsecshr unable to chdir to tmp directory",
|
|
"gtmsecshr startup failed - gtmsecshr unable to determine invocation path",
|
|
"gtmsecshr startup failed - gtmsecshr not named gtmsecshr",
|
|
"gtmsecshr startup failed - $gtm_dist not same as startup path"
|
|
};
|
|
|
|
#define MAX_COMM_ATTEMPTS 4 /* 1 to start secshr, 2 maybe slow, 3 maybe really slow, 4 outside max */
|
|
#define CLIENT_ACK_TIMER 5
|
|
|
|
#define START_SERVER \
|
|
{ \
|
|
int arraysize, errorindex; \
|
|
\
|
|
if (0 != (create_server_status = create_server())) \
|
|
{ \
|
|
assert(ARRAYSIZE(secshrstart_error_code) == (LASTEXITCODE + 1)); \
|
|
errorindex = create_server_status; \
|
|
if ((0 > errorindex) || (LASTEXITCODE < errorindex)) \
|
|
errorindex = LASTEXITCODE; \
|
|
assert(0 <= errorindex); \
|
|
assert(ARRAYSIZE(secshrstart_error_code) > errorindex); \
|
|
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), \
|
|
process_id, ERR_TEXT, 2, \
|
|
RTS_ERROR_STRING(secshrstart_error_code[errorindex])); \
|
|
if (FATALFAILURE(create_server_status)) \
|
|
{ \
|
|
gtmsecshr_sock_cleanup(CLIENT); \
|
|
return create_server_status; \
|
|
} \
|
|
/* For transient failures we will continue after printing out message */ \
|
|
} \
|
|
hiber_start(3000); /* 3000 ms (3 sec) to allow server to come up */ \
|
|
}
|
|
|
|
#define SETUP_FOR_RECV \
|
|
{ \
|
|
recv_ptr = (char *)&mesg; \
|
|
recv_len = SIZEOF(mesg); \
|
|
client_timer_popped = FALSE; \
|
|
recv_complete = FALSE; \
|
|
save_errno = 0; \
|
|
msec_timeout = timeout2msec(CLIENT_ACK_TIMER); \
|
|
start_timer(timer_id, msec_timeout, client_timer_handler, 0, NULL); \
|
|
}
|
|
|
|
error_def(ERR_GTMSECSHR);
|
|
error_def(ERR_GTMSECSHRPERM);
|
|
error_def(ERR_GTMSECSHRSOCKET);
|
|
error_def(ERR_GTMSECSHRSRVF);
|
|
error_def(ERR_GTMSECSHRSRVFID);
|
|
error_def(ERR_GTMSECSHRSRVFIL);
|
|
error_def(ERR_GTMSECSHRSTART);
|
|
error_def(ERR_GTMSECSHRTMPPATH);
|
|
error_def(ERR_LOGTOOLONG);
|
|
error_def(ERR_SYSCALL);
|
|
error_def(ERR_TEXT);
|
|
|
|
void client_timer_handler(void)
|
|
{
|
|
client_timer_popped = TRUE;
|
|
}
|
|
|
|
int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path_len)
|
|
{
|
|
int client_sockfd, create_server_status, fcntl_res;
|
|
int req_code, wait_count = 0;
|
|
int recv_len, send_len;
|
|
ssize_t num_chars_recvd, num_chars_sent;
|
|
int save_errno, ret_code = 0, init_ret_code = 0;
|
|
int loop_count = 0;
|
|
int recv_complete, send_complete;
|
|
boolean_t retry = FALSE;
|
|
size_t server_proc_len;
|
|
int semop_res;
|
|
int selstat, status;
|
|
char *recv_ptr, *send_ptr;
|
|
struct sockaddr_un server_proc;
|
|
struct sembuf sop[4];
|
|
fd_set wait_on_fd;
|
|
gtmsecshr_mesg mesg;
|
|
TID timer_id;
|
|
int4 msec_timeout;
|
|
char *gtm_tmp_ptr;
|
|
struct stat stat_buf;
|
|
struct shmid_ds shm_info;
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
DBGGSSHR((LOGFLAGS, "secshr_client: New send request\n"));
|
|
/* Create communication key (hash of release name) if it has not already been done */
|
|
if (0 == TREF(gtmsecshr_comkey))
|
|
{
|
|
STR_HASH((char *)gtm_release_name, gtm_release_name_len, TREF(gtmsecshr_comkey), 0);
|
|
}
|
|
timer_id = (TID)send_mesg2gtmsecshr;
|
|
if (!gtmsecshr_file_check_done)
|
|
{
|
|
gtmsecshr_logname.addr = GTMSECSHR_PATH;
|
|
gtmsecshr_logname.len = SIZEOF(GTMSECSHR_PATH);
|
|
status = TRANS_LOG_NAME(>msecshr_logname, >msecshr_pathname, gtmsecshr_path, SIZEOF(gtmsecshr_path),
|
|
dont_sendmsg_on_log2long);
|
|
if (SS_NORMAL != status)
|
|
{
|
|
if (SS_LOG2LONG == status)
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3,
|
|
gtmsecshr_logname.len, gtmsecshr_logname.addr, SIZEOF(gtmsecshr_path) - 1);
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3,
|
|
RTS_ERROR_TEXT("Client"), process_id, ERR_TEXT, 2,
|
|
RTS_ERROR_STRING(secshrstart_error_code[INVTRANSGTMSECSHR]));
|
|
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3,
|
|
RTS_ERROR_TEXT("Client"), process_id, ERR_TEXT, 2,
|
|
RTS_ERROR_STRING(secshrstart_error_code[INVTRANSGTMSECSHR]));
|
|
}
|
|
gtmsecshr_pathname.addr[gtmsecshr_pathname.len] = '\0';
|
|
if (-1 == Stat(gtmsecshr_pathname.addr, &stat_buf))
|
|
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
|
|
LEN_AND_LIT("stat"), CALLFROM, errno);
|
|
if ((ROOTUID != stat_buf.st_uid) ||
|
|
!(stat_buf.st_mode & S_ISUID))
|
|
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMSECSHRPERM);
|
|
gtmsecshr_file_check_done = TRUE;
|
|
}
|
|
if (!gtmsecshr_sock_init_done && (0 < (init_ret_code = gtmsecshr_sock_init(CLIENT)))) /* Note assignment */
|
|
return init_ret_code;
|
|
DEBUG_ONLY(mesg.usesecshr = TREF(gtm_usesecshr)); /* Flag ignored in PRO build */
|
|
while (MAX_COMM_ATTEMPTS >= loop_count)
|
|
{ /* first, try the sendto */
|
|
req_code = mesg.code = code;
|
|
send_len = (int4)(GTM_MESG_HDR_SIZE);
|
|
if (REMOVE_FILE == code)
|
|
{
|
|
assert(GTM_PATH_MAX > path_len); /* Name is not user supplied so simple check */
|
|
memcpy(mesg.mesg.path, path, path_len);
|
|
send_len += path_len;
|
|
} else if (FLUSH_DB_IPCS_INFO == code)
|
|
{
|
|
assert(GTM_PATH_MAX > db_ipcs.fn_len);
|
|
memcpy(&mesg.mesg.db_ipcs, &db_ipcs, (offsetof(ipcs_mesg, fn[0]) + db_ipcs.fn_len + 1));
|
|
/* Most of the time file length is much smaller than GTM_PATH_MAX */
|
|
send_len += offsetof(ipcs_mesg, fn[0]);
|
|
send_len += mesg.mesg.db_ipcs.fn_len + 1;
|
|
} else
|
|
{
|
|
mesg.mesg.id = id;
|
|
send_len += SIZEOF(mesg.mesg.id);
|
|
}
|
|
DBGGSSHR((LOGFLAGS, "secshr_client: loop %d frm-pid: %d to-pid: %d send_len: %d code: %d\n", loop_count,
|
|
process_id, id, send_len, code));
|
|
mesg.comkey = TREF(gtmsecshr_comkey); /* Version communication key */
|
|
mesg.pid = process_id; /* Process id of client */
|
|
mesg.seqno = ++cur_seqno;
|
|
send_ptr = (char *)&mesg;
|
|
send_complete = FALSE;
|
|
SENDTO_SOCK(gtmsecshr_sockfd, send_ptr, send_len, 0, (struct sockaddr *)>msecshr_sock_name,
|
|
(GTM_SOCKLEN_TYPE)gtmsecshr_sockpath_len, num_chars_sent); /* This form handles EINTR internally */
|
|
save_errno = errno;
|
|
DBGGSSHR((LOGFLAGS, "secshr_client: sendto rc: %d errno: %d (only important if rc=-1)\n", (int)num_chars_sent,
|
|
save_errno));
|
|
if (0 >= num_chars_sent)
|
|
{ /* SENDTO_SOCK failed - start server and attempt to resend */
|
|
if ((EISCONN == save_errno) || (EBADF == save_errno))
|
|
{
|
|
gtmsecshr_sock_cleanup(CLIENT);
|
|
gtmsecshr_sock_init(CLIENT);
|
|
wcs_backoff(loop_count + 1);
|
|
DBGGSSHR((LOGFLAGS, "secshr_client: Connection error, reset socket\n"));
|
|
} else
|
|
{
|
|
if (0 < loop_count)
|
|
/* No message unless attempted server start at least once */
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_GTMSECSHRSRVF, 4,
|
|
RTS_ERROR_TEXT("Client"), process_id,
|
|
loop_count - 1, ERR_TEXT, 2,
|
|
RTS_ERROR_TEXT("sendto to gtmsecshr failed"), save_errno);
|
|
START_SERVER;
|
|
DBGGSSHR((LOGFLAGS, "secshr_client: sendto() failed - restarting server\n"));
|
|
}
|
|
loop_count++;
|
|
continue;
|
|
}
|
|
SETUP_FOR_RECV; /* Sets timer, recvcomplete = FALSE */
|
|
do
|
|
{ /* Note RECVFROM does not loop on EINTR return codes so must be handled. Note also we only expect
|
|
* to receive the message header back as an acknowledgement.
|
|
*/
|
|
num_chars_recvd = RECVFROM(gtmsecshr_sockfd, recv_ptr, GTM_MESG_HDR_SIZE, 0, (struct sockaddr *)0,
|
|
(GTM_SOCKLEN_TYPE *)0);
|
|
save_errno = errno;
|
|
DBGGSSHR((LOGFLAGS, "secshr_client: recvfrom rc: %d errno: %d (only important if rc=-1)\n",
|
|
(int)num_chars_recvd, save_errno));
|
|
if (0 <= num_chars_recvd)
|
|
{ /* Message received - make sure it is large enough to have set seqno before we do anything
|
|
* to rely on it.
|
|
*/
|
|
if ((GTM_MESG_HDR_SIZE <= num_chars_recvd) && (mesg.seqno == cur_seqno)
|
|
&& (TREF(gtmsecshr_comkey) == mesg.comkey))
|
|
recv_complete = TRUE;
|
|
else
|
|
{ /* Message too short or not correct sequence */
|
|
cancel_timer(timer_id);
|
|
/* Print True/False for the possibilities we failed */
|
|
DBGGSSHR((LOGFLAGS, "secshr_client: Message incorrect - chars: %d, seq: %d\n",
|
|
(GTM_MESG_HDR_SIZE <= num_chars_recvd), (mesg.seqno == cur_seqno)));
|
|
SETUP_FOR_RECV;
|
|
continue;
|
|
}
|
|
} else
|
|
{ /* Something untoward happened */
|
|
if (client_timer_popped)
|
|
break;
|
|
if (EINTR == save_errno) /* Had an irrelevant interrupt - ignore */
|
|
continue;
|
|
if (EBADF == save_errno)
|
|
break;
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_GTMSECSHRSRVF, 4,
|
|
RTS_ERROR_TEXT("Client"), process_id, loop_count - 1, ERR_TEXT, 2,
|
|
RTS_ERROR_TEXT("recvfrom from gtmsecshr failed"), save_errno);
|
|
if ((ECONNRESET == save_errno) || (ENOTCONN == save_errno))
|
|
{
|
|
num_chars_recvd = 0;
|
|
break;
|
|
}
|
|
gtmsecshr_sock_cleanup(CLIENT);
|
|
return save_errno;
|
|
}
|
|
} while (!recv_complete);
|
|
cancel_timer(timer_id);
|
|
if (client_timer_popped || (EBADF == save_errno) || (0 == num_chars_recvd))
|
|
{ /* Timeout, connection issues, bad descriptor block - retry */
|
|
gtmsecshr_sock_cleanup(CLIENT);
|
|
gtmsecshr_sock_init(CLIENT);
|
|
retry = TRUE;
|
|
if (client_timer_popped)
|
|
{
|
|
START_SERVER;
|
|
DBGGSSHR((LOGFLAGS, "secshr_client: Read timer popped - restarting server\n"));
|
|
} else
|
|
DBGGSSHR((LOGFLAGS, "secshr_client: Read error - socket reset, retrying\n"));
|
|
loop_count++;
|
|
continue;
|
|
}
|
|
/* Response to *our* latest message available */
|
|
assert(recv_complete);
|
|
if (ret_code = mesg.code) /* Warning - assignment */
|
|
{
|
|
DBGGSSHR((LOGFLAGS, "secshr_client: non-zero response from gtmsecshr - request: %d retcode: %d\n",
|
|
req_code, ret_code));
|
|
if (INVALID_COMKEY == ret_code)
|
|
{ /* Comkey mismatch means for a different version of GT.M - we will not handle it */
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_TEXT("Client"),
|
|
process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path),
|
|
ERR_TEXT, 2, RTS_ERROR_STRING("Communicating with wrong GT.M version"));
|
|
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_TEXT("Client"),
|
|
process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path),
|
|
ERR_TEXT, 2, RTS_ERROR_STRING("Communicating with wrong GT.M version"));
|
|
break; /* rts_error should not return */
|
|
}
|
|
switch(req_code)
|
|
{
|
|
case REMOVE_FILE:
|
|
/* Called from mutex_sock_init(). Path (and length) contain null terminator byte.
|
|
* See if file still exists (may have been deleted by earlier attempt). Caller
|
|
* handles actual error.
|
|
*/
|
|
if ((-1 != Stat(path, &stat_buf)) || (ENOENT != ret_code))
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7,
|
|
RTS_ERROR_TEXT("Client"),
|
|
process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path),
|
|
ERR_TEXT, 2, RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
|
|
mesg.code);
|
|
else
|
|
ret_code = 0; /* File is gone so this or a previous try actually worked */
|
|
break;
|
|
case REMOVE_SEM:
|
|
/* See if semaphore still eixsts (may have been removed by earlier attempt that
|
|
* got a reply confused or lost). If not there, no error. Else error to op-log.
|
|
*/
|
|
if ((-1 != semctl(id, 0, GETVAL)) && !SEM_REMOVED(errno))
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
|
|
RTS_ERROR_TEXT("Client"),
|
|
process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2,
|
|
RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
|
|
mesg.code);
|
|
else
|
|
ret_code = 0; /* File is gone so this or a previous try actually worked */
|
|
case REMOVE_SHM:
|
|
/* See if shmem still eixsts (may have been removed by earlier attempt that
|
|
* got a reply confused or lost). If not there, no error. Else error to op-log.
|
|
* Note -
|
|
*/
|
|
if ((-1 != shmctl(id, IPC_STAT, &shm_info)) && !SEM_REMOVED(errno))
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
|
|
RTS_ERROR_TEXT("Client"),
|
|
process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2,
|
|
RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
|
|
mesg.code);
|
|
else
|
|
ret_code = 0; /* File is gone so this or a previous try actually worked */
|
|
break;
|
|
case FLUSH_DB_IPCS_INFO: /* Errors handled by caller */
|
|
break;
|
|
default:
|
|
if (EPERM != mesg.code && EACCES != mesg.code)
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
|
|
RTS_ERROR_TEXT("Client"),
|
|
process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2,
|
|
RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
|
|
mesg.code);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (MAX_COMM_ATTEMPTS < loop_count)
|
|
{
|
|
ret_code = -1;
|
|
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSRVF, 4,
|
|
RTS_ERROR_TEXT("Client"), process_id, loop_count - 1,
|
|
ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to communicate with gtmsecshr"));
|
|
/* If gtm_tmp is not defined, show default path */
|
|
if (gtm_tmp_ptr = GETENV("gtm_tmp"))
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_GTMSECSHRTMPPATH, 2,
|
|
RTS_ERROR_TEXT(gtm_tmp_ptr),
|
|
ERR_TEXT, 2, RTS_ERROR_TEXT("(from $gtm_tmp)"));
|
|
else
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4)
|
|
ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT("/tmp"));
|
|
}
|
|
if (ONETIMESOCKET == init_ret_code)
|
|
gtmsecshr_sock_cleanup(CLIENT);
|
|
return ret_code;
|
|
}
|
|
|
|
int create_server(void)
|
|
{
|
|
int child_pid, done_pid, status = 0;
|
|
# ifdef _BSD
|
|
union wait chld_status;
|
|
# define CSTAT chld_status
|
|
# else
|
|
# define CSTAT status
|
|
# endif
|
|
int save_errno;
|
|
|
|
FORK(child_pid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
|
|
if (0 == child_pid)
|
|
{
|
|
process_id = getpid();
|
|
/* Do exec using gtmsecshr_path, which was initialize in file check code - send_mesg2gtmsecshr */
|
|
status = EXECL(gtmsecshr_path, gtmsecshr_path, 0);
|
|
if (-1 == status)
|
|
{
|
|
send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
|
|
ERR_TEXT, 2, RTS_ERROR_STRING(secshrstart_error_code[INVTRANSGTMSECSHR]));
|
|
exit(UNABLETOEXECGTMSECSHR);
|
|
}
|
|
} else
|
|
{
|
|
if (-1 == child_pid)
|
|
{
|
|
status = GNDCHLDFORKFLD;
|
|
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
|
|
ERR_TEXT, 2, RTS_ERROR_TEXT("Failed to fork off gtmsecshr"), errno);
|
|
/* Sleep for a while and hope a subsequent fork will succeed */
|
|
hiber_start(1000);
|
|
}
|
|
for (; !status ;)
|
|
{
|
|
/* To prevent a warning message that the compiler issues */
|
|
done_pid = wait(&CSTAT);
|
|
if (done_pid == child_pid)
|
|
{
|
|
status = WEXITSTATUS(CSTAT);
|
|
break;
|
|
} else if (-1 == done_pid)
|
|
{
|
|
if (ECHILD == errno) /* Assume normal exit status */
|
|
break;
|
|
else if (EINTR != errno)
|
|
{
|
|
status = GNDCHLDFORKFLD;
|
|
gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3,
|
|
RTS_ERROR_TEXT("Client"), process_id,
|
|
ERR_TEXT, 2, RTS_ERROR_TEXT("Error spawning gtmsecshr"), errno);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return status;
|
|
}
|