## root/clib/sys_log.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. sys_log_init
2. sys_log_end
3. sys_log
4. sys_log_nf
5. sys_log_status
6. sys_log_stop
7. sys_log_lock
8. sys_log_unlock
9. sys_log_open
10. sys_log_close
11. sys_log_delete
12. sys_log_log_off
13. sys_log_log_on
14. sys_log_log_status
15. sys_log_service_name
16. sys_log_version
17. sys_log_trans_num
18. sys_log_connect_num
19. is_sys_log_active
20. sys_log_console
21. sys_log_get_console
22. sys_log_get_active
23. sys_log_sr_code
24. sys_log_sr_char
25. sys_log_sr_long
26. sys_log_sr_int
27. sys_log_failover
28. sys_log_lsr_code
29. sys_log_lsr_char
30. sys_log_lsr_long
31. sys_log_lsr_int
32. sys_log_client_connect
33. sys_log_header

    /* System logger client API.
       Rick Smereka, Copyright (C) 1998-2004.

       This API uses the 'socloc' server to obtain the TCP/IP
       details of a 'sys_log' server. You must have already
       initialized the 'socloc' API by calling 'sloc_initialize'.
       There must be at least one running 'socloc' server and one
       running 'sys_log' server. Automatic failover of the 'socloc'
       server is provided in the 'socloc' API. Automatic failover
       of the 'sys_log' server is provided in this API (provided
       there is another server to failover to.
       Note that this interface does not use the IPC library
       (with the exception of the 'IPCOMM.C' low level
       routines) since the client of this API might
       be a TCP server whose executable will be bound
       to the IPC routines in 'IPCSRV.C'.

       This program is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation; either version 2 of the License, or
       (at your option) any later version.

       This program is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.

       You should have received a copy of the GNU General Public License
       along with this program; if not, get a copy via the Internet at
       http://gnu.org/copyleft/gpl.html or write to the Free Software
       Foundation, Inc., 59 Temple Place, Suite 330, Boston,
       MA 02111-1307 USA

       You can contact the author via email at rsmereka@future-lab.com

       Original version for CodeWarrior V4 under Windows 32bit.
       Dec/98, Rick Smereka

       Ported to HP-UX under GNU C 2.8.1.
       Jan/99, Rick Smereka

       Added function 'is_sys_log_active'. Feb/99,
       Rick Smereka

       Ported to Red Hat Linux 5.2, Jul/99, Rick Smereka

       Changed to use the 'socloc' API instead of local IPC config files.
       Also changed to provide automatic failover to another 'sys_log'
       server (provided there is another one running). Added missing
       common socket send commands. Removed all references to the Windows
       Winsock fuctions 'WSAStartup' and 'WSACleanup' as the client
       application is now responsible to call these. Mar/2000,
       Rick Smereka

       Added function 'sys_log_get_active' to obtain the host name
       and TCP/IP port number of the current 'sys_log' server.
       Removed all personal logging calls from the functions
       'sys_log' and 'sys_log_header' as these casued too many
       messages in the logs. Apr/2000, Rick Smereka

       Modified for use with both socket and QNX message passing IPC.
       Added function 'sys_log_nf'. Oct/2001, Rick Smereka

       Added a parameter to the 'sys_log_init' function consisting of
       the application name. Added global module variables to hold the
       application name, local host name (TCP), current process ID (QNX
       message passing) and current node ID (QNX message passing).
       Modified 'sys_log_init' to load this data. Modified 'sys_log_end'
       to de-allocate dynamically allocated module data.
       Jun/2002, Rick Smereka

       Added extra error messages using the personal logger.
       Oct/2002, Rick Smereka

       Ported to Debian Linux. Nov/2002, Rick Smereka

       Corrected bug in TCP socket connect to the server. The TCP
       socket 'connect' function was being called for each request
       sent to the server.  This caused the socket descriptor pool
       to become exhausted under some Unix's when a large number
       of transactions were being processed. This behavior has been
       changed to connect to the server only upon initialization or
       previous send/receive socket error. This means that the socket
       stays connected even when not in use. It is up to the
       developer to call 'sys_log_end' when the socket is no longer
       required.

       This API will properly talk only to sys_log server's that are using
       the new 'ipcsrv' (GPL package version 1.33 or higher).

       Added functions 'sys_log_trans_num' and 'sys_log_connect_num'.
       May/2003, Rick Smereka

       Added global 'sys_log_console_output'. Added functions
       'sys_log_console' and 'sys_log_get_console'. Modified
       functions 'sys_log' and 'sys_log_nf' to output the message
       to the screen if 'sys_log_console_output' flag is high.
       Mar/2004, Rick Smereka */

    #include "stdhead.h"
    #include "flsocket.h"

    #ifdef IPC_TCP
    #include "ipcomm.h"
    #include "socloc.h"
    #include "sloc.h"
    #include "sliocode.h"
    #endif

    // global (to module) data

    #ifdef IPC_TCP
    #ifdef OS_WIN32
    SOCKET sl_clientSocket;           // client socket
    SOCKADDR_IN sl_sockClientAddr;    // client address structure
    LPHOSTENT sl_lpHostEnt;           // host info structure
    #endif

    #ifdef OS_UNIX
    int sl_clientSocket;
    struct sockaddr_in sl_sockClientAddr;
    struct hostent *sl_lpHostEnt;
    #endif

    char sys_log_hostname[128];       // host name of system logger
    char *this_hostname;              // host name running this application
    int sys_log_port = 0;             // port system logger is using
    int sys_log_is_connect;           // have we already connected?
    #else
    pid_t sys_log_pid = -1;           // QNX process ID of system log server
    pid_t this_pid;                   // QNX process ID of this application
    nid_t this_nid;                   // QNX node ID of this application
    #endif

    int sys_log_islog = FALSE;        // is system logging active?
    int sys_log_console_output = FALSE; // log messages to console?
    char *this_apname;                // current application name

    // private function prototypes

    static int sys_log_sr_code(int, char *);
    static int sys_log_sr_char(int, char *, char *);
    static int sys_log_sr_long(int, char *, long *);
    static int sys_log_sr_int(int, char *, int *);
    static int sys_log_lsr_code(int, char *);
    static int sys_log_lsr_char(int, char *, char *);
    static int sys_log_lsr_long(int, char *, long *);
    static int sys_log_lsr_int(int, char *, int *);
    static void sys_log_header(char *);

    #ifdef IPC_TCP
    static int sys_log_failover(int);
    static int sys_log_client_connect(void);
    #endif

    int sys_log_init(char *apname)
    {
       /* Initialize the client for communication with the
          system logger. This function will attempt to find a
          running 'sys_log' server by using the 'socloc' API.
          A check is made to make sure that the socloc interface
          has already been initialized. Note that 'socloc' is used
          only in TCP IPC. The parameter 'apname' must contain the
          current running application name. Function returns a
          'sys_log' code. */

       char mname[] = "sys_log_init";
       char mes[128], *localHost;
       int ret;

       sys_log_header(mname);

    #ifdef IPC_TCP
       sys_log_hostname[0] = EOS;
       sys_log_port = 0;
       sys_log_is_connect = FALSE;

       /* make sure 'socloc' has already been initialized */

       if ((ret = sloc_is_init()) != SL_OK)
          {
          sl_code_string(ret, mes);
          log_file_date("%s:bad rc[%d,%s] from 'sloc_is_init'", mname,
                        ret, mes);
          return(SYS_LOG_SOCLOC_NO_INIT);
          }

       /* locate a 'sys_log' server */

       if ((ret = sloc_find(SYS_LOG_SERVICE_NAME, sys_log_hostname,
                            &sys_log_port, (char *)NULL)) != SL_OK)
          /* it is assumed that the failure is 'not found' */
          {
          sl_code_string(ret, mes);
          log_file_date("%s:bad rc[%d,%s] from 'sloc_find'", mname,
                        ret, mes);
          return(SYS_LOG_NO_SERVER);
          }

       /* obtain and store the host name this application is running on */

       if ((localHost = (char *)malloc(1024)) == (char *)NULL)
          {
          log_file_date("%s:alloc fail[localHost]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       // attempt to resolve the local host name

       if (gethostname(localHost, 1023))
          {
          free(localHost);
          log_file_date("%s:unable to resolve local host name", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       if ((this_hostname = initstring(localHost)) == (char *)NULL)
          {
          log_file_date("%s:alloc fail[this_hostname]", mname);
          free(localHost);
          return(SYS_LOG_ALLOC_FAIL);
          }

       free(localHost);

       if ((ret = sys_log_client_connect()) != SYS_LOG_OK)
          {
          sys_log_code_string(ret, mes);
          log_file_date("%s:bad rc[%s] from 'sys_log_client_connect'", mname,
                        mes);
          return(ret);
          }
    #else
       if ((sys_log_pid = qnx_name_locate(0, SYS_LOG_SERVICE_NAME, 0, NULL)) == -1)
          {
          log_file_date("%s:bad rc[-1] from 'qnx_name_locate'", mname);
          return(SYS_LOG_NO_SERVER);
          }

       this_nid = getnid();
       this_pid = getpid();
    #endif

       if (apname == (char *)NULL || !strlen(apname))
          {
          log_file_date("%s:null or empty[apname]", mname);
          return(SYS_LOG_PARM_ERROR);
          }

       if ((this_apname = initstring(apname)) == (char *)NULL)
          {
          log_file_date("%s:alloc fail[this_apname]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       sys_log_islog = TRUE;
       log_file_date("%s:normal exit,rc[0]", mname);
       return(SYS_LOG_OK);
    }

    void sys_log_end(void)
    {
       /* End system logging. All further calls to 'sys_log' will
          be immediately returned. This will not affect personal
          logging ('log_start', 'log'). Use 'sys_log_init' to
          re-initialize system logging. */

       char mname[] = "sys_log_end";

       sys_log_header(mname);
       sys_log_islog = FALSE;
       free(this_apname);

    #ifdef IPC_TCP
       sys_log_hostname[0] = EOS;
       sys_log_port = 0;
       sys_log_is_connect = FALSE;
       free(this_hostname);

       // only close socket upon API shutdown

    #ifdef OS_WIN32
       (void)closesocket(sl_clientSocket);
    #else
       close(sl_clientSocket);
    #endif
    #else
       sys_log_pid = -1;
    #endif

       log_file_date("%s:normal exit", mname);
    }

    int sys_log(char *fmt,...)
    {
       /* Log a message to the system log thru the system logging
          server. System logging must be turned on (thru 'sys_log_init')
          otherwise this function will return 'FALSE' immediately.
          Its ok to have spaces in the message. DO NOT USE THE
          SINGLE QUOTE IN YOUR MESSAGE as this will confuse
          the parser. This function automatically surrounds
          the message in single quotes. No personal logging
          of this function is performed. Function returns a 'sys_log'
          code. */

       va_list argptr;
       char *mes;
       int ret;

       // if system logging not active, return

       if (!sys_log_islog)
          return(SYS_LOG_NO_SERVER);

       va_start(argptr, fmt);

       if ((mes = (char *)malloc(SYS_LOG_MAXMES)) == (char *)NULL)
          {
          log_file_date_nf("sys_log:alloc fail[mes]");
          return(SYS_LOG_ALLOC_FAIL);
          }

       // format message

       memset(mes, 0, SYS_LOG_MAXMES);
       vsprintf(mes, fmt, argptr);
       ret = sys_log_sr_code(SYS_LOG_SEND, mes);

       if (ret == SYS_LOG_OK && sys_log_console_output)
          printf("%s\n", mes);

       free(mes);
       return(ret);
    }

    int sys_log_nf(char *mes)
    {
       /* Operates the same as 'sys_log' except that the string
          to send is assumed to already be formatted. Function
          returns a 'sys_log' code. */

       int ret;

       // if system logging not active, return

       if (!sys_log_islog)
          return(SYS_LOG_NO_SERVER);

       ret = sys_log_sr_code(SYS_LOG_SEND, mes);

       if (ret == SYS_LOG_OK && sys_log_console_output)
          printf("%s\n", mes);

       return(ret);
    }

    int sys_log_status(void)
    {
       /* Get the current status of the system logging server.
          Function returns 'SYS_LOG_OK' upon success, another
          'sys_log' code otherwise. */

       char mname[] = "sys_log_status";
       int ret;

       sys_log_header(mname);
       ret = sys_log_sr_code(SYS_LOG_SEND_STATUS, (char *)NULL);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int sys_log_stop(char *passwd)
    {
       /* Attempt to halt the system logging server. Server
          password is expected in 'passwd'. Function returns
          a 'sys_log' code. */

       char mname[] = "sys_log_stop";
       int ret;

       sys_log_header(mname);

       if (passwd == (char *)NULL || !strlen(passwd))
          {
          log_file_date("%s:password null or empty", mname);
          return(SYS_LOG_PARM_ERROR);
          }

       ret = sys_log_sr_code(SYS_LOG_SEND_STOP, passwd);

       /* if termination was successful, attempt to
          failover to another 'sys_log' server (TCP only) */

    #ifdef IPC_TCP
       if (ret == SYS_LOG_OK)
          ret = sys_log_failover(FALSE);
    #endif

       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int sys_log_lock(void)
    {
       /* Lock the primary log file. No read/write operations will
          be done on the file while it is locked. Function returns
          'SYS_LOG_OK' upon success, an error code (defined in
          'sys_log.h') otherwise. */

       char mname[] = "sys_log_lock";
       int ret;

       sys_log_header(mname);
       ret = sys_log_sr_code(SYS_LOG_SEND_LOCK, (char *)NULL);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int sys_log_unlock(void)
    {
       /* Unlock the primary log file. Function returns
          'SYS_LOG_OK' upon success, an error code (defined in
          'sys_log.h') otherwise. */

       char mname[] = "sys_log_unlock";
       int ret;

       sys_log_header(mname);
       ret = sys_log_sr_code(SYS_LOG_SEND_UNLOCK, (char *)NULL);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int sys_log_open(void)
    {
       /* Open (and leave open) the primary log file. Function
          returns 'SYS_LOG_OK' upon success, an error code
          otherwise. */

       char mname[] = "sys_log_open";
       int ret;

       sys_log_header(mname);
       ret = sys_log_sr_code(SYS_LOG_SEND_OPEN, (char *)NULL);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);

    }

    int sys_log_close(void)
    {
       /* Close the primary log file. File must be currently open.
          Function returns 'SYS_LOG_OK' upon success, an error code
          otherwise. */

       char mname[] = "sys_log_close";
       int ret;

       sys_log_header(mname);
       ret = sys_log_sr_code(SYS_LOG_SEND_CLOSE, (char *)NULL);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int sys_log_delete(char *passwd)
    {
       /* Attempt to delete the primary log file. Server
          password is expected in 'passwd'. Function returns
          'SYS_LOG_OK' if the log file was deleted, a
          'sys_log' error code otherwise. */

       char mname[] = "sys_log_delete";
       int ret;

       sys_log_header(mname);

       if (passwd == (char *)NULL || !strlen(passwd))
          {
          log_file_date("%s:password is null or empty", mname);
          return(SYS_LOG_PARM_ERROR);
          }

       ret = sys_log_sr_code(SYS_LOG_SEND_DELETE, passwd);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int sys_log_log_off(void)
    {
       /* Implementation of the common socket send code to turn the
          log off. Since this does not make sense in the 'sys_log'
          server, it is not implemented. */

       char mname[] = "sys_log_log_off";
       int ret;

       sys_log_header(mname);
       log_file_date("%s:normal exit,rc[%d]", mname, SYS_LOG_NOT_IMPLEMENTED);
       return(SYS_LOG_NOT_IMPLEMENTED);
    }

    int sys_log_log_on(char *lfname)
    {
       /* Implementation of the common socket send code to turn the
          log on. Since this does not make sense in the 'sys_log'
          server, it is not implemented. The parameter 'lfname'
          is used to maintain compatibility with other server
          'log on' commands. */

       char mname[] = "sys_log_log_on";
       int ret;

       sys_log_header(mname);
       log_file_date("%s:normal exit,rc[%d]", mname, SYS_LOG_NOT_IMPLEMENTED);
       return(SYS_LOG_NOT_IMPLEMENTED);
    }

    int sys_log_log_status(int *lflag, char *lfname)
    {
       /* Get status of 'sys_log' server logging. Function returns
          the log status (0=off,1=on) in 'lflag' (which is always
          on) and the current primary log file name in 'lfname'
          followed by a comma and the alternate log file name
          upon success. Function returns a 'sys_log' code. */

       char mname[] = "sys_log_log_status";
       char reply[128], flag_char[25];
       int ret, flag;

       sys_log_header(mname);

       if (lflag == (int *)NULL)
          {
          log_file_date("%s:null parm[lflag]", mname);
          return(SYS_LOG_PARM_ERROR);
          }

       if (lfname == (char *)NULL)
          {
          log_file_date("%s:null parm[lfname]", mname);
          return(SYS_LOG_PARM_ERROR);
          }

       lfname[0] = EOS;
       *lflag = 0;

       if ((ret = sys_log_sr_char(SYS_LOG_SEND_LOG_STATUS, (char *)NULL, reply))
           != SYS_LOG_OK)
          {
          log_file_date("%s:bad rc[%d] from 'sys_log_sr_char'", mname, ret);
          return(ret);
          }

       if (!command_word(reply, flag_char, 1))
          {
          log_file_date("%s:parse error[flag_char]", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       if (!qatoi(flag_char, &flag))
          {
          log_file_date("%s:status flag not numeric", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       if (flag != 0 && flag != 1)
          {
          log_file_date("%s:status flag not zero or one", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       *lflag = flag;

       if (!command_word(reply, lfname, 2))
          {
          log_file_date("%s:parse error[lfname]", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int sys_log_service_name(char *sname)
    {
       /* Get the 'sys_log' server service name which should always
          be 'sys_log'. Function returns the service name in 'sname'
          upon success which already be allocated to sufficident size.
          Function returns a 'sys_log' code. */

       char mname[] = "sys_log_service_name";
       int ret;

       sys_log_header(mname);

       if (sname == (char *)NULL)
          {
          log_file_date("%s:null parm[sname]", mname);
          return(SYS_LOG_PARM_ERROR);
          }

       sname[0] = EOS;
       ret = sys_log_sr_char(SYS_LOG_SEND_SERVICE_NAME, (char *)NULL, sname);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int sys_log_version(char *ver)
    {
       /* Get the 'sys_log' server version ID string. Function returns the
          version string in 'ver' upon success which must already be
          allocated to sufficient size. Function returns a 'sys_log'
          code. */

       char mname[] = "sys_log_version";
       int ret;

       sys_log_header(mname);

       if (ver == (char *)NULL)
          {
          log_file_date("%s:null parm[ver]", mname);
          return(SYS_LOG_PARM_ERROR);
          }

       ver[0] = EOS;
       ret = sys_log_sr_char(SYS_LOG_SEND_VERSION, (char *)NULL, ver);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int sys_log_trans_num(long *trans_num)
    {
       /* Get the 'sys_log' server current transaction count.
          Function returns the transaction count in 'trans_num'
          upon success. Function returns a 'sys_log' code. */

       char mname[] = "sys_log_trans_num";
       int ret;

       sys_log_header(mname);

       if (trans_num == (long *)NULL)
          {
          log_file_date("%s:null parm[trans_num]", mname);
          return(SYS_LOG_PARM_ERROR);
          }

       *trans_num = 0L;
       ret = sys_log_sr_long(SYS_LOG_SEND_TRANS_NUM, (char *)NULL, trans_num);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int sys_log_connect_num(int *connect_num)
    {
       /* Get the 'sys_log' server current connection count.
          Function returns the connection count in 'connect_num'
          upon success. Function returns a 'sys_log' code. */

       char mname[] = "sys_log_connect_num";
       int ret;

       sys_log_header(mname);

       if (connect_num == (int *)NULL)
          {
          log_file_date("%s:null parm[connect_num]", mname);
          return(SYS_LOG_PARM_ERROR);
          }

       *connect_num = 0;
       ret = sys_log_sr_int(SYS_LOG_SEND_CONNECT_NUM, (char *)NULL, connect_num);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    int is_sys_log_active(void)
    {
       /* Return the value of the 'sys_log_islog' flag. */

       char mname[] = "is_sys_log_active";

       sys_log_header(mname);
       log_file_date("%s:normal exit,active[%d]", mname, sys_log_islog);
       return(sys_log_islog);
    }

    void sys_log_console(int flag)
    {
       /* Set whether logging output will be sent to the console/screen.
          Output will be turned off if 'flag' is zero. Any other value
          will cause console output to be turned on. */

       sys_log_console_output = flag ? 1 : 0;
    }

    int sys_log_get_console(void)
    {
       /* Return the current value of the console/screem output flag
          ('sys_log_console_output'). */

       return(sys_log_console_output);
    }

    #ifdef IPC_TCP
    void sys_log_get_active(char *hname, int *port)
    {
       /* Get and return the active 'sys_log' server host name
          and port number. 'hname' must be allocated by the
          caller to sufficient size. */

       if (hname == (char *)NULL || port == (int *)NULL)
          return;

       hname[0] = EOS;
       *port = 0;

       if (!strlen(sys_log_hostname) || sys_log_port == 0)
          return;

       strcpy(hname, sys_log_hostname);
       *port = sys_log_port;
    }
    #endif

    // private functions

    static int sys_log_sr_code(int typ, char *parm)
    {
       /* Send and receive a message to the 'sys_log' server that
          returns only a code. Function will failover to another
          'sys_log' server (if one available) upon a socket
          communication error (TCP only). If the send code indicates
          a message to be logged, the message will be prefixed with
          the application name followed by the TCP hostname or
          the QNX message passing node ID and process ID depending
          on the IPC method in use. Function returns a 'sys_log'
          code. */

       char mname[] = "sys_log_sr_code", *new_parm;
       int ret, done = FALSE;

       sys_log_header(mname);

       /* make sure server specs are present */

    #ifdef IPC_TCP
       if (!sys_log_port || sys_log_hostname == (char *)NULL ||
           !strlen(sys_log_hostname))
    #else
       if (sys_log_pid == -1)
    #endif
          {
          log_file_date("%s:no init or no current sys_log server", mname);
          return(SYS_LOG_NO_INIT);
          }

       /* prefix the message with the application name plus either
          the TCP hostname or the QNX message passing node ID and
          process ID */

       if (typ == SYS_LOG_SEND)
          {
          ret = (parm != (char *)NULL && strlen(parm)) ? strlen(parm) : 0;

          if ((new_parm = (char *)malloc(ret + 1024)) == (char *)NULL)
             {
             log_file_date("%s:alloc fail[new_parm]", mname);
             return(SYS_LOG_ALLOC_FAIL);
             }

          if (ret)
    #ifdef IPC_TCP
             sprintf(new_parm, "[%s,%s]%s", this_apname, this_hostname, parm);
    #else
             sprintf(new_parm, "[%s,%lu,%d]%s", this_apname, this_nid, this_pid,
                     parm);
    #endif
          else
    #ifdef IPC_TCP
             sprintf(new_parm, "[%s,%s]", this_apname, this_hostname);
    #else
             sprintf(new_parm, "[%s,%lu,%d]", this_apname, this_nid, this_pid);
    #endif
          }
       else
          if ((new_parm = initstring(parm)) == (char *)NULL)
             {
             log_file_date("%s:alloc fail[initstring,new_parm]", mname);
             return(SYS_LOG_ALLOC_FAIL);
             }

    #ifdef IPC_QNX
       ret = sys_log_lsr_code(typ, new_parm);
    #else
       /* loop while there is a socket error and other 'sys_log'
          servers are available */

       while(!done)
          {
          /* attempt to send command and receive reply */

          ret = sys_log_lsr_code(typ, new_parm);
          log_file_date("%s:'sys_log_lsr_code' rc[%d]", mname, ret);

          /* if a socket communication error, failover */

          if (ret == SYS_LOG_VC_ERROR)
             {
             log_file_date("%s:server not responding,will failover", mname);

             /* if failover failed, exit */

             if ((ret = sys_log_failover(TRUE)) != SYS_LOG_OK)
                {
                log_file_date("%s:bad rc[%d] from 'sys_log_failover'",
                              mname, ret);
                done = TRUE;
                }
             }
          else
             done = TRUE;
          }
    #endif

       free(new_parm);
       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    static int sys_log_sr_char(int typ, char *parm, char *char_out)
    {
       /* Send and receive a message to the 'sys_log' server that
          returns a string in addition to the return code. Function
          will failover to another 'sys_log' server (if one available)
          upon a socket communication error (TCP only). Function returns
          a 'sys_log' code. */

       char mname[] = "sys_log_sr_char";
       int ret, done = FALSE;

       sys_log_header(mname);

       /* make sure server specs are present */

    #ifdef IPC_TCP
       if (!sys_log_port || sys_log_hostname == (char *)NULL ||
           !strlen(sys_log_hostname))
    #else
       if (sys_log_pid == -1)
    #endif
          {
          log_file_date("%s:no init or no current sys_log server", mname);
          return(SYS_LOG_NO_INIT);
          }

    #ifdef IPC_QNX
       ret = sys_log_lsr_char(typ, parm, char_out);
    #else
       /* loop while there is a socket error and other 'sys_log'
          servers are available */

       while(!done)
          {
          /* attempt to send command and receive reply */

          ret = sys_log_lsr_char(typ, parm, char_out);
          log_file_date("%s:'sys_log_lsr_char' rc[%d]", mname, ret);

          /* if a socket communication error, failover */

          if (ret == SYS_LOG_VC_ERROR)
             {
             log_file_date("%s:server not responding,will failover", mname);

             /* if failover failed, exit */

             if ((ret = sys_log_failover(TRUE)) != SYS_LOG_OK)
                {
                log_file_date("%s:bad rc[%d] from 'sys_log_failover'",
                              mname, ret);
                done = TRUE;
                }
             }
          else
             done = TRUE;
          }
    #endif

       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    static int sys_log_sr_long(int typ, char *parm, long *long_out)
    {
       /* Send and receive a message to the 'sys_log' server that
          returns a long integer in addition to the return code. Function
          will failover to another 'sys_log' server (if one available)
          upon a socket communication error (TCP only). Function returns
          a 'sys_log' code. */

       char mname[] = "sys_log_sr_long";
       int ret, done = FALSE;

       sys_log_header(mname);

       /* make sure server specs are present */

    #ifdef IPC_TCP
       if (!sys_log_port || sys_log_hostname == (char *)NULL ||
           !strlen(sys_log_hostname))
    #else
       if (sys_log_pid == -1)
    #endif
          {
          log_file_date("%s:no init or no current sys_log server", mname);
          return(SYS_LOG_NO_INIT);
          }

    #ifdef IPC_QNX
       ret = sys_log_lsr_long(typ, parm, long_out);
    #else
       /* loop while there is a socket error and other 'sys_log'
          servers are available */

       while(!done)
          {
          /* attempt to send command and receive reply */

          ret = sys_log_lsr_long(typ, parm, long_out);
          log_file_date("%s:'sys_log_lsr_long' rc[%d]", mname, ret);

          /* if a socket communication error, failover */

          if (ret == SYS_LOG_VC_ERROR)
             {
             log_file_date("%s:server not responding,will failover", mname);

             /* if failover failed, exit */

             if ((ret = sys_log_failover(TRUE)) != SYS_LOG_OK)
                {
                log_file_date("%s:bad rc[%d] from 'sys_log_failover'",
                              mname, ret);
                done = TRUE;
                }
             }
          else
             done = TRUE;
          }
    #endif

       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    static int sys_log_sr_int(int typ, char *parm, int *int_out)
    {
       /* Send and receive a message to the 'sys_log' server that
          returns an integer in addition to the return code. Function
          will failover to another 'sys_log' server (if one available)
          upon a socket communication error (TCP only). Function returns
          a 'sys_log' code. */

       char mname[] = "sys_log_sr_int";
       int ret, done = FALSE;

       sys_log_header(mname);

       /* make sure server specs are present */

    #ifdef IPC_TCP
       if (!sys_log_port || sys_log_hostname == (char *)NULL ||
           !strlen(sys_log_hostname))
    #else
       if (sys_log_pid == -1)
    #endif
          {
          log_file_date("%s:no init or no current sys_log server", mname);
          return(SYS_LOG_NO_INIT);
          }

    #ifdef IPC_QNX
       ret = sys_log_lsr_int(typ, parm, int_out);
    #else
       /* loop while there is a socket error and other 'sys_log'
          servers are available */

       while(!done)
          {
          /* attempt to send command and receive reply */

          ret = sys_log_lsr_int(typ, parm, int_out);
          log_file_date("%s:'sys_log_lsr_int' rc[%d]", mname, ret);

          /* if a socket communication error, failover */

          if (ret == SYS_LOG_VC_ERROR)
             {
             log_file_date("%s:server not responding,will failover", mname);

             /* if failover failed, exit */

             if ((ret = sys_log_failover(TRUE)) != SYS_LOG_OK)
                {
                log_file_date("%s:bad rc[%d] from 'sys_log_failover'",
                              mname, ret);
                done = TRUE;
                }
             }
          else
             done = TRUE;
          }
    #endif

       log_file_date("%s:normal exit,rc[%d]", mname, ret);
       return(ret);
    }

    #ifdef IPC_TCP
    static int sys_log_failover(int dflag)
    {
       /* Failover to another 'sys_log' server. The flag 'dflag'
          indicates whether we should get 'socloc' to delete the
          old entry. */

       char mname[] = "sys_log_failover";
       char mes[128];
       int ret;

       sys_log_header(mname);
       sys_log_is_connect = FALSE;

       // close current socket

    #ifdef OS_WIN32
       (void)closesocket(sl_clientSocket);
    #else
       close(sl_clientSocket);
    #endif

       if (dflag)
          if ((ret = sloc_delete(sys_log_port)) != SL_OK)
             {
             /* if delete fails log a message but continue */

             sl_code_string(ret, mes);
             log_file_date("%s:bad rc[%s] from 'sloc_delete'", mname, mes);
             }

       sys_log_hostname[0] = EOS;
       sys_log_port = 0;

       if ((ret = sloc_find(SYS_LOG_SERVICE_NAME, sys_log_hostname, &sys_log_port,
           (char *)NULL)) != SL_OK)
          {
          sl_code_string(ret, mes);
          log_file_date("%s:bad rc[%s] from 'sloc_find'", mname, mes);
          return(SYS_LOG_NO_SERVER);
          }

       if ((ret = sys_log_client_connect()) != SYS_LOG_OK)
          {
          sys_log_code_string(ret, mes);
          log_file_date("%s:bad rc[%s] from 'sys_log_client_connect'", mname,
                        mes);
          return(ret);
          }

       log_file_date("%s:normal exit,rc[0]", mname);
       return(SYS_LOG_OK);
    }
    #endif

    static int sys_log_lsr_code(int typ, char *parm)
    {
       /* Send and receive a message to the 'sys_log' server that returns
          only a return code. Its ok if 'parm' is NULL or empty.
          Function returns a 'sys_log' code. Private function. */

       char *mess, *qparm, mname[] = "sys_log_lsr_code";
       char tmp[256];
       int len, full_len, ret;

    #ifdef IPC_QNX
       int i, sent = FALSE;
    #endif

       sys_log_header(mname);

       /* make sure server specs are present */

    #ifdef IPC_TCP
       if (!sys_log_port || sys_log_hostname == (char *)NULL ||
           !strlen(sys_log_hostname))
    #else
       if (sys_log_pid == -1)
    #endif
          {
          log_file_date("%s:sys_log server host empty or port zero", mname);
          return(SYS_LOG_NO_INIT);
          }

       /* estimate length and alloc send/receive buffer */

       len = (parm == (char *)NULL) ? 0 : strlen(parm);
       full_len = len + 6;

       /* quote 'parm' if necessary */

       if (len)
          {
          if ((qparm = initqstring(parm)) == (char *)NULL)
             {
             // leave socket open

             log_file_date("%s:alloc fail[qparm]", mname);
             return(SYS_LOG_ALLOC_FAIL);
             }

          log_file_date("%s:qparm=%s,%d", mname, qparm, strlen(qparm));
          }

       if ((mess = (char *)malloc(full_len)) == (char *)NULL)
          {
          if (len)
             free(qparm);

          // leave socket open

          log_file_date("%s:alloc fail[mess]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       memset(mess, 0, full_len);

       /* format send string */

       if (!len)
          sprintf(mess, "%d", typ);
       else
          {
          sprintf(mess, "%d %s", typ, qparm);
          free(qparm);
          }

       log_file_date("%s:mess=%s,%d", mname, mess, strlen(mess));

       /* send message */

    #ifdef IPC_QNX
       if ((qparm = (char *)malloc(full_len)) == NULL)
          {
          free(mess);
          log_file_date("%s:alloc fail[mess]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       for(i = 0; i < IPC_SEND_RETRY; i++)
          if (!Send(sys_log_pid, mess, qparm, strlen(mess) + 1, full_len))
             {
             sent = TRUE;
             break;
             }

       if (!sent)
          {
          free(qparm);
          free(mess);
          log_file_date("%s:virtual circuit communication error", mname);
          return(SYS_LOG_VC_ERROR);
          }

       strcpy(mess, qparm);
       free(qparm);
    #else
       if (!ipc_send(sl_clientSocket, mess))
          {
          // leave socket open, it will be closed by 'sys_log_failover'

          free(mess);
          log_file_date("%s:socket error sending message", mname);
          return(SYS_LOG_VC_ERROR);
          }

       log_file_date("%s:message sent successfully", mname);
       memset(mess, 0, full_len);

       /* receive return code */

       if (!ipc_recv(sl_clientSocket, mess))
          {
          // leave socket open, it will be closed by 'sys_log_failover'

          log_file_date("%s:socket error receiving message", mname);
          free(mess);
          return(SYS_LOG_VC_ERROR);
          }
    #endif

       log_file_date("%s:message received successfully,mess=%s,%d", mname,
                      mess, strlen(mess));

       /* make sure its a number */

       if (!qatoi(mess, &ret))
          {
          // leave socket still connected

          free(mess);
          log_file_date("%s:bad rc[FALSE] from qatoi[mess,ret]", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       sys_log_code_string(ret, tmp);
       log_file_date("%s:server rc[%s]", mname, tmp);
       free(mess);
       log_file_date("%s:normal exit[%d]", mname, ret);
       return(ret);
    }

    static int sys_log_lsr_char(int typ, char *parm, char *char_out)
    {
       /* Send and recveive a message to the 'sys_log' server that
          returns a string as well as a return code. 'char_out' must
          already be allocated to sufficient size for the receiving string.
          Its ok if 'parm' is NULL or empty. Function returns a
          'sys_log' code. Private function. */

       char *mess, *qparm, tmp[50];
       char mname[] = "sys_log_lsr_char";
       int len, full_len, nwords, pos, ret;

    #ifdef IPC_QNX
       int i, sent = FALSE;
    #endif

       /* make sure server specs are present */

    #ifdef IPC_TCP
       if (!sys_log_port || sys_log_hostname == (char *)NULL ||
           !strlen(sys_log_hostname))
    #else
       if (sys_log_pid == -1)
    #endif
          {
          log_file_date("%s:sys_log interface not initialized", mname);
          return(SYS_LOG_NO_INIT);
          }

       char_out[0] = EOS;

       /* estimate length and alloc send/receive buffer */

       len = (parm == (char *)NULL) ? 0 : strlen(parm);
       full_len = len + 6;

       /* quote 'parm' if necessary */

       if (len)
          if ((qparm = initqstring(parm)) == (char *)NULL)
             {
             // leave socket open

             log_file_date("%s:alloc fail[qparm]", mname);
             return(SYS_LOG_ALLOC_FAIL);
             }

       if ((mess = (char *)malloc(full_len)) == (char *)NULL)
          {
          if (len)
             free(qparm);

          // leave socket open

          log_file_date("%s:alloc fail[mess]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       memset(mess, 0, full_len);

       /* format send string */

       if (parm == (char *)NULL || !len)
          sprintf(mess, "%d", typ);
       else
          {
          sprintf(mess, "%d %s", typ, qparm);
          free(qparm);
          }

       /* send message */

    #ifdef IPC_QNX
       if ((qparm = (char *)malloc(SYS_LOG_MAXMES)) == NULL)
          {
          free(mess);
          log_file_date("%s:alloc fail[qparm]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       for(i = 0; i < IPC_SEND_RETRY; i++)
          if (!Send(sys_log_pid, mess, qparm, strlen(mess) + 1, SYS_LOG_MAXMES - 1))
             {
             sent = TRUE;
             break;
             }

       if (!sent)
          {
          free(qparm);
          free(mess);
          log_file_date("%s:virtual circuit communication error", mname);
          return(SYS_LOG_VC_ERROR);
          }

       strcpy(mess, qparm);
       free(qparm);
    #else
       if (!ipc_send(sl_clientSocket, mess))
          {
          // leave socket open, it will be closed by 'sys_log_failover'

          free(mess);
          log_file_date("%s:bad rc[FALSE] from ipc_send", mname);
          return(SYS_LOG_VC_ERROR);
          }

       free(mess);

       /* re-allocate 'mess' for receive buffer (max size) */

       if ((mess = (char *)malloc(SYS_LOG_MAXMES)) == (char *)NULL)
          {
          // leave socket open

          log_file_date("%s:alloc fail[mess]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       memset(mess, 0, SYS_LOG_MAXMES);

       /* receive reply */

       if (!ipc_recv(sl_clientSocket, mess))
          {
          // leave socket open, it will be closed by 'sys_log_failover'

          free(mess);
          log_file_date("%s:bad rc[FALSE] from ipc_recv", mname);
          return(SYS_LOG_VC_ERROR);
          }
    #endif

       /* s/b two words in reply */

       nwords = command_words(mess);

       /* s/b reply code in word one */

       if (!command_word(mess, tmp, 1))
          {
          // leave socket open

          free(mess);
          log_file_date("%s:bad rc[FALSE] from command_word[1]", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       /* make sure its a number */

       if (!qatoi(tmp, &ret))
          {
          // leave socket open

          free(mess);
          log_file_date("%s:bad rc[FALSE] from qatoi[1]", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       /* if reply is 'ok', load 'char_out' */

       if (ret == SYS_LOG_OK)
          {
          if (nwords < 2)
             {
             // leave socket open

             free(mess);
             log_file_date("%s:less than two words in reply", mname);
             return(SYS_LOG_INTERNAL_ERROR);
             }

          /* 'char_value' is from the end of the first word */

          if ((pos = command_indxword(mess, 2)) == -1)
             {
             // leave socket open

             free(mess);
             log_file_date("%s:bad rc[-1] from command_indxword[2]", mname);
             return(SYS_LOG_INTERNAL_ERROR);
             }

          /* if second command word starts with quote backup one */

          if (mess[pos - 1] == '\'' || mess[pos - 1] == '"')
             pos -= 1;

          len = strlen(mess) - pos;
          strncpy(char_out, &mess[pos], len);
          char_out[len] = EOS;
          }

       free(mess);
       return(ret);
    }

    static int sys_log_lsr_long(int typ, char *parm, long *long_out)
    {
       /* Send and recveive a message to the 'sys_log' server that
          returns a long integer as well as a return code.
          Its ok if 'parm' is NULL or empty. Function returns a
          'sys_log' code. Private function. */

       char *mess, *qparm, tmp[50];
       char mname[] = "sys_log_lsr_long";
       int len, full_len, nwords, pos, ret;

    #ifdef IPC_QNX
       int i, sent = FALSE;
    #endif

       /* make sure server specs are present */

    #ifdef IPC_TCP
       if (!sys_log_port || sys_log_hostname == (char *)NULL ||
           !strlen(sys_log_hostname))
    #else
       if (sys_log_pid == -1)
    #endif
          {
          log_file_date("%s:sys_log interface not initialized", mname);
          return(SYS_LOG_NO_INIT);
          }

       *long_out = 0L;

       /* estimate length and alloc send/receive buffer */

       len = (parm == (char *)NULL) ? 0 : strlen(parm);
       full_len = len + 6;

       /* quote 'parm' if necessary */

       if (len)
          if ((qparm = initqstring(parm)) == (char *)NULL)
             {
             log_file_date("%s:alloc fail[qparm]", mname);
             return(SYS_LOG_ALLOC_FAIL);
             }

       if ((mess = (char *)malloc(full_len)) == (char *)NULL)
          {
          if (len)
             free(qparm);

          log_file_date("%s:alloc fail[mess]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       memset(mess, 0, full_len);

       /* format send string */

       if (parm == (char *)NULL || !len)
          sprintf(mess, "%d", typ);
       else
          {
          sprintf(mess, "%d %s", typ, qparm);
          free(qparm);
          }

       /* send message */

    #ifdef IPC_QNX
       if ((qparm = (char *)malloc(SYS_LOG_MAXMES)) == NULL)
          {
          log_file_date("%s:alloc fail[qparm]", mname);
          free(mess);
          return(SYS_LOG_ALLOC_FAIL);
          }

       for(i = 0; i < IPC_SEND_RETRY; i++)
          if (!Send(sys_log_pid, mess, qparm, strlen(mess) + 1, SYS_LOG_MAXMES - 1))
             {
             sent = TRUE;
             break;
             }

       if (!sent)
          {
          free(qparm);
          free(mess);
          log_file_date("%s:virtual circuit communication error", mname);
          return(SYS_LOG_VC_ERROR);
          }

       strcpy(mess, qparm);
       free(qparm);
    #else
       if (!ipc_send(sl_clientSocket, mess))
          {
          // leave socket open, it will be closed by 'sys_log_failover'

          free(mess);
          log_file_date("%s:bad rc[FALSE] from ipc_send", mname);
          return(SYS_LOG_VC_ERROR);
          }

       free(mess);

       /* re-allocate 'mess' for receive buffer (max size) */

       if ((mess = (char *)malloc(SYS_LOG_MAXMES)) == (char *)NULL)
          {
          // leave socket open

          log_file_date("%s:alloc fail[mess]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       memset(mess, 0, SYS_LOG_MAXMES);

       /* receive reply */

       if (!ipc_recv(sl_clientSocket, mess))
          {
          // leave socket open, it will be closed by 'sys_log_failover'

          free(mess);
          log_file_date("%s:bad rc[FALSE] from ipc_recv", mname);
          return(SYS_LOG_VC_ERROR);
          }
    #endif

       /* s/b two words in reply */

       nwords = words(mess);

       /* s/b reply code in word one */

       if (!word(mess, tmp, 1))
          {
          // leave socket open

          free(mess);
          log_file_date("%s:bad rc[FALSE] from word[1]", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       /* make sure its a number */

       if (!qatoi(tmp, &ret))
          {
          // leave socket open

          free(mess);
          log_file_date("%s:bad rc[FALSE] from qatoi[1]", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       /* if reply is 'ok', load 'long_out' */

       if (ret == SYS_LOG_OK)
          {
          if (nwords < 2)
             {
             free(mess);
             log_file_date("%s:less than two words in reply", mname);
             return(SYS_LOG_INTERNAL_ERROR);
             }

          if (!word(mess, tmp, 2))
             {
             free(mess);
             log_file_date("%s:bad rc[FALSE] from word[2]", mname);
             return(SYS_LOG_INTERNAL_ERROR);
             }

          /* make sure its a number */

          if (!qatol(tmp, long_out))
             {
             free(mess);
             log_file_date("%s:bad rc[FALSE] from qatol[2]", mname);
             return(SYS_LOG_INTERNAL_ERROR);
             }
          }

       free(mess);
       return(ret);
    }

    static int sys_log_lsr_int(int typ, char *parm, int *int_out)
    {
       /* Send and recveive a message to the 'sys_log' server that
          returns an integer as well as a return code.
          Its ok if 'parm' is NULL or empty. Function returns a
          'sys_log' code. Private function. */

       char *mess, *qparm, tmp[50];
       char mname[] = "sys_log_lsr_int";
       int len, full_len, nwords, pos, ret;

    #ifdef IPC_QNX
       int i, sent = FALSE;
    #endif

       /* make sure server specs are present */

    #ifdef IPC_TCP
       if (!sys_log_port || sys_log_hostname == (char *)NULL ||
           !strlen(sys_log_hostname))
    #else
       if (sys_log_pid == -1)
    #endif
          {
          log_file_date("%s:sys_log interface not initialized", mname);
          return(SYS_LOG_NO_INIT);
          }

       *int_out = 0;

       /* estimate length and alloc send/receive buffer */

       len = (parm == (char *)NULL) ? 0 : strlen(parm);
       full_len = len + 6;

       /* quote 'parm' if necessary */

       if (len)
          if ((qparm = initqstring(parm)) == (char *)NULL)
             {
             log_file_date("%s:alloc fail[qparm]", mname);
             return(SYS_LOG_ALLOC_FAIL);
             }

       if ((mess = (char *)malloc(full_len)) == (char *)NULL)
          {
          if (len)
             free(qparm);

          log_file_date("%s:alloc fail[mess]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       memset(mess, 0, full_len);

       /* format send string */

       if (parm == (char *)NULL || !len)
          sprintf(mess, "%d", typ);
       else
          {
          sprintf(mess, "%d %s", typ, qparm);
          free(qparm);
          }

       /* send message */

    #ifdef IPC_QNX
       if ((qparm = (char *)malloc(SYS_LOG_MAXMES)) == NULL)
          {
          log_file_date("%s:alloc fail[qparm]", mname);
          free(mess);
          return(SYS_LOG_ALLOC_FAIL);
          }

       for(i = 0; i < IPC_SEND_RETRY; i++)
          if (!Send(sys_log_pid, mess, qparm, strlen(mess) + 1, SYS_LOG_MAXMES - 1))
             {
             sent = TRUE;
             break;
             }

       if (!sent)
          {
          free(qparm);
          free(mess);
          log_file_date("%s:virtual circuit communication error", mname);
          return(SYS_LOG_VC_ERROR);
          }

       strcpy(mess, qparm);
       free(qparm);
    #else
       if (!ipc_send(sl_clientSocket, mess))
          {
          free(mess);
          log_file_date("%s:bad rc[FALSE] from ipc_send", mname);
          return(SYS_LOG_VC_ERROR);
          }

       free(mess);

       /* re-allocate 'mess' for receive buffer (max size) */

       if ((mess = (char *)malloc(SYS_LOG_MAXMES)) == (char *)NULL)
          {
          log_file_date("%s:alloc fail[mess]", mname);
          return(SYS_LOG_ALLOC_FAIL);
          }

       memset(mess, 0, SYS_LOG_MAXMES);

       /* receive reply */

       if (!ipc_recv(sl_clientSocket, mess))
          {
          free(mess);
          log_file_date("%s:bad rc[FALSE] from ipc_recv", mname);
          return(SYS_LOG_VC_ERROR);
          }
    #endif

       /* s/b two words in reply */

       nwords = words(mess);

       /* s/b reply code in word one */

       if (!word(mess, tmp, 1))
          {
          free(mess);
          log_file_date("%s:bad rc[FALSE] from word[1]", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       /* make sure its a number */

       if (!qatoi(tmp, &ret))
          {
          free(mess);
          log_file_date("%s:bad rc[FALSE] from qatoi[1]", mname);
          return(SYS_LOG_INTERNAL_ERROR);
          }

       /* if reply is 'ok', load 'int_out' */

       if (ret == SYS_LOG_OK)
          {
          if (nwords < 2)
             {
             free(mess);
             log_file_date("%s:less than two words in reply", mname);
             return(SYS_LOG_INTERNAL_ERROR);
             }

          if (!word(mess, tmp, 2))
             {
             free(mess);
             log_file_date("%s:bad rc[FALSE] from word[2]", mname);
             return(SYS_LOG_INTERNAL_ERROR);
             }

          /* make sure its a number */

          if (!qatoi(tmp, int_out))
             {
             free(mess);
             log_file_date("%s:bad rc[FALSE] from qatol[2]", mname);
             return(SYS_LOG_INTERNAL_ERROR);
             }
          }

       free(mess);
       return(ret);
    }

    #ifdef IPC_TCP
    static int sys_log_client_connect(void)
    {
       /* Connect to the 'sys_log' server. An attempt to open the TCP
          socket is made. Function returns a 'sys_log' code. Private
          function. */

       char mname[] = "sys_log_client_connect", mes[128];

       sys_log_header(mname);

       if (sys_log_is_connect)
          {
          log_file_date("%s:already connected", mname);
          return(SYS_LOG_OK);
          }

       // resolve server host name

       sl_lpHostEnt = gethostbyname(sys_log_hostname);

       if (!sl_lpHostEnt)
          {
          log_file_date("%s:unable to resolve sys_log server host name", mname);
          return(SYS_LOG_VC_ERROR);
          }

       // create the socket

    #ifdef OS_WIN32
       sl_clientSocket = socket(PF_INET, SOCK_STREAM, DEFAULT_PROTOCOL);
    #endif

    #ifdef OS_UNIX
       sl_clientSocket = socket(AF_INET, SOCK_STREAM, DEFAULT_PROTOCOL);
    #endif

       if (sl_clientSocket == INVALID_SOCKET)
          {
          log_file_date("%s:unable to open the sys_log server socket", mname);
          return(SYS_LOG_VC_ERROR);
          }

       // load client address data
       memset(&sl_sockClientAddr, 0, sizeof(sl_sockClientAddr));
       sl_sockClientAddr.sin_family = AF_INET;
       sl_sockClientAddr.sin_port = htons(sys_log_port);

    #ifdef OS_WIN32
       sl_sockClientAddr.sin_addr = *((LPIN_ADDR)*sl_lpHostEnt->h_addr_list);
    #endif

    #ifdef OS_UNIX
       sl_sockClientAddr.sin_addr.s_addr = ((struct in_addr *)(sl_lpHostEnt->h_addr))->s_addr;
    #endif

       // connect to server

    #ifdef OS_WIN32
       if (connect(sl_clientSocket, (LPSOCKADDR)&sl_sockClientAddr,
           sizeof(sl_sockClientAddr)))
    #endif

    #ifdef OS_UNIX
       if (connect(sl_clientSocket, (SA *)&sl_sockClientAddr,
           sizeof(sl_sockClientAddr)) == SOCKET_ERROR)
    #endif
          {
          log_file_date("%s:error connecting the socket to the sys_log "
                        "server", mname);
          return(SYS_LOG_VC_ERROR);
          }

       sys_log_is_connect = TRUE;
       log_file_date("%s:normal exit[%d]", mname, SYS_LOG_OK);
       return(SYS_LOG_OK);
    }
    #endif

    static void sys_log_header(char *mname)
    {
       /* Start of function logging header. */

       if (!is_log_active())
          return;

    #ifdef IPC_TCP
       if (sys_log_port == 0 || !strlen(sys_log_hostname))
          return;

       log_file_date("%s:enter:host=%s,port=%d", mname, sys_log_hostname,
                     sys_log_port);
    #else
       log_file_date("%s:enter", mname);
    #endif
    }

/* [<][>][^][v][top][bottom][index][help] */