OpenSolaris_b135/cmd/mms/mm/common/mm_msg.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <sys/types.h>
#include <mms_list.h>
#include <mms_parser.h>
#include <libpq-fe.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <libintl.h>
#include <locale.h>
#include <ctype.h>
#include <mms_trace.h>
#include <mms_strapp.h>
#include <msg_sub.h>
#include <mms_cat.h>
#include "mm_db.h"
#include "mm.h"
#include "mm_util.h"
#include "mm_commands.h"
#include "mm_sql.h"
#include "mm_sql_impl.h"

static char *_SrcFile = __FILE__;
#define	NOT_FOUND() goto not_found

#define	MESS_EMERG_STR		"emergency"
#define	MESS_ALERT_STR		"alert"
#define	MESS_CRIT_STR		"critical"
#define	MESS_ERROR_STR		"error"
#define	MESS_WARN_STR		"warning"
#define	MESS_NOTICE_STR		"notice"
#define	MESS_INFO_STR		"information"
#define	MESS_DEBUG_STR		"debug"
#define	MESS_DEVP_STR		"developer"

#define	MESS_OPER_STR		"operator"
#define	MESS_ADMIN_STR		"administrator"
#define	MESS_LOG_STR		"log"

typedef struct {
	char		*msg_client;
	char		*msg_instance;
	char		*msg_host;

	int		slog_fd;
	char		slog_fname[PATH_MAX];
	uint64_t	slog_size;
	int		slog_sync;
	int		slog_count;
	mm_msg_sev_t	slog_level;
	uint64_t	slog_rot_size;
	pthread_mutex_t	slog_mutex;
} mm_msg_data_t;

/* message */
static int mm_msg_add_private(mm_wka_t *mm_wka, char *client, char *inst);
static int mm_msg_avail(mm_command_t *cmd);
static int mm_msg_fifo(mm_db_t *db, mm_msg_t *mess);

/* system log file */
static int mm_slog_open(mm_db_t *db);
static void mm_slog_close(void);
static void mm_slog_flush(void);
static int mm_slog(mm_msg_t *mess);

/* utility */
static char *mm_msg_sev2str(mm_msg_sev_t severity);
static mm_msg_sev_t mm_msg_str2sev(char *serverity);
static char *mm_msg_who2str(mm_msg_who_t who);
static mm_msg_who_t mm_msg_str2who(char *who);
static void mm_get_timestamp(mm_db_t *db, char *timestamp);

static mm_msg_data_t mm_msg_data;

int
mm_message_init(mm_db_t *db, mm_data_t *data)
{
	mms_cat_open();
	(void) setlocale(LC_MESSAGES, "");

	memset(&mm_msg_data, 0, sizeof (mm_msg_data_t));
	mm_msg_data.msg_client = data->mm_cfg.mm_network_cfg.cli_name;
	mm_msg_data.msg_instance = data->mm_cfg.mm_network_cfg.cli_inst;
	mm_msg_data.msg_host = data->mm_host_name;
	pthread_mutex_init(&mm_msg_data.slog_mutex, NULL);
	if (mm_slog_open(db)) {
		mms_trace(MMS_ERR, "unable to open system log file");
		return (1);
	}
	return (0);
}

void
mm_message_close(void)
{
	mm_slog_close();
	pthread_mutex_destroy(&mm_msg_data.slog_mutex);
	memset(&mm_msg_data, 0, sizeof (mm_msg_data_t));
	mm_msg_data.slog_fd = -1;
}

int
mm_msg_tracing_cmd_func(mm_wka_t *mm_wka, mm_command_t *cmd)
{
	mm_response_t	response;

	mms_trace(MMS_DEVP,
	    "mm_msg_tracing_cmd_func, state %d", cmd->cmd_state);

	/*
	 * Handle device manager change tracing private command
	 */

	if (cmd->cmd_state == 0) {
		mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_textcmd);
		mms_trace(MMS_DEVP, "set tracing sent");
		cmd->cmd_flags |= MM_CMD_NEED_ACCEPT;
		cmd->cmd_state = 1;
		return (MM_ACCEPT_NEEDED);
	} else if (cmd->cmd_state == 1) {
		if (mm_parse_response(cmd->cmd_response, &response) == 0 &&
		    response.response_type == MM_RESPONSE_ACCEPTED) {
			mms_trace(MMS_DEVP, "set tracing accepted");
			cmd->cmd_flags &= ~MM_CMD_NEED_ACCEPT;
			cmd->cmd_flags |= MM_CMD_ACCEPTED;
			cmd->cmd_state = 2;
			return (MM_NO_DISPATCH);
		}
	} else if (cmd->cmd_state == 2) {
		if (mm_parse_response(cmd->cmd_response, &response) == 0 &&
		    response.response_type == MM_RESPONSE_SUCCESS) {
			mms_trace(MMS_DEVP, "set tracing success");
			cmd->cmd_remove = 1;
			if (mm_has_depend(cmd)) {
				return (MM_DEPEND_DONE);
			}
			return (MM_CMD_DONE);
		}
		mms_trace(MMS_DEVP, "set tracing failed");
		cmd->cmd_remove = 1;
		return (MM_CMD_ERROR);
	}
	mms_trace(MMS_DEVP, "set tracing state");
	cmd->cmd_remove = 1;
	return (MM_CMD_ERROR);
}

