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