eventlog.c revision 03831d35f7499c87d51205817c93e9a8d42c4bae
/*
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* eventlog.c: support for the scadm loghistory option (to display the
* service processor log history)
*/
#include <libintl.h>
#include <stdio.h>
#include <string.h>
#include <time.h> /* required by librsc.h */
#include "librsc.h"
#include "adm.h"
#include "event_mess.h"
#define TAB '\t'
#define BACKSLASH_ESCAPE '\\'
/* #define DEBUG */
static char *
getEventLogMessage(int eventId)
{
int category;
int event;
char **alertCategory;
char *alertMessage;
category = eventId >> 16;
event = eventId &0x0000ffff;
alertCategory = rsc_alerts[category];
if (alertCategory) {
alertMessage = alertCategory[event];
} else {
return (NULL);
}
if (alertMessage) {
return (alertMessage);
} else {
return (NULL);
}
}
/*
* getNextEventLogParam
*
* Return the next message from a TAB delimited message parameter list.
* Given a string message "mess1\tmess2\tmess3\t\t", this function will
* return a ponter to "mess2" the first time it is called.
*/
static char *
getNextEventLogParam(char *mess)
{
char *p = mess;
do {
/* ESCAPE means interpret the next character literally */
if ((p != mess) && (*(p-1) == BACKSLASH_ESCAPE)) {
p++;
continue;
}
if ((*p == TAB) && (*(p+1) == TAB)) {
/* Double tab means end of list */
return (NULL);
}
p++;
} while (*p != TAB);
/* return pointer to char after TAB */
p++;
return (p);
}
/*
* expandEventLogMessage
*
* This function will expand the base message for the category/event
* passed in with the TAB delimited parameters passed in via messParams.
* The expanded message will be returned in the buf character buffer.
*/
static int
expandEventLogMessage(int eventId, char *messParams, size_t messParamsLen,
char *buf)
{
char *alertMessage;
char *s;
char *d;
char *param;
/* Get Alert message from internal tables */
alertMessage = getEventLogMessage(eventId);
if (alertMessage == NULL) {
(void) strcpy(buf, "Unknown alert");
return (strlen("Unknown alert"));
}
/* No message parameters to copy */
if (messParamsLen == 0) {
(void) strcpy(buf, alertMessage);
return (strlen(buf));
}
/* A %s in the base message means we expand with a parameter */
if (strstr(alertMessage, "%s")) {
s = alertMessage;
d = buf;
param = messParams;
do {
if ((*s == '%') && (*(s+1) == 's')) {
if (param) {
char *p = param;
while ((*p) && (*p != TAB)) {
*d++ = *p++;
}
}
/* Get next parameter on list for next %s */
param = getNextEventLogParam(param);
s += 2;
}
} while ((*d++ = *s++));
} else {
/* If no %s tokens to expand, just copy message */
(void) strcpy(buf, alertMessage);
}
return (strlen(buf));
}
static void
ADM_Process_old_event_log()
{
char timebuf[32];
char messBuff[256];
char eventMsgBuf[256];
rscp_msg_t Message;
struct timespec Timeout;
dp_get_event_log_r_t *rscReply;
char *datap;
dp_event_log_entry_t entry;
int i, len, entryhdrsize;
ADM_Start();
Message.type = DP_GET_EVENT_LOG;
Message.len = 0;
Message.data = NULL;
ADM_Send(&Message);
Timeout.tv_nsec = 0;
Timeout.tv_sec = ADM_TIMEOUT;
ADM_Recv(&Message, &Timeout,
DP_GET_EVENT_LOG_R, sizeof (*rscReply));
/* Print the event log messages */
rscReply = (dp_get_event_log_r_t *)Message.data;
datap = (char *)rscReply->data;
for (i = 0; i < rscReply->entry_count; i++) {
entryhdrsize = sizeof (entry) - sizeof (entry.param);
(void) memcpy(&entry, datap, entryhdrsize);
datap += entryhdrsize;
(void) memcpy(&entry.param, datap, entry.paramLen);
(void) strftime(timebuf, sizeof (timebuf), "%b %d %H:%M:%S",
gmtime((time_t *)&entry.eventTime));
(void) sprintf(messBuff, "%s : %08lx: \"", timebuf,
entry.eventId);
len = expandEventLogMessage(entry.eventId, entry.param,
entry.paramLen, eventMsgBuf);
(void) strncat(messBuff, eventMsgBuf, len);
(void) strcat(messBuff, "\"\r\n");
(void) printf(messBuff);
datap += entry.paramLen;
}
ADM_Free(&Message);
}
static int
ADM_Process_new_event_log(int all)
{
char timebuf[32];
char messBuff[256];
char eventMsgBuf[256];
rscp_msg_t Message;
struct timespec Timeout;
dp_get_event_log2_r_t *rscReply;
char *datap;
dp_event_log_entry_t entry;
int i, len, entryhdrsize, sent_ok;
rsci64 events_remaining, seqno;
rsci16 request_size, returned_events;
dp_get_event_log2_t rscCmd;
ADM_Start();
/*
* Start by sending a zero-length request to ALOM, so that
* we can learn the length of the console log. We expect
* ALOM to return the length of the entire log. We get
* a snapshot of the length of the log here - it may however
* continue to grow as we're reading it. We read only as
* much of the log as we get in this snapshot.
*
* If the command fails, we quietly return failure here so
* that the caller can re-try with the old/legacy command.
*/
rscCmd.start_seq = 0;
rscCmd.length = 0;
Message.type = DP_GET_EVENT_LOG2;
Message.len = sizeof (rscCmd);
Message.data = (char *)&rscCmd;
if (ADM_Send_ret(&Message) != 0) {
return (1);
}
Timeout.tv_nsec = 0;
Timeout.tv_sec = ADM_TIMEOUT;
ADM_Recv(&Message, &Timeout,
DP_GET_EVENT_LOG2_R, sizeof (*rscReply));
rscReply = (dp_get_event_log2_r_t *)Message.data;
/*
* Fetch an fixed number of events from the end of
* the log if at least that many exist, and we were not
* asked to fetch all the events.
*/
if ((all == 0) &&
(rscReply->remaining_log_events > DEFAULT_NUM_EVENTS)) {
events_remaining = DEFAULT_NUM_EVENTS;
seqno = (rscReply->remaining_log_events +
rscReply->next_seq) - events_remaining;
} else {
events_remaining = rscReply->remaining_log_events;
seqno = rscReply->next_seq;
}
request_size = sizeof (rscReply->buffer);
ADM_Free(&Message);
/*
* This loop runs as long as there is data in the log, or until
* we hit the default limit (above). It's possible that ALOM may
* shrink the log - we need to account for this. If ALOM returns
* no data, we bail out.
*/
while (events_remaining) {
rscCmd.start_seq = seqno;
rscCmd.length = request_size;
Message.type = DP_GET_EVENT_LOG2;
Message.len = sizeof (rscCmd);
Message.data = (char *)&rscCmd;
ADM_Send(&Message);
Timeout.tv_nsec = 0;
Timeout.tv_sec = ADM_TIMEOUT;
ADM_Recv(&Message, &Timeout,
DP_GET_EVENT_LOG2_R, sizeof (*rscReply));
rscReply = (dp_get_event_log2_r_t *)Message.data;
/* If ALOM returns zero events, we're done. */
returned_events = rscReply->num_events;
if (returned_events == 0) {
ADM_Free(&Message);
break;
}
/*
* if the event at the original sequence number is no
* longer in the log, print a message
*/
if (seqno + returned_events < rscReply->next_seq) {
printf(gettext("\nscadm: lost %d events\n"),
rscReply->next_seq - (seqno + returned_events));
}
/*
* get ready for next main loop iteration
*/
seqno = rscReply->next_seq;
events_remaining -= returned_events;
/* Print the event log messages */
datap = rscReply->buffer;
for (i = 0; i < returned_events; i++) {
entryhdrsize = sizeof (entry) - sizeof (entry.param);
(void) memcpy(&entry, datap, entryhdrsize);
datap += entryhdrsize;
(void) memcpy(&entry.param, datap, entry.paramLen);
(void) strftime(timebuf, sizeof (timebuf),
"%b %d %H:%M:%S",
gmtime((time_t *)&entry.eventTime));
(void) sprintf(messBuff, "%s : %08lx: \"", timebuf,
entry.eventId);
len = expandEventLogMessage(entry.eventId, entry.param,
entry.paramLen, eventMsgBuf);
(void) strncat(messBuff, eventMsgBuf, len);
(void) strcat(messBuff, "\"\r\n");
(void) printf(messBuff);
datap += entry.paramLen;
}
ADM_Free(&Message);
}
return (0);
}
void
ADM_Process_event_log(int all)
{
if (ADM_Process_new_event_log(all) != 0) {
ADM_Process_old_event_log();
}
}