int
mm_msg_send_tracing(mm_wka_t *mm_wka)
{
	mm_db_t		*db = &mm_wka->mm_data->mm_db;
	cci_t		*conn = &mm_wka->wka_conn;
	uuid_text_t	task;
	char		*buf;
	mm_command_t	*pvt_cmd;

	/*
	 * Add change tracing private command to command queue
	 */

	if (mm_wka->mm_wka_mm_lang == MM_LANG_LMP) {

		mms_trace(MMS_DEVP, "Set lmp tracing");

		if (mm_db_exec(HERE, db, "select \"LMMessageLevel\","
		    "\"TraceLevel\",\"TraceFileSize\" from \"LM\" where "
		    "\"LMName\" = '%s';", conn->cci_instance) != MM_DB_DATA) {
			mm_clear_db(&db->mm_db_results);
			return (1);
		}
		if (PQntuples(db->mm_db_results) != 1) {
			mm_clear_db(&db->mm_db_results);
			return (1);
		}

		mm_get_uuid(task);

		buf = mms_strnew("private task[\"%s\"] "
		    "set[\"LMMessageLevel\" \"%s\" "
		    "\"TraceLevel\" \"%s\" "
		    "\"TraceFileSize\" \"%s\"];",
		    task,
		    PQgetvalue(db->mm_db_results, 0, 0),
		    PQgetvalue(db->mm_db_results, 0, 1),
		    PQgetvalue(db->mm_db_results, 0, 2));

		mm_clear_db(&db->mm_db_results);
		pvt_cmd = mm_alloc_cmd(mm_wka);
		pvt_cmd->cmd_textcmd = buf;
		pvt_cmd->cmd_root = mm_text_to_par_node(pvt_cmd->cmd_textcmd,
		    mms_lmpm_parse);
		pvt_cmd->cmd_task = mm_get_task(pvt_cmd->cmd_root);
		pvt_cmd->wka_ptr = mm_wka;
		pvt_cmd->cmd_func = mm_msg_tracing_cmd_func;
		pvt_cmd->cmd_flags = MM_CMD_DISPATCHABLE;
		pvt_cmd->cmd_language = MM_LANG_LMP;
		pvt_cmd->cmd_name = strdup("lmp tracing");

		pthread_mutex_lock(&mm_wka->mm_data->mm_queue_mutex);
		mms_list_insert_tail(&mm_wka->mm_data->mm_cmd_queue, pvt_cmd);
		pthread_mutex_unlock(&mm_wka->mm_data->mm_queue_mutex);

		mms_trace(MMS_DEVP, "Added set lmp tracing");

	} else if (mm_wka->mm_wka_mm_lang == MM_LANG_DMP) {

		mms_trace(MMS_DEVP, "Set dmp tracing");

		if (mm_db_exec(HERE, db, "select \"DMMessageLevel\","
		    "\"TraceLevel\",\"TraceFileSize\" from \"DM\" where "
		    "\"DMName\" = '%s';", conn->cci_instance) != MM_DB_DATA) {
			mm_clear_db(&db->mm_db_results);
			return (1);
		}
		if (PQntuples(db->mm_db_results) != 1) {
			mm_clear_db(&db->mm_db_results);
			return (1);
		}

		mm_get_uuid(task);

		buf = mms_strnew("private task[\"%s\"] "
		    "set[\"DMMessageLevel\" \"%s\" "
		    "\"TraceLevel\" \"%s\" "
		    "\"TraceFileSize\" \"%s\"];",
		    task,
		    PQgetvalue(db->mm_db_results, 0, 0),
		    PQgetvalue(db->mm_db_results, 0, 1),
		    PQgetvalue(db->mm_db_results, 0, 2));

		mm_clear_db(&db->mm_db_results);


		pvt_cmd = mm_alloc_cmd(mm_wka);
		pvt_cmd->cmd_textcmd = buf;
		pvt_cmd->cmd_root = mm_text_to_par_node(pvt_cmd->cmd_textcmd,
		    mms_dmpm_parse);
		pvt_cmd->cmd_task = mm_get_task(pvt_cmd->cmd_root);
		pvt_cmd->wka_ptr = mm_wka;
		pvt_cmd->cmd_func = mm_msg_tracing_cmd_func;
		pvt_cmd->cmd_flags = MM_CMD_DISPATCHABLE;
		pvt_cmd->cmd_language = MM_LANG_DMP;
		pvt_cmd->cmd_name = strdup("dmp tracing");

		pthread_mutex_lock(&mm_wka->mm_data->mm_queue_mutex);
		mms_list_insert_tail(&mm_wka->mm_data->mm_cmd_queue, pvt_cmd);
		pthread_mutex_unlock(&mm_wka->mm_data->mm_queue_mutex);

		mms_trace(MMS_DEVP, "Added set dmp tracing");
	}

	return (0);
}

static int
mm_msg_add_private(mm_wka_t *mm_wka, char *client, char *inst)
{
	mm_wka_t	*cli_wka;
	int		rc = 0;

	/* find client work area */
	mms_list_foreach(&mm_wka->mm_data->mm_wka_list, cli_wka) {

		/* only connected clients have work areas */
		if (strcmp(cli_wka->wka_conn.cci_client, client) == 0 &&
		    strcmp(cli_wka->wka_conn.cci_instance, inst) == 0) {

			/* send private command to change tracing */
			if (rc = mm_msg_send_tracing(cli_wka)) {
				break;
			}
		}
	}
	return (rc);
}

