1*03831d35Sstevel /* 2*03831d35Sstevel * CDDL HEADER START 3*03831d35Sstevel * 4*03831d35Sstevel * The contents of this file are subject to the terms of the 5*03831d35Sstevel * Common Development and Distribution License (the "License"). 6*03831d35Sstevel * You may not use this file except in compliance with the License. 7*03831d35Sstevel * 8*03831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*03831d35Sstevel * or http://www.opensolaris.org/os/licensing. 10*03831d35Sstevel * See the License for the specific language governing permissions 11*03831d35Sstevel * and limitations under the License. 12*03831d35Sstevel * 13*03831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each 14*03831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*03831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the 16*03831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying 17*03831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner] 18*03831d35Sstevel * 19*03831d35Sstevel * CDDL HEADER END 20*03831d35Sstevel */ 21*03831d35Sstevel 22*03831d35Sstevel /* 23*03831d35Sstevel * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*03831d35Sstevel * Use is subject to license terms. 25*03831d35Sstevel */ 26*03831d35Sstevel 27*03831d35Sstevel #pragma ident "%Z%%M% %I% %E% SMI" 28*03831d35Sstevel 29*03831d35Sstevel /* 30*03831d35Sstevel * eventlog.c: support for the scadm loghistory option (to display the 31*03831d35Sstevel * service processor log history) 32*03831d35Sstevel */ 33*03831d35Sstevel 34*03831d35Sstevel #include <libintl.h> 35*03831d35Sstevel #include <stdio.h> 36*03831d35Sstevel #include <string.h> 37*03831d35Sstevel #include <time.h> /* required by librsc.h */ 38*03831d35Sstevel 39*03831d35Sstevel #include "librsc.h" 40*03831d35Sstevel #include "adm.h" 41*03831d35Sstevel 42*03831d35Sstevel #include "event_mess.h" 43*03831d35Sstevel #define TAB '\t' 44*03831d35Sstevel #define BACKSLASH_ESCAPE '\\' 45*03831d35Sstevel 46*03831d35Sstevel /* #define DEBUG */ 47*03831d35Sstevel 48*03831d35Sstevel static char * 49*03831d35Sstevel getEventLogMessage(int eventId) 50*03831d35Sstevel { 51*03831d35Sstevel int category; 52*03831d35Sstevel int event; 53*03831d35Sstevel char **alertCategory; 54*03831d35Sstevel char *alertMessage; 55*03831d35Sstevel 56*03831d35Sstevel category = eventId >> 16; 57*03831d35Sstevel event = eventId &0x0000ffff; 58*03831d35Sstevel 59*03831d35Sstevel alertCategory = rsc_alerts[category]; 60*03831d35Sstevel if (alertCategory) { 61*03831d35Sstevel alertMessage = alertCategory[event]; 62*03831d35Sstevel } else { 63*03831d35Sstevel return (NULL); 64*03831d35Sstevel } 65*03831d35Sstevel 66*03831d35Sstevel if (alertMessage) { 67*03831d35Sstevel return (alertMessage); 68*03831d35Sstevel } else { 69*03831d35Sstevel return (NULL); 70*03831d35Sstevel } 71*03831d35Sstevel } 72*03831d35Sstevel 73*03831d35Sstevel /* 74*03831d35Sstevel * getNextEventLogParam 75*03831d35Sstevel * 76*03831d35Sstevel * Return the next message from a TAB delimited message parameter list. 77*03831d35Sstevel * Given a string message "mess1\tmess2\tmess3\t\t", this function will 78*03831d35Sstevel * return a ponter to "mess2" the first time it is called. 79*03831d35Sstevel */ 80*03831d35Sstevel static char * 81*03831d35Sstevel getNextEventLogParam(char *mess) 82*03831d35Sstevel { 83*03831d35Sstevel char *p = mess; 84*03831d35Sstevel 85*03831d35Sstevel do { 86*03831d35Sstevel /* ESCAPE means interpret the next character literally */ 87*03831d35Sstevel if ((p != mess) && (*(p-1) == BACKSLASH_ESCAPE)) { 88*03831d35Sstevel p++; 89*03831d35Sstevel continue; 90*03831d35Sstevel } 91*03831d35Sstevel 92*03831d35Sstevel if ((*p == TAB) && (*(p+1) == TAB)) { 93*03831d35Sstevel /* Double tab means end of list */ 94*03831d35Sstevel return (NULL); 95*03831d35Sstevel } 96*03831d35Sstevel p++; 97*03831d35Sstevel 98*03831d35Sstevel } while (*p != TAB); 99*03831d35Sstevel 100*03831d35Sstevel /* return pointer to char after TAB */ 101*03831d35Sstevel p++; 102*03831d35Sstevel return (p); 103*03831d35Sstevel 104*03831d35Sstevel } 105*03831d35Sstevel 106*03831d35Sstevel /* 107*03831d35Sstevel * expandEventLogMessage 108*03831d35Sstevel * 109*03831d35Sstevel * This function will expand the base message for the category/event 110*03831d35Sstevel * passed in with the TAB delimited parameters passed in via messParams. 111*03831d35Sstevel * The expanded message will be returned in the buf character buffer. 112*03831d35Sstevel */ 113*03831d35Sstevel 114*03831d35Sstevel static int 115*03831d35Sstevel expandEventLogMessage(int eventId, char *messParams, size_t messParamsLen, 116*03831d35Sstevel char *buf) 117*03831d35Sstevel { 118*03831d35Sstevel 119*03831d35Sstevel char *alertMessage; 120*03831d35Sstevel char *s; 121*03831d35Sstevel char *d; 122*03831d35Sstevel char *param; 123*03831d35Sstevel 124*03831d35Sstevel /* Get Alert message from internal tables */ 125*03831d35Sstevel alertMessage = getEventLogMessage(eventId); 126*03831d35Sstevel if (alertMessage == NULL) { 127*03831d35Sstevel (void) strcpy(buf, "Unknown alert"); 128*03831d35Sstevel return (strlen("Unknown alert")); 129*03831d35Sstevel } 130*03831d35Sstevel 131*03831d35Sstevel /* No message parameters to copy */ 132*03831d35Sstevel if (messParamsLen == 0) { 133*03831d35Sstevel (void) strcpy(buf, alertMessage); 134*03831d35Sstevel return (strlen(buf)); 135*03831d35Sstevel } 136*03831d35Sstevel 137*03831d35Sstevel /* A %s in the base message means we expand with a parameter */ 138*03831d35Sstevel if (strstr(alertMessage, "%s")) { 139*03831d35Sstevel s = alertMessage; 140*03831d35Sstevel d = buf; 141*03831d35Sstevel param = messParams; 142*03831d35Sstevel 143*03831d35Sstevel do { 144*03831d35Sstevel if ((*s == '%') && (*(s+1) == 's')) { 145*03831d35Sstevel if (param) { 146*03831d35Sstevel char *p = param; 147*03831d35Sstevel 148*03831d35Sstevel while ((*p) && (*p != TAB)) { 149*03831d35Sstevel *d++ = *p++; 150*03831d35Sstevel } 151*03831d35Sstevel } 152*03831d35Sstevel /* Get next parameter on list for next %s */ 153*03831d35Sstevel param = getNextEventLogParam(param); 154*03831d35Sstevel s += 2; 155*03831d35Sstevel } 156*03831d35Sstevel } while ((*d++ = *s++)); 157*03831d35Sstevel 158*03831d35Sstevel } else { 159*03831d35Sstevel /* If no %s tokens to expand, just copy message */ 160*03831d35Sstevel (void) strcpy(buf, alertMessage); 161*03831d35Sstevel } 162*03831d35Sstevel 163*03831d35Sstevel return (strlen(buf)); 164*03831d35Sstevel 165*03831d35Sstevel } 166*03831d35Sstevel 167*03831d35Sstevel static void 168*03831d35Sstevel ADM_Process_old_event_log() 169*03831d35Sstevel { 170*03831d35Sstevel char timebuf[32]; 171*03831d35Sstevel char messBuff[256]; 172*03831d35Sstevel char eventMsgBuf[256]; 173*03831d35Sstevel rscp_msg_t Message; 174*03831d35Sstevel struct timespec Timeout; 175*03831d35Sstevel dp_get_event_log_r_t *rscReply; 176*03831d35Sstevel char *datap; 177*03831d35Sstevel dp_event_log_entry_t entry; 178*03831d35Sstevel int i, len, entryhdrsize; 179*03831d35Sstevel 180*03831d35Sstevel ADM_Start(); 181*03831d35Sstevel 182*03831d35Sstevel Message.type = DP_GET_EVENT_LOG; 183*03831d35Sstevel Message.len = 0; 184*03831d35Sstevel Message.data = NULL; 185*03831d35Sstevel ADM_Send(&Message); 186*03831d35Sstevel 187*03831d35Sstevel Timeout.tv_nsec = 0; 188*03831d35Sstevel Timeout.tv_sec = ADM_TIMEOUT; 189*03831d35Sstevel ADM_Recv(&Message, &Timeout, 190*03831d35Sstevel DP_GET_EVENT_LOG_R, sizeof (*rscReply)); 191*03831d35Sstevel 192*03831d35Sstevel /* Print the event log messages */ 193*03831d35Sstevel rscReply = (dp_get_event_log_r_t *)Message.data; 194*03831d35Sstevel datap = (char *)rscReply->data; 195*03831d35Sstevel for (i = 0; i < rscReply->entry_count; i++) { 196*03831d35Sstevel entryhdrsize = sizeof (entry) - sizeof (entry.param); 197*03831d35Sstevel (void) memcpy(&entry, datap, entryhdrsize); 198*03831d35Sstevel datap += entryhdrsize; 199*03831d35Sstevel (void) memcpy(&entry.param, datap, entry.paramLen); 200*03831d35Sstevel (void) strftime(timebuf, sizeof (timebuf), "%b %d %H:%M:%S", 201*03831d35Sstevel gmtime((time_t *)&entry.eventTime)); 202*03831d35Sstevel (void) sprintf(messBuff, "%s : %08lx: \"", timebuf, 203*03831d35Sstevel entry.eventId); 204*03831d35Sstevel len = expandEventLogMessage(entry.eventId, entry.param, 205*03831d35Sstevel entry.paramLen, eventMsgBuf); 206*03831d35Sstevel (void) strncat(messBuff, eventMsgBuf, len); 207*03831d35Sstevel (void) strcat(messBuff, "\"\r\n"); 208*03831d35Sstevel (void) printf(messBuff); 209*03831d35Sstevel datap += entry.paramLen; 210*03831d35Sstevel } 211*03831d35Sstevel 212*03831d35Sstevel ADM_Free(&Message); 213*03831d35Sstevel } 214*03831d35Sstevel 215*03831d35Sstevel static int 216*03831d35Sstevel ADM_Process_new_event_log(int all) 217*03831d35Sstevel { 218*03831d35Sstevel char timebuf[32]; 219*03831d35Sstevel char messBuff[256]; 220*03831d35Sstevel char eventMsgBuf[256]; 221*03831d35Sstevel rscp_msg_t Message; 222*03831d35Sstevel struct timespec Timeout; 223*03831d35Sstevel dp_get_event_log2_r_t *rscReply; 224*03831d35Sstevel char *datap; 225*03831d35Sstevel dp_event_log_entry_t entry; 226*03831d35Sstevel int i, len, entryhdrsize, sent_ok; 227*03831d35Sstevel rsci64 events_remaining, seqno; 228*03831d35Sstevel rsci16 request_size, returned_events; 229*03831d35Sstevel dp_get_event_log2_t rscCmd; 230*03831d35Sstevel 231*03831d35Sstevel ADM_Start(); 232*03831d35Sstevel 233*03831d35Sstevel /* 234*03831d35Sstevel * Start by sending a zero-length request to ALOM, so that 235*03831d35Sstevel * we can learn the length of the console log. We expect 236*03831d35Sstevel * ALOM to return the length of the entire log. We get 237*03831d35Sstevel * a snapshot of the length of the log here - it may however 238*03831d35Sstevel * continue to grow as we're reading it. We read only as 239*03831d35Sstevel * much of the log as we get in this snapshot. 240*03831d35Sstevel * 241*03831d35Sstevel * If the command fails, we quietly return failure here so 242*03831d35Sstevel * that the caller can re-try with the old/legacy command. 243*03831d35Sstevel */ 244*03831d35Sstevel rscCmd.start_seq = 0; 245*03831d35Sstevel rscCmd.length = 0; 246*03831d35Sstevel Message.type = DP_GET_EVENT_LOG2; 247*03831d35Sstevel Message.len = sizeof (rscCmd); 248*03831d35Sstevel Message.data = (char *)&rscCmd; 249*03831d35Sstevel if (ADM_Send_ret(&Message) != 0) { 250*03831d35Sstevel return (1); 251*03831d35Sstevel } 252*03831d35Sstevel 253*03831d35Sstevel Timeout.tv_nsec = 0; 254*03831d35Sstevel Timeout.tv_sec = ADM_TIMEOUT; 255*03831d35Sstevel ADM_Recv(&Message, &Timeout, 256*03831d35Sstevel DP_GET_EVENT_LOG2_R, sizeof (*rscReply)); 257*03831d35Sstevel 258*03831d35Sstevel rscReply = (dp_get_event_log2_r_t *)Message.data; 259*03831d35Sstevel 260*03831d35Sstevel /* 261*03831d35Sstevel * Fetch an fixed number of events from the end of 262*03831d35Sstevel * the log if at least that many exist, and we were not 263*03831d35Sstevel * asked to fetch all the events. 264*03831d35Sstevel */ 265*03831d35Sstevel if ((all == 0) && 266*03831d35Sstevel (rscReply->remaining_log_events > DEFAULT_NUM_EVENTS)) { 267*03831d35Sstevel events_remaining = DEFAULT_NUM_EVENTS; 268*03831d35Sstevel seqno = (rscReply->remaining_log_events + 269*03831d35Sstevel rscReply->next_seq) - events_remaining; 270*03831d35Sstevel } else { 271*03831d35Sstevel events_remaining = rscReply->remaining_log_events; 272*03831d35Sstevel seqno = rscReply->next_seq; 273*03831d35Sstevel } 274*03831d35Sstevel request_size = sizeof (rscReply->buffer); 275*03831d35Sstevel ADM_Free(&Message); 276*03831d35Sstevel 277*03831d35Sstevel /* 278*03831d35Sstevel * This loop runs as long as there is data in the log, or until 279*03831d35Sstevel * we hit the default limit (above). It's possible that ALOM may 280*03831d35Sstevel * shrink the log - we need to account for this. If ALOM returns 281*03831d35Sstevel * no data, we bail out. 282*03831d35Sstevel */ 283*03831d35Sstevel while (events_remaining) { 284*03831d35Sstevel rscCmd.start_seq = seqno; 285*03831d35Sstevel rscCmd.length = request_size; 286*03831d35Sstevel Message.type = DP_GET_EVENT_LOG2; 287*03831d35Sstevel Message.len = sizeof (rscCmd); 288*03831d35Sstevel Message.data = (char *)&rscCmd; 289*03831d35Sstevel ADM_Send(&Message); 290*03831d35Sstevel 291*03831d35Sstevel Timeout.tv_nsec = 0; 292*03831d35Sstevel Timeout.tv_sec = ADM_TIMEOUT; 293*03831d35Sstevel ADM_Recv(&Message, &Timeout, 294*03831d35Sstevel DP_GET_EVENT_LOG2_R, sizeof (*rscReply)); 295*03831d35Sstevel 296*03831d35Sstevel rscReply = (dp_get_event_log2_r_t *)Message.data; 297*03831d35Sstevel 298*03831d35Sstevel /* If ALOM returns zero events, we're done. */ 299*03831d35Sstevel returned_events = rscReply->num_events; 300*03831d35Sstevel if (returned_events == 0) { 301*03831d35Sstevel ADM_Free(&Message); 302*03831d35Sstevel break; 303*03831d35Sstevel } 304*03831d35Sstevel 305*03831d35Sstevel /* 306*03831d35Sstevel * if the event at the original sequence number is no 307*03831d35Sstevel * longer in the log, print a message 308*03831d35Sstevel */ 309*03831d35Sstevel if (seqno + returned_events < rscReply->next_seq) { 310*03831d35Sstevel printf(gettext("\nscadm: lost %d events\n"), 311*03831d35Sstevel rscReply->next_seq - (seqno + returned_events)); 312*03831d35Sstevel } 313*03831d35Sstevel 314*03831d35Sstevel /* 315*03831d35Sstevel * get ready for next main loop iteration 316*03831d35Sstevel */ 317*03831d35Sstevel seqno = rscReply->next_seq; 318*03831d35Sstevel events_remaining -= returned_events; 319*03831d35Sstevel 320*03831d35Sstevel /* Print the event log messages */ 321*03831d35Sstevel datap = rscReply->buffer; 322*03831d35Sstevel 323*03831d35Sstevel for (i = 0; i < returned_events; i++) { 324*03831d35Sstevel entryhdrsize = sizeof (entry) - sizeof (entry.param); 325*03831d35Sstevel (void) memcpy(&entry, datap, entryhdrsize); 326*03831d35Sstevel datap += entryhdrsize; 327*03831d35Sstevel (void) memcpy(&entry.param, datap, entry.paramLen); 328*03831d35Sstevel (void) strftime(timebuf, sizeof (timebuf), 329*03831d35Sstevel "%b %d %H:%M:%S", 330*03831d35Sstevel gmtime((time_t *)&entry.eventTime)); 331*03831d35Sstevel (void) sprintf(messBuff, "%s : %08lx: \"", timebuf, 332*03831d35Sstevel entry.eventId); 333*03831d35Sstevel len = expandEventLogMessage(entry.eventId, entry.param, 334*03831d35Sstevel entry.paramLen, eventMsgBuf); 335*03831d35Sstevel (void) strncat(messBuff, eventMsgBuf, len); 336*03831d35Sstevel (void) strcat(messBuff, "\"\r\n"); 337*03831d35Sstevel (void) printf(messBuff); 338*03831d35Sstevel datap += entry.paramLen; 339*03831d35Sstevel } 340*03831d35Sstevel 341*03831d35Sstevel ADM_Free(&Message); 342*03831d35Sstevel } 343*03831d35Sstevel return (0); 344*03831d35Sstevel } 345*03831d35Sstevel 346*03831d35Sstevel void 347*03831d35Sstevel ADM_Process_event_log(int all) 348*03831d35Sstevel { 349*03831d35Sstevel if (ADM_Process_new_event_log(all) != 0) { 350*03831d35Sstevel ADM_Process_old_event_log(); 351*03831d35Sstevel } 352*03831d35Sstevel } 353