root/usr/src/cmd/dcs/sparc/sun4u/dcs_msg.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2000 by Sun Microsystems, Inc.
 * All rights reserved.
 */

/*
 * This file is a module that handles the logging features of the
 * DCS. All error messages that are generated by the DCS are kept in
 * a static array and accessed through one of the access functions
 * defined in this file.
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <syslog.h>
#include <libintl.h>

#include "dcs.h"


#define SYSLOG_FMT      "<%d> %s"


/*
 * This is an array of strings representing all of the error and
 * informational messages that are used by the DCS. This includes
 * messages that are logged using syslog(3C) and those that are
 * displayed to the user through a message callback.
 */
static const char *dcs_err_fmt[] = {

        /*
         * Network Errors:
         */
        /* DCS_INIT_ERR     */ "network initialization failed",
        /* DCS_NO_PORT      */ "failed to acquire reserved port",
        /* DCS_CONNECT_ERR  */ "connection attempt failed",
        /* DCS_RECEIVE_ERR  */ "unable to receive message",
        /* DCS_OP_REPLY_ERR */ "unable to send message for %s operation",
        /* DCS_NO_SERV      */ "%s service not found, using reserved port 665",
        /* DCS_DISCONNECT   */ "client disconnected",

        /*
         * Session Errors:
         */
        /* DCS_SES_HAND_ERR */ "failed to start a new session handler",
        /* DCS_ABORT_ERR    */ "abort attempt of session, %d, unsuccessful",
        /* DCS_VER_INVAL    */ "unsupported message protocol version %d.%d",
        /* DCS_SES_ABORTED  */ "session aborted",

        /*
         * DR Request Errors:
         */
        /* DCS_UNKNOWN_OP   */ "unknown operation requested",
        /* DCS_OP_FAILED    */ "operation failed",
        /* DCS_SEQ_INVAL    */ "invalid session establishment sequence",
        /* DCS_NO_SES_ESTBL */ "%s operation issued before session established",
        /* DCS_MSG_INVAL    */ "received an invalid message",
        /* DCS_CONF_CB_ERR  */ "confirm callback failed, aborting operation",
        /* DCS_MSG_CB_ERR   */ "message callback failed, continuing",
        /* DCS_BAD_RETRY    */ "retry value invalid (%d)",
        /* DCS_BAD_TIMEOUT  */ "timeout value invalid (%d)",
        /* DCS_RETRY        */ "retrying operation, attempt %d",

        /*
         * General Errors:
         */
        /* DCS_NO_PRIV      */ "permission denied",
        /* DCS_INT_ERR      */ "internal error: %s: %s",
        /* DCS_UNKNOWN_ERR  */ "unrecognized error reported",
        /* DCS_BAD_OPT      */ "illegal option (-%c), exiting",
        /* DCS_BAD_OPT_ARG  */ "illegal argument to -%c flag (%s), %s",
        /* DCS_CFGA_UNKNOWN */ "configuration administration unknown error",
        /* DCS_CFGA_ERR     */ "%s: %s",
        /* DCS_RSRC_ERR     */ "resource info init error (%d)",
        /* DCS_MSG_COUNT    */ NULL
};


/*
 * dcs_log_msg:
 *
 * Based on an error code, construct an error string and output it to
 * a logfile using syslog(3C). Note that the string will not be localized.
 */
void
dcs_log_msg(int priority, int err_code, ...)
{
        va_list vap;
        char    err_str[MAX_MSG_LEN];
        char    syslog_str[MAX_MSG_LEN];


        /* check if error code is out of bounds */
        if ((err_code < 0) || (err_code >= DCS_MSG_COUNT)) {
                syslog(LOG_NOTICE, dcs_err_fmt[DCS_UNKNOWN_ERR]);
                return;
        }

        va_start(vap, err_code);
        (void) vsnprintf(err_str, MAX_MSG_LEN, dcs_err_fmt[err_code], vap);
        va_end(vap);

        /* prepend session identifier */
        snprintf(syslog_str, MAX_MSG_LEN, SYSLOG_FMT, curr_ses_id(), err_str);

        syslog(priority, syslog_str);

        if (standalone) {
                fprintf(stderr, "%s\n", syslog_str);
        }
}


/*
 * dcs_strerror:
 *
 * Return the format string associated with a supplied DCS specific
 * error code. dgettext(3C) is used to retrieve the localized version
 * of the format string.
 */
const char *
dcs_strerror(int err_code)
{
        /* check if code is out of bounds */
        if ((err_code < 0) || (err_code >= DCS_MSG_COUNT)) {
                return (dgettext(TEXT_DOMAIN, dcs_err_fmt[DCS_UNKNOWN_ERR]));
        }

        return (dgettext(TEXT_DOMAIN, dcs_err_fmt[err_code]));
}