int
mm_msg_set_tracing(mm_wka_t *mm_wka, mm_command_t *cmd, int id)
{
	mm_db_t		*db = &mm_wka->mm_data->mm_db;
	PGresult	*results;
	char		*query;
	int		row;
	char		*client;
	char		*inst;
	char		*level;
	char		*fsize;
	int		num;

	/*
	 * Change mm or device manager tracing
	 */

	if (id == LM) {

		/* clear path matching */
		mm_clear_source(cmd);
		mm_clear_dest(cmd);
		mm_clear_const(cmd);

		/* sql command */
		(void) mm_get_dest(mm_wka, cmd);
		(void) mm_get_const(mm_wka, cmd);
		(void) mm_add_match_list("LM", &cmd->cmd_source_list);
		if (mm_add_char("LM", &cmd->cmd_source_list)) {
			mms_trace(MMS_ERR,
			    "mm_msg_set_tracing: "
			    "out of mem creating source list");
			return (1);
		}

		cmd->cmd_source_num = 1;

		query = "select distinct \"LM\".\"LibraryName\","
		    "\"LM\".\"LMName\" from ";
		SQL_CHK_LEN(&cmd->cmd_buf, 0, &cmd->cmd_bufsize,
		    strlen(query) + 1);
		strcpy(cmd->cmd_buf, query);

		if (mm_sql_from_where(cmd, db)) {
			mms_trace(MMS_ERR,
			    "mm_msg_set_tracing: "
			    "db error creating helper functions");
			return (1);
		}
		mm_sql_order(cmd);
		mm_sql_number(cmd);

		if (mm_db_exec(HERE, db, cmd->cmd_buf) != MM_DB_DATA) {
			mms_trace(MMS_ERR, "lm tracing");
			mm_clear_db(&db->mm_db_results);
			return (1);
		}
		if (PQntuples(db->mm_db_results) < 1) {
			mms_trace(MMS_ERR, "lm tracing results");
			mm_clear_db(&db->mm_db_results);
			/* see if any lms are configed */
			if (mm_db_exec(HERE, db, "select \"LM\".\"LMName\" "
			    "from \"LM\" limit 1;") != MM_DB_DATA) {
				mms_trace(MMS_ERR, "lms configed");
				mm_clear_db(&db->mm_db_results);
				return (1);
			}
			num = PQntuples(db->mm_db_results);
			PQntuples(db->mm_db_results);
			if (num == 0 && cmd->cmd_dest_num == 0) {
				/* no lms configured or specified */
				return (0);
			}
			/* lm not found */
			return (1);
		}
		results = db->mm_db_results;
		for (row = 0; row < PQntuples(results); row++) {
			client = PQgetvalue(results, row, 0);
			inst = PQgetvalue(results, row, 1);

			mms_trace(MMS_DEVP, "%d of %d - %s %s",
			    row,
			    PQntuples(results),
			    client,
			    inst);

			if (mm_msg_add_private(mm_wka, client, inst)) {
				mm_clear_db(&results);
				return (1);
			}
		}
		mm_clear_db(&results);

	} else if (id == DM) {

		/* clear path matching */
		mm_clear_source(cmd);
		mm_clear_dest(cmd);
		mm_clear_const(cmd);

		/* sql command */
		(void) mm_get_dest(mm_wka, cmd);
		(void) mm_get_const(mm_wka, cmd);
		(void) mm_add_match_list("DM", &cmd->cmd_source_list);
		if (mm_add_char("DM", &cmd->cmd_source_list)) {
			mms_trace(MMS_ERR,
			    "mm_msg_set_tracing: "
			    "out of mem creating source list");
			return (1);
		}
		cmd->cmd_source_num = 1;

		query = "select distinct \"DM\".\"DriveName\","
		    "\"DM\".\"DMName\" from ";
		SQL_CHK_LEN(&cmd->cmd_buf, 0, &cmd->cmd_bufsize,
		    strlen(query) + 1);
		strcpy(cmd->cmd_buf, query);


		if (mm_sql_from_where(cmd, db)) {
			mms_trace(MMS_ERR,
			    "mm_msg_set_tracing: "
			    "db error creating helper functions");
			return (1);
		}
		mm_sql_order(cmd);
		mm_sql_number(cmd);

		if (mm_db_exec(HERE, db, cmd->cmd_buf) != MM_DB_DATA) {
			mms_trace(MMS_ERR, "dm tracing");
			mm_clear_db(&db->mm_db_results);
			return (1);
		}
		if (PQntuples(db->mm_db_results) < 1) {
			mms_trace(MMS_ERR, "dm tracing results");
			mm_clear_db(&db->mm_db_results);
			/* see if any dms are configed */
			if (mm_db_exec(HERE, db, "select \"DM\".\"DMName\" "
			    "from \"DM\" limit 1;") != MM_DB_DATA) {
				mms_trace(MMS_ERR, "dms configed");
				mm_clear_db(&db->mm_db_results);
				return (1);
			}
			num = PQntuples(db->mm_db_results);
			PQntuples(db->mm_db_results);
			if (num == 0 && cmd->cmd_dest_num == 0) {
				/* no dms configed or specified */
				return (0);
			}
			/* dm not found */
			return (1);
		}
		results = db->mm_db_results;
		for (row = 0; row < PQntuples(results); row++) {
			client = PQgetvalue(results, row, 0);
			inst = PQgetvalue(results, row, 1);

			mms_trace(MMS_DEVP, "%d of %d - %s %s",
			    row,
			    PQntuples(results),
			    client,
			    inst);

			if (mm_msg_add_private(mm_wka, client, inst)) {
				mm_clear_db(&results);
				return (1);
			}
		}
		mm_clear_db(&results);

	} else if (id == MM) {

		if (mm_db_exec(HERE, db, "select \"MessageLevel\", "
		    "\"TraceLevel\",\"TraceFileSize\" from \"SYSTEM\";")
		    != MM_DB_DATA) {
			mms_trace(MMS_ERR, "mm tracing");
			mm_clear_db(&db->mm_db_results);
			return (1);
		}
		if (PQntuples(db->mm_db_results) != 1) {
			mms_trace(MMS_ERR, "mm tracing results");
			mm_clear_db(&db->mm_db_results);
			return (1);
		}
		level = PQgetvalue(db->mm_db_results, 0, 1);
		fsize = PQgetvalue(db->mm_db_results, 0, 2);

		if (mms_trace_set_fsize(fsize)) {
			mms_trace(MMS_ERR, "invalid mms_trace fsize %s", fsize);
			return (1);
		}
		if (mms_trace_str_filter(level)) {
			mms_trace(MMS_ERR,
			    "invalid mms_trace filter %s", level);
			return (1);
		}
		mm_write_trace_level(mms_trace_get_severity());
		mm_clear_db(&db->mm_db_results);

	} else {
		mms_trace(MMS_ERR, "invalid id %d", id);
		return (1);
	}

	return (0);

no_mem:
	MM_ABORT_NO_MEM();
	return (1);
}

