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 *
getEventLogMessage(int eventId)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 *
getNextEventLogParam(char * mess)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
expandEventLogMessage(int eventId,char * messParams,size_t messParamsLen,char * buf)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
ADM_Process_old_event_log()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
ADM_Process_new_event_log(int all)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
ADM_Process_event_log(int all)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