/*
 * dcs_cfga_str:
 *
 * Assemble a string that describes a particular libcfgadm error code.
 * This string will contain both the platform dependent and platform
 * independent message strings available from a libcfgadm function call.
 * The resulting string will be localized indirectly through the call
 * to config_strerror() and the localized error string returned from
 * the libcfgadm operation.
 */
char *
dcs_cfga_str(char **err_strp, int err_code)
{
        const char      *ep;
        char            *buf;
        char            *err_str;


        /*
         * Extract the platform specific message passed as
         * a parameter, or use NULL to signal that no error
         * string was passed.
         */
        if (err_strp && *err_strp) {
                err_str = *err_strp;
        } else {
                err_str = NULL;
        }

        buf = (char *)malloc(MAX_MSG_LEN);

        if (buf == NULL) {
                dcs_log_msg(LOG_ERR, DCS_INT_ERR, "malloc", strerror(errno));
                return (NULL);
        }

        /* get the platform independent message */
        ep = config_strerror(err_code);

        if (ep == NULL) {
                ep = dgettext(TEXT_DOMAIN, dcs_err_fmt[DCS_CFGA_UNKNOWN]);
        }

        /*
         * Check if a platform specific message was provided, and
         * generate the appropriate message.
         */
        if ((err_str != NULL) && (*err_str != '\0')) {
                snprintf(buf, MAX_MSG_LEN, "%s: %s\n", ep, err_str);
        } else {
                snprintf(buf, MAX_MSG_LEN, "%s\n", ep);
        }

        return (buf);
}


/*
 * dcs_dbg:
 *
 * Output a debugging message to a logfile using syslog(3C). The bits
 * in the debug mask specify the category of the message. They have
 * the following meanings:
 *
 *              0x1 - the string contains basic information
 *              0x2 - the string contains message information
 *              0x4 - the string contains session information
 *              0x8 - the string contains state information
 *
 * The debug mask is compared to the global value of dcs_debug which is
 * set through a command line option. This determines whether or not
 * to output the message to the logfile.
 */
void
dcs_dbg(int dbg_mask, char *fmt, ...)
{
        va_list         vap;
        char            err_str[MAX_MSG_LEN];
        char            syslog_str[MAX_MSG_LEN];


        if ((dcs_debug & dbg_mask) == 0) {
                return;
        }

        va_start(vap, fmt);
        (void) vsnprintf(err_str, MAX_MSG_LEN, fmt, vap);
        va_end(vap);

        /* prepend session identifier */
        snprintf(syslog_str, MAX_MSG_LEN, SYSLOG_FMT, curr_ses_id(), err_str);

        syslog(LOG_DEBUG, syslog_str);

        if (standalone) {
                fprintf(stderr, "%s\n", syslog_str);
        }
}


/*
 * print_msg_hdr:
 *
 * Print selected information from the header for a given message. The
 * information logged includes the information needed to track the flow
 * of messages: opcode, send/receive, request/reply, and success/failure.
 */
void
print_msg_hdr(dcs_msg_type_t type, rdr_msg_hdr_t *hdr)
{
        static char *type_str[] = {
                "INVALID TYPE",
                "RDR_REQUEST",
                "RDR_REPLY"
        };

        static char *op_str[] = {
                "RDR_INVALID_OP",
                "RDR_SES_REQ",
                "RDR_SES_ESTBL",
                "RDR_SES_END",
                "RDR_CONF_CHANGE_STATE",
                "RDR_CONF_PRIVATE_FUNC",
                "RDR_CONF_TEST",
                "RDR_CONF_LIST_EXT",
                "RDR_CONF_HELP",
                "RDR_CONF_AP_ID_CMP",
                "RDR_CONF_ABORT_CMD",
                "RDR_CONF_CONFIRM_CALLBACK",
                "RDR_CONF_MSG_CALLBACK",
                "RDR_RSRC_INFO"
        };

        assert(hdr);

        /* clamp an invalid opcode */
        if (hdr->message_opcode >= RDR_NUM_OPS) {
                hdr->message_opcode = 0;
        }

        /* clamp an invalid type */
        if (hdr->data_type > RDR_REPLY) {
                hdr->data_type = 0;
        }

        DCS_DBG(DBG_MSG, "message %s: <%s, %s%s>",
            (type == DCS_RECEIVE) ? "received" : "sent",
            op_str[hdr->message_opcode],
            type_str[hdr->data_type],
            ((hdr->data_type == RDR_REQUEST) ||
            (hdr->message_opcode == RDR_CONF_AP_ID_CMP)) ? "" :
            (hdr->status == RDR_SUCCESS) ? ", RDR_SUCCESS" :
            ", RDR_FAILED");
}