int
mm_message_cmd_func(mm_wka_t *mm_wka, mm_command_t *cmd)
{
	mm_db_t		*db = &mm_wka->mm_data->mm_db;
	mms_par_node_t	*clause;
	mms_par_node_t	*value;

	mms_trace(MMS_DEVP, "mm_message_cmd_func");

	/*
	 * Device manager message command
	 */

	cmd->cmd_msg.msg_flags |= MESS_FLAG_HANDLED;

	/* message command */
	MMS_PN_LOOKUP(clause, cmd->cmd_root, "who", MMS_PN_CLAUSE, NULL);
	MMS_PN_LOOKUP(value, clause, NULL, MMS_PN_KEYWORD, NULL);
	cmd->cmd_msg.msg_who = mm_msg_str2who(mms_pn_token(value));

	MMS_PN_LOOKUP(clause, cmd->cmd_root, "severity",
	    MMS_PN_CLAUSE, NULL);
	MMS_PN_LOOKUP(value, clause, NULL, MMS_PN_KEYWORD, NULL);
	cmd->cmd_msg.msg_severity = mm_msg_str2sev(mms_pn_token(value));

	if (mm_msg_parse(cmd, cmd->cmd_root)) {
		SQL_CHK_LEN(&cmd->cmd_buf, 0, &cmd->cmd_bufsize,
		    strlen(RESPONSE_ERROR) + strlen(cmd->cmd_task) +
		    strlen(ECLASS_INTERNAL) + strlen(MM_E_CMDARGS) + 1);
		(void) snprintf(cmd->cmd_buf, cmd->cmd_bufsize,
		    RESPONSE_ERROR, cmd->cmd_task,
		    ECLASS_INTERNAL, MM_E_CMDARGS);
		mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
		cmd->cmd_remove = 1;
		return (MM_CMD_ERROR);
	}

	mm_get_timestamp(db, cmd->cmd_msg.msg_timestamp);

	cmd->cmd_msg.msg_client_uuid = cmd->wka_ptr->wka_conn.cci_uuid;
	mm_get_uuid(cmd->cmd_msg.msg_uuid);
	cmd->cmd_msg.msg_type = mm_msg_lang2component(mm_wka->mm_wka_mm_lang);
	cmd->cmd_msg.msg_client = cmd->wka_ptr->wka_conn.cci_client;
	cmd->cmd_msg.msg_instance = cmd->wka_ptr->wka_conn.cci_instance;
	cmd->cmd_msg.msg_cid = cmd->wka_ptr->wka_conn.cci_uuid;
	cmd->cmd_msg.msg_host = cmd->wka_ptr->wka_conn.cci_host;

	/* add message to system log file */
	if (mm_slog(&cmd->cmd_msg)) {
		SQL_CHK_LEN(&cmd->cmd_buf, 0, &cmd->cmd_bufsize,
		    strlen(RESPONSE_ERROR) + strlen(cmd->cmd_task) +
		    strlen(ECLASS_INTERNAL) + strlen(MM_E_INTERNAL) + 1);
		(void) snprintf(cmd->cmd_buf, cmd->cmd_bufsize,
		    RESPONSE_ERROR, cmd->cmd_task,
		    ECLASS_INTERNAL, MM_E_INTERNAL);
		mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
		cmd->cmd_remove = 1;
		return (MM_CMD_ERROR);
	}

	/* add message to message fifo */
	if (mm_msg_fifo(db, &cmd->cmd_msg)) {
		SQL_CHK_LEN(&cmd->cmd_buf, 0, &cmd->cmd_bufsize,
		    strlen(RESPONSE_ERROR) + strlen(cmd->cmd_task) +
		    strlen(ECLASS_INTERNAL) + strlen(MM_E_INTERNAL) + 1);
		(void) snprintf(cmd->cmd_buf, cmd->cmd_bufsize,
		    RESPONSE_ERROR, cmd->cmd_task,
		    ECLASS_INTERNAL, MM_E_INTERNAL);
		mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
		cmd->cmd_remove = 1;
		return (MM_CMD_ERROR);
	}

	SQL_CHK_LEN(&cmd->cmd_buf, 0, &cmd->cmd_bufsize,
	    strlen(RESPONSE_SUCCESS) + strlen(cmd->cmd_task) + 1);
	(void) snprintf(cmd->cmd_buf, cmd->cmd_bufsize,
	    RESPONSE_SUCCESS, cmd->cmd_task);

	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	cmd->cmd_remove = 1;
	return (MM_CMD_DONE);

not_found:
	SQL_CHK_LEN(&cmd->cmd_buf, 0, &cmd->cmd_bufsize,
	    strlen(RESPONSE_ERROR) + strlen(cmd->cmd_task) +
	    strlen(ECLASS_INTERNAL) + strlen(MM_E_CMDARGS) + 1);
	(void) snprintf(cmd->cmd_buf, cmd->cmd_bufsize,
	    RESPONSE_ERROR, cmd->cmd_task,
	    ECLASS_INTERNAL, MM_E_CMDARGS);
	mm_send_text(mm_wka->mm_wka_conn, cmd->cmd_buf);
	cmd->cmd_remove = 1;
	return (MM_CMD_ERROR);

no_mem:
	MM_ABORT_NO_MEM();
	return (MM_CMD_ERROR);
}

static int
mm_msg_avail(mm_command_t *cmd)
{
	/*
	 * Tell caller if command contains message-clause
	 */

	if (mms_pn_lookup(cmd->cmd_root, "message", MMS_PN_CLAUSE, NULL)) {
		return (1); /* command has message-clause */
	}
	return (0);
}

int
mm_message_command(mm_command_t *cmd)
{
	mm_db_t		*db = &cmd->wka_ptr->mm_data->mm_db;
	mm_response_t	response;
	int		rc;

	mms_trace(MMS_DEVP, "mm_msg_command");

	/*
	 * Handle message in non-message command
	 */

	if (cmd->cmd_msg.msg_flags & MESS_FLAG_HANDLED) {
		return (0);	/* already handled this command's message */
	}
	cmd->cmd_msg.msg_flags |= MESS_FLAG_HANDLED;

	if (cmd->wka_ptr->mm_wka_mm_lang == MM_LANG_MMP) {
		return (0);		/* ignore messages in mmp commands */
	}

	if (mm_msg_avail(cmd) == 0)
		return (0);		/* command does not have a message */

	if (mm_msg_parse(cmd, cmd->cmd_root))
		return (0);		/* failed to parse command message */

	if (mm_parse_response(cmd->cmd_root, &response) == 0) {
		/* command response */
		switch (response.response_type) {
		case MM_RESPONSE_ERROR:
			cmd->cmd_msg.msg_severity = MESS_ERROR;
			break;

		case MM_RESPONSE_ACCEPTED:
		case MM_RESPONSE_UNACCEPTABLE:
		case MM_RESPONSE_SUCCESS:
		case MM_RESPONSE_CANCELLED:
		default:
			cmd->cmd_msg.msg_severity = MESS_INFO;
			break;
		}
	} else {
		/* not command response */
		cmd->cmd_msg.msg_severity = MESS_INFO;
	}

	mm_get_timestamp(db, cmd->cmd_msg.msg_timestamp);

	cmd->cmd_msg.msg_client_uuid = cmd->wka_ptr->wka_conn.cci_uuid;
	mm_get_uuid(cmd->cmd_msg.msg_uuid);
	cmd->cmd_msg.msg_type =
	    mm_msg_lang2component(cmd->wka_ptr->mm_wka_mm_lang);
	cmd->cmd_msg.msg_client = cmd->wka_ptr->wka_conn.cci_client,
	    cmd->cmd_msg.msg_instance = cmd->wka_ptr->wka_conn.cci_instance,
	    cmd->cmd_msg.msg_cid = cmd->wka_ptr->wka_conn.cci_uuid;
	cmd->cmd_msg.msg_host = cmd->wka_ptr->wka_conn.cci_host,
	    cmd->cmd_msg.msg_who = MESS_LOG;

	if ((rc = mm_slog(&cmd->cmd_msg)) == 0) {
		rc = mm_msg_fifo(db, &cmd->cmd_msg);
	}

	return (rc);
}

