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