int
mm_message(mm_db_t *db, mm_msg_who_t who, mm_msg_sev_t severity,
    int messageid, ...)
{
	mm_msg_t	mess;
	va_list		args;
	int		rc;

	mms_trace(MMS_DEVP, "mm_message: %s %s %d",
	    mm_msg_who2str(who), mm_msg_sev2str(severity), messageid);

	memset(&mess, 0, sizeof (mm_msg_t));

	mm_get_timestamp(db, mess.msg_timestamp);

	mess.msg_client_uuid = NULL;
	mm_get_uuid(mess.msg_uuid);
	mess.msg_type = MESS_MM_STR;
	mess.msg_client = mm_msg_data.msg_client;
	mess.msg_instance = mm_msg_data.msg_instance;
	mess.msg_host = mm_msg_data.msg_host;
	mess.msg_who = who;
	mess.msg_severity = severity;
	mess.msg_manufacturer = MESS_MANUFACTURER;
	mess.msg_model = MESS_MODEL;
	mess.msg_messageid = messageid;
	mess.msg_lang = MESS_LANG;
	va_start(args, messageid);
	mess.msg_localized = mms_get_locstr(messageid, args);
	va_end(args);

	if ((rc = mm_slog(&mess)) == 0) {
		rc = mm_msg_fifo(db, &mess);
	}

	free(mess.msg_localized);

	return (rc);
}

int
mm_msg_exists(int message_id)
{
	char	*fmt;

	fmt = mms_get_cat_msg(message_id);
	if (fmt == NULL || fmt[0] == '\0') {
		return (0);
	}
	return (1);
}

int
mm_msg_parse(mm_command_t *cmd, mms_par_node_t *root)
{
	mms_par_node_t	*arg;
	mms_par_node_t	*name;
	mms_par_node_t	*value;
	mms_par_node_t	*count;
	mms_par_node_t	*work;
	char		*p;
	char		*fmt;

	mms_trace(MMS_DEVP, "mm_msg_parse");

	/*
	 * Parse and localize command's message-clause
	 */

	/* message-clause */
	MMS_PN_LOOKUP(arg, root, "message", MMS_PN_CLAUSE, NULL);

	MMS_PN_LOOKUP(arg, root, "id", MMS_PN_CLAUSE, NULL);
	work = NULL;
	MMS_PN_LOOKUP(value, arg, NULL, MMS_PN_STRING, &work);
	cmd->cmd_msg.msg_manufacturer = value->pn_string;

	MMS_PN_LOOKUP(value, arg, NULL, MMS_PN_STRING, &work);
	cmd->cmd_msg.msg_model = value->pn_string;

	MMS_PN_LOOKUP(value, arg, NULL, MMS_PN_STRING, &work);
	cmd->cmd_msg.msg_messageid = atoi(value->pn_string);

	/* locale-text-clause */
	count = NULL;
	while (arg = mms_pn_lookup(root, "loctext",
	    MMS_PN_CLAUSE, &count)) {

		work = NULL;
		value = mms_pn_lookup(arg, NULL, MMS_PN_STRING, &work);
		if (value == NULL)
			NOT_FOUND();
		cmd->cmd_msg.msg_lang = value->pn_string;

		value = mms_pn_lookup(arg, NULL, MMS_PN_STRING, &work);
		if (value == NULL)
			NOT_FOUND();
		cmd->cmd_msg.msg_text = value->pn_string;
	}

	/* lookup localized message */
	fmt = mms_get_cat_msg(cmd->cmd_msg.msg_messageid);
	if (fmt == NULL || fmt[0] == '\0') {
		/* no catalog message found so use default if it exists */
		mms_trace(MMS_DEVP, "catalog messageid %d not found",
		    cmd->cmd_msg.msg_messageid);
		if (cmd->cmd_msg.msg_text) {
			fmt = cmd->cmd_msg.msg_text;
		}
		if (fmt == NULL) {
			fmt = "\0";
		}
	}

	/* copy localized message */
	if (cmd->cmd_msg.msg_localized)
		free(cmd->cmd_msg.msg_localized);
	cmd->cmd_msg.msg_localized = strdup(fmt);

	/* arg-clause */
	if (arg = mms_pn_lookup(root, "arguments",
	    MMS_PN_CLAUSE, NULL)) {

		/* save arguments list */
		cmd->cmd_msg.msg_args = &arg->pn_arglist;

		/* substitue each text argument with value */
		mms_list_pair_foreach(&arg->pn_arglist, name, value) {

			if (name == NULL || value == NULL) {
				NOT_FOUND();
			}

			if ((p = mms_msg_sub(cmd->cmd_msg.msg_localized,
			    name->pn_string,
			    value->pn_string)) == NULL) {
				MM_ABORT_NO_MEM();
				return (1);
			}
			free(cmd->cmd_msg.msg_localized);
			cmd->cmd_msg.msg_localized = p;
		}
	}

	mms_trace(MMS_DEVP, "parsed message: %s %s %d - %s",
	    cmd->cmd_msg.msg_manufacturer,
	    cmd->cmd_msg.msg_model,
	    cmd->cmd_msg.msg_messageid,
	    cmd->cmd_msg.msg_localized);

	return (0);

not_found:
	mms_trace(MMS_DEVP, "parse message: not found");
	return (1);

no_mem:
	MM_ABORT_NO_MEM();
	return (1);
}

static int
mm_msg_fifo(mm_db_t *db, mm_msg_t *mess)
{
	mm_msg_sev_t	sys_acc_level;
	int		sys_msg_limit;
	int		sys_msg_count;
	char		cid[UUID_PRINTF_SIZE + 3];
	char		*localized;

	mms_trace(MMS_DEVP, "mm_msg_fifo");

	/*
	 * Add message to mm's message fifo
	 */

	if (mm_db_exec(HERE, db, "select \"SystemAcceptLevel\","
	    "\"SystemMessageLimit\",\"SystemMessageCount\" from "
	    "\"SYSTEM\";") != MM_DB_DATA) {
		mm_clear_db(&db->mm_db_results);
		return (1);
	}
	if (PQntuples(db->mm_db_results) != 1) {
		mm_clear_db(&db->mm_db_results);
		return (1);
	}
	sys_acc_level = mm_msg_str2sev(PQgetvalue(db->mm_db_results, 0, 0));
	sys_msg_limit = atoi(PQgetvalue(db->mm_db_results, 0, 1));
	sys_msg_count = atoi(PQgetvalue(db->mm_db_results, 0, 2));
	mm_clear_db(&db->mm_db_results);

	if (mess->msg_severity < sys_acc_level) {
		return (0);
	}

	if (sys_msg_limit == 0) {
		return (0);
	}

	if (mess->msg_cid == NULL) {
		(void) strlcpy(cid, "NULL", sizeof (cid));
	} else {
		(void) snprintf(cid, sizeof (cid), "'%s'", mess->msg_cid);
	}

	if ((localized = mm_db_escape_string(mess->
	    msg_localized)) == NULL) {
		mms_trace(MMS_ERR, "db mms_escape string - %s",
		    mess->msg_localized);
		mm_clear_db(&db->mm_db_results);
		return (1);
	}

	if (sys_msg_count < sys_msg_limit) {

		if (mm_db_exec(HERE, db, "insert into \"MESSAGE\" "
		    "(\"MessageID\","
		    "\"MessageSenderType\","
		    "\"MessageSenderName\","
		    "\"MessageSenderInstance\","
		    "\"MessageConnectionID\","
		    "\"MessageLevel\","
		    "\"MessageManufacturer\","
		    "\"MessageModel\","
		    "\"MessageNumber\","
		    "\"MessageText\","
		    "\"MessageTimeCreated\","
		    "\"MessageHost\") "
		    "values ('%s','%s','%s','%s',%s,"
		    "'%s','%s','%s','%d','%s','%s','%s');",
		    mess->msg_uuid,
		    mess->msg_type,
		    mess->msg_client,
		    mess->msg_instance,
		    cid,
		    mm_msg_sev2str(mess->msg_severity),
		    mess->msg_manufacturer,
		    mess->msg_model,
		    mess->msg_messageid,
		    localized,
		    mess->msg_timestamp,
		    mess->msg_host) != MM_DB_OK) {
			mm_clear_db(&db->mm_db_results);
			free(localized);
			return (1);
		}
		free(localized);

		if (mm_db_exec(HERE, db, "update \"SYSTEM\" set "
		    "\"SystemMessageCount\" = '%d';",
		    sys_msg_count + 1) != MM_DB_OK) {
			mm_clear_db(&db->mm_db_results);
			return (1);
		}

		if (db->mm_db_count != 1) {
			return (1);
		}

	} else {

		if (mm_db_exec(HERE, db, "update \"MESSAGE\" set "
		    "\"MessageID\" = '%s',"
		    "\"MessageSenderType\" = '%s',"
		    "\"MessageSenderName\" = '%s',"
		    "\"MessageSenderInstance\" = '%s',"
		    "\"MessageConnectionID\" = %s,"
		    "\"MessageLevel\" = '%s',"
		    "\"MessageManufacturer\" = '%s',"
		    "\"MessageModel\" = '%s',"
		    "\"MessageNumber\" = '%d',"
		    "\"MessageText\" = '%s',"
		    "\"MessageTimeCreated\" = '%s',"
		    "\"MessageHost\" = '%s' "
		    "where \"MessageID\" = (select \"MessageID\" from "
		    "\"MESSAGE\" order by \"MessageTimeCreated\" limit 1);",
		    mess->msg_uuid,
		    mess->msg_type,
		    mess->msg_client,
		    mess->msg_instance,
		    cid,
		    mm_msg_sev2str(mess->msg_severity),
		    mess->msg_manufacturer,
		    mess->msg_model,
		    mess->msg_messageid,
		    localized,
		    mess->msg_timestamp,
		    mess->msg_host) != MM_DB_OK) {
			mm_clear_db(&db->mm_db_results);
			free(localized);
			return (1);
		}
		free(localized);

		if (db->mm_db_count != 1) {
			return (1);
		}
	}

	mess->msg_flags |= MESS_FLAG_FIFO;
	mms_trace(MMS_DEVP, "message added to fifo");

	return (0);
}

int
mm_msg_set_limit(mm_db_t *db)
{
	int limit;
	int count;
	int actual_count;

	mms_trace(MMS_DEVP, "mm_msg_set_limit");

	/*
	 * Change message fifo size.
	 */

	if (mm_db_exec(HERE, db, "select \"SystemMessageLimit\","
	    "\"SystemMessageCount\" from \"SYSTEM\";") != MM_DB_DATA) {
		return (1);
	}
	limit = atoi(PQgetvalue(db->mm_db_results, 0, 0));
	count = atoi(PQgetvalue(db->mm_db_results, 0, 1));
	mm_clear_db(&db->mm_db_results);

	if (mm_db_exec(HERE, db, "select \"MessageID\" "
	    "from \"MESSAGE\";") != MM_DB_DATA) {
		return (1);
	}
	actual_count = PQntuples(db->mm_db_results);
	mm_clear_db(&db->mm_db_results);

	if (count != actual_count) {
		count = actual_count;
	}

	/* remove excess messages from message fifo */
	while (count > limit) {
		/* remove oldest message */
		if (mm_db_exec(HERE, db, "delete from \"MESSAGE\" "
		    "where \"MessageID\" = (select \"MessageID\" "
		    "from \"MESSAGE\" "
		    "order by \"MessageTimeCreated\" "
		    "limit 1);") != MM_DB_OK) {
			return (1);
		}
		if (db->mm_db_count != 1) {
			return (1);
		}
		count--;
	}

	if (count < 0) {
		count = 0;
	}

	if (mm_db_exec(HERE, db, "update \"SYSTEM\" set "
	    "\"SystemMessageCount\" = '%d';", count) != MM_DB_OK) {
		mm_clear_db(&db->mm_db_results);
		return (1);
	}

	return (0);
}

/*
 * System Log File
 */

static int
mm_slog_open(mm_db_t *db)
{
	int		oflags = O_CREAT | O_RDWR | O_APPEND;
	struct stat	buf;

	mms_trace(MMS_DEVP, "mm_slog_open");

	if (mm_db_exec(HERE, db, "select \"SystemLogFile\" from "
	    "\"SYSTEM\";") != MM_DB_DATA) {
		mm_clear_db(&db->mm_db_results);
		mms_trace(MMS_ERR, "query system log file name");
		return (1);
	}
	if (PQntuples(db->mm_db_results) != 1) {
		mm_clear_db(&db->mm_db_results);
		mms_trace(MMS_ERR, "missing system log file name");
		return (1);
	}
	snprintf(mm_msg_data.slog_fname, PATH_MAX,
	    "%s", PQgetvalue(db->mm_db_results, 0, 0));
	mm_clear_db(&db->mm_db_results);

	if (mm_slog_set_sync(db)) {
		mms_trace(MMS_ERR, "system log file sync");
		return (1);
	}

	if (mm_slog_set_level(db)) {
		mms_trace(MMS_ERR, "system log file level");
		return (1);
	}

	if (mm_slog_set_size(db)) {
		mms_trace(MMS_ERR, "system log file size");
		return (1);
	}

	mm_msg_data.slog_fd = open(mm_msg_data.slog_fname, oflags, 0644);
	if (mm_msg_data.slog_fd < 0) {
		mms_trace(MMS_ERR, "open %s %s", mm_msg_data.slog_fname,
		    strerror(errno));
		return (1);
	}

	if (fstat(mm_msg_data.slog_fd, &buf) != 0) {
		mms_trace(MMS_ERR, "fstat %s %s", mm_msg_data.slog_fname,
		    strerror(errno));
		close(mm_msg_data.slog_fd);
		mm_msg_data.slog_fd = -1;
		return (1);
	}

	mm_msg_data.slog_size = buf.st_size;

	return (0);
}

static void
mm_slog_close(void)
{
	mms_trace(MMS_DEVP, "mm_slog_close");
	close(mm_msg_data.slog_fd);
	mm_msg_data.slog_fd = -1;
}

static void
mm_slog_flush(void)
{
	(void) fsync(mm_msg_data.slog_fd);
}

static int
mm_slog(mm_msg_t *mess)
{
	char	*buf;
	int	len;
	int	oflags = O_CREAT | O_RDWR | O_APPEND;
	char	*localized;
	pid_t	shpid;
	char	size[20];

	/*
	 * Write message to system log file.
	 */

	if (mess->msg_severity > MESS_EMERG ||
	    mess->msg_severity < MESS_DEVP) {
		mms_trace(MMS_ERR, "invalid severity %d", mess->msg_severity);
		return (1);		/* invalid severity */
	}

	if (mess->msg_severity < mm_msg_data.slog_level) {
		return (0);		/* not logging this severity */
	}

	localized = mms_strpar_undo_escape_sequence(mess->msg_localized);
	if (localized == NULL) {
		mms_trace(MMS_ERR, "unable to localized message");
		return (1);		/* mms_escape sequence removal failed */
	}

	if ((buf = mms_strnew(
	    "%s %s %.2s %s %s %s %d %s\n",
	    mess->msg_timestamp,
	    mess->msg_host,
	    mess->msg_type,
	    mess->msg_client,
	    mess->msg_instance,
	    mm_msg_sev2str(mess->msg_severity),
	    mess->msg_messageid,
	    localized)) == NULL) {
		mms_trace(MMS_ERR, "message allocation failed");
		free(localized);
		return (1);
	}
	free(localized);

	len = strlen(buf);

	pthread_mutex_lock(&mm_msg_data.slog_mutex);
	if (write(mm_msg_data.slog_fd, buf, len) == len) {
		mess->msg_flags |= MESS_FLAG_SLOG;
	}
	free(buf);
	mm_msg_data.slog_size += len;
	mm_msg_data.slog_count++;

	/* flush system log file to disk */
	if (mm_msg_data.slog_count > mm_msg_data.slog_sync) {
		mm_slog_flush();
		mm_msg_data.slog_count = 0;
	}
	if (mm_msg_data.slog_size > mm_msg_data.slog_rot_size) {
		mm_slog_flush();
		(void) close(mm_msg_data.slog_fd);
		if ((shpid = fork()) < 0) {
			mms_trace(MMS_DEBUG,
			    "mm_slog: fork failed");
			return (-1);
		} else if (shpid == 0) { /* child */
			(void) snprintf(size, sizeof (size), "%lldb",
			    mm_msg_data.slog_size);
			(void) execl(MMS_LOGADM, MMS_LOGADM,
			    "-f", MMS_LOGADM_CONF,
			    "-s", size,
			    mm_msg_data.slog_fname,
			    (char *)0);
			exit(1);
		}
		if (waitpid(shpid, NULL, 0) < 0) /* parent */
			mms_trace(MMS_DEBUG,
			    "mm_slog: wait failed");

		mm_msg_data.slog_size = 0;
		mm_msg_data.slog_fd =
		    open(mm_msg_data.slog_fname, oflags, 0644);
	}
	pthread_mutex_unlock(&mm_msg_data.slog_mutex);
	return (0);
}

int
mm_slog_set_fname(mm_db_t *db)
{
	int	rc;

	mms_trace(MMS_DEVP, "mm_slog_set_fname");

	pthread_mutex_lock(&mm_msg_data.slog_mutex);
	mm_slog_close();
	rc = mm_slog_open(db);
	pthread_mutex_unlock(&mm_msg_data.slog_mutex);
	return (rc);
}

int
mm_slog_set_sync(mm_db_t *db)
{
	mms_trace(MMS_DEVP, "mm_slog_set_sync");

	if (mm_db_exec(HERE, db, "select \"SystemSyncLimit\" from "
	    "\"SYSTEM\";") != MM_DB_DATA) {
		mm_clear_db(&db->mm_db_results);
		return (1);
	}
	if (PQntuples(db->mm_db_results) != 1) {
		mm_clear_db(&db->mm_db_results);
		return (1);
	}
	mm_msg_data.slog_sync = atoi(PQgetvalue(db->mm_db_results, 0, 0));
	mm_clear_db(&db->mm_db_results);
	return (0);
}

int
mm_slog_set_level(mm_db_t *db)
{
	char		*level;

	mms_trace(MMS_DEVP, "mm_slog_set_level");

	if (mm_db_exec(HERE, db, "select \"SystemLogLevel\" from "
	    "\"SYSTEM\";") != MM_DB_DATA) {
		mm_clear_db(&db->mm_db_results);
		return (1);
	}
	if (PQntuples(db->mm_db_results) != 1) {
		mm_clear_db(&db->mm_db_results);
		return (1);
	}
	level = PQgetvalue(db->mm_db_results, 0, 0);
	mm_msg_data.slog_level = mm_msg_str2sev(level);
	mm_clear_db(&db->mm_db_results);
	return (0);
}

int
mm_slog_set_size(mm_db_t *db)
{
	uint64_t	value;
	int		rc;
	char		*size;

	mms_trace(MMS_DEVP, "mm_slog_set_size");

	if (mm_db_exec(HERE, db, "select \"SystemLogFileSize\" from "
	    "\"SYSTEM\";") != MM_DB_DATA) {
		mm_clear_db(&db->mm_db_results);
		return (1);
	}
	if (PQntuples(db->mm_db_results) != 1) {
		mm_clear_db(&db->mm_db_results);
		return (1);
	}
	size = PQgetvalue(db->mm_db_results, 0, 0);
	if ((rc = mms_trace_str_to_fsize(size, &value)) == 0) {
		mm_msg_data.slog_rot_size = value;
	}
	mm_clear_db(&db->mm_db_results);
	return (rc);
}

/*
 * Get message-clause strings
 */

void
mm_response_error(mm_command_t *cmd, char *eclass, char *ecode,
    int messageid, ...)
{
	va_list args;
	char *buf;
	char *text;

	mm_cmd_err_t *err = NULL;


	mms_trace(MMS_ERR, "mm_response_error");
	mms_trace(MMS_ERR, "Class:: %s",
	    eclass);
	mms_trace(MMS_ERR, "Token:: %s",
	    ecode);
	mms_trace(MMS_ERR, "ID:: %d",
	    messageid);

	/*
	 * Get final-command response error with message-clause
	 */

	if (cmd->cmd_eclass != NULL) {
		free(cmd->cmd_eclass);
		cmd->cmd_eclass = NULL;
	}
	cmd->cmd_eclass = strdup(eclass);

	if (cmd->cmd_ecode != NULL) {
		free(cmd->cmd_ecode);
		cmd->cmd_ecode = NULL;
	}
	cmd->cmd_ecode = strdup(ecode);

	va_start(args, messageid);
	text = mms_bld_msgcl(messageid, args);
	va_end(args);

	buf = mms_strnew("response task[\"%s\"] error[%s %s] %s;",
	    cmd->cmd_task, eclass, ecode, text);
	free(text);

	SQL_CHK_LEN(&cmd->cmd_buf, 0, &cmd->cmd_bufsize, strlen(buf) + 1);
	strcpy(cmd->cmd_buf, buf);
	free(buf);

	/* insert this error into the cmd's err_list */
	if ((err = mm_alloc_err()) == NULL) {
		mms_trace(MMS_ERR,
		    "mm_response_error: "
		    "could not allocate err struct");
		return;
	}
	err->eclass = strdup(eclass);
	err->ecode = strdup(ecode);
	err->err_bufsize = cmd->cmd_bufsize;
	err->err_buf = strdup(cmd->cmd_buf);
	err->retry_drive = NULL;
	err->retry_cart = NULL;
	err->retry_lib = NULL;
	mms_list_insert_tail(&cmd->cmd_err_list, err);

	return;

no_mem:
	MM_ABORT_NO_MEM();
}

static mm_msg_sev_t
mm_msg_str2sev(char *serverity)
{
	mm_msg_sev_t rc;

	/* convert mms severity string to enum. */
	if (strcmp(serverity, MESS_EMERG_STR) == 0) {
		rc = MESS_EMERG;
	} else if (strcmp(serverity, MESS_ALERT_STR) == 0) {
		rc = MESS_ALERT;
	} else if (strcmp(serverity, MESS_CRIT_STR) == 0) {
		rc = MESS_CRIT;
	} else if (strcmp(serverity, MESS_ERROR_STR) == 0) {
		rc = MESS_ERROR;
	} else if (strcmp(serverity, MESS_WARN_STR) == 0) {
		rc = MESS_WARN;
	} else if (strcmp(serverity, MESS_NOTICE_STR) == 0) {
		rc = MESS_NOTICE;
	} else if (strcmp(serverity, MESS_INFO_STR) == 0) {
		rc = MESS_INFO;
	} else if (strcmp(serverity, MESS_DEBUG_STR) == 0) {
		rc = MESS_DEBUG;
	} else {
		rc = MESS_DEVP;
	}
	return (rc);
}

/* Convert mms severity enum to string. */
char *
mm_msg_sev2str(mm_msg_sev_t severity)
{
	char *rc;

	if (severity == MESS_EMERG) {
		rc = MESS_EMERG_STR;
	} else if (severity == MESS_ALERT) {
		rc = MESS_ALERT_STR;
	} else if (severity == MESS_CRIT) {
		rc = MESS_CRIT_STR;
	} else if (severity == MESS_ERROR) {
		rc = MESS_ERROR_STR;
	} else if (severity == MESS_WARN) {
		rc = MESS_WARN_STR;
	} else if (severity == MESS_NOTICE) {
		rc = MESS_NOTICE_STR;
	} else if (severity == MESS_INFO) {
		rc = MESS_INFO_STR;
	} else if (severity == MESS_DEBUG) {
		rc = MESS_DEBUG_STR;
	} else {
		rc = MESS_DEVP_STR;
	}
	return (rc);
}

/* Convert message cmd who enum to string. */
static char *
mm_msg_who2str(mm_msg_who_t who)
{
	char *rc;

	if (who == MESS_OPER) {
		rc = MESS_OPER_STR;
	} else if (who == MESS_ADMIN) {
		rc = MESS_ADMIN_STR;
	} else {
		rc = MESS_LOG_STR;
	}
	return (rc);
}

static mm_msg_who_t
mm_msg_str2who(char *who)
{
	mm_msg_who_t rc;

	if (strcmp(who, MESS_OPER_STR) == 0) {
		rc = MESS_OPER;
	} else if (strcmp(who, MESS_ADMIN_STR) == 0) {
		rc = MESS_ADMIN;
	} else {
		rc = MESS_LOG;
	}
	return (rc);
}

/* Convert mms protocol language enum to message component string. */
char *
mm_msg_lang2component(mm_lang_t lang)
{
	char *rc;

	if (lang == MM_LANG_DMP) {
		rc = MESS_DM_STR;
	} else if (lang == MM_LANG_LMP) {
		rc = MESS_LM_STR;
	} else {
		rc = MESS_AI_STR;
	}
	return (rc);
}

static void
mm_get_timestamp(mm_db_t *db, char *timestamp)
{
	int		rc = 1;
	char		date[100];
	time_t		tm;
	struct tm	ltime;
	int		i;
	char		*p;

	/*
	 * Get timestamp with 3 digit millisecond
	 */

	if (db != NULL) {
		if (mm_db_exec(HERE, db, "select cast(current_timestamp as "
		    "timestamp(3)) as ts;") != MM_DB_DATA) {
			rc = 1;
		} else if (PQntuples(db->mm_db_results) != 1) {
			rc = 1;
		} else {
			memset(timestamp, 0, MM_TIMESTAMP);
			snprintf(timestamp, MM_TIMESTAMP, "%s",
			    PQgetvalue(db->mm_db_results, 0, 0));

			/* pad milliseconds with zeros */
			if (p = strrchr(timestamp, '.')) {
				for (i = 1; i <= 3; i++) {
					if (!isdigit(*(p+i))) {
						*(p+i) = '0';
					}
				}
			} else {
				/* zero milliseconds */
				strlcat(timestamp, ".000", MM_TIMESTAMP);
			}
			rc = 0;
		}
		mm_clear_db(&db->mm_db_results);
	}

	if (rc) {
		/* failed to get time from db so use system time */
		(void) time(&tm);
		(void) localtime_r(&tm, &ltime);
		(void) strftime(date, 100, "%Y-%m-%d %H:%M:%S.000", &ltime);
		strlcpy(timestamp, date, MM_TIMESTAMP);
	}
}