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.
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * eventlog.c: support for the scadm loghistory option (to display the
31 * service processor log history)
37 #include <time.h> /* required by librsc.h */
42 #include "event_mess.h"
44 #define BACKSLASH_ESCAPE '\\'
49 getEventLogMessage(int eventId
)
56 category
= eventId
>> 16;
57 event
= eventId
&0x0000ffff;
59 alertCategory
= rsc_alerts
[category
];
61 alertMessage
= alertCategory
[event
];
67 return (alertMessage
);
74 * getNextEventLogParam
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.
81 getNextEventLogParam(char *mess
)
86 /* ESCAPE means interpret the next character literally */
87 if ((p
!= mess
) && (*(p
-1) == BACKSLASH_ESCAPE
)) {
92 if ((*p
== TAB
) && (*(p
+1) == TAB
)) {
93 /* Double tab means end of list */
100 /* return pointer to char after TAB */
107 * expandEventLogMessage
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.
115 expandEventLogMessage(int eventId
, char *messParams
, size_t messParamsLen
,
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"));
131 /* No message parameters to copy */
132 if (messParamsLen
== 0) {
133 (void) strcpy(buf
, alertMessage
);
134 return (strlen(buf
));
137 /* A %s in the base message means we expand with a parameter */
138 if (strstr(alertMessage
, "%s")) {
144 if ((*s
== '%') && (*(s
+1) == 's')) {
148 while ((*p
) && (*p
!= TAB
)) {
152 /* Get next parameter on list for next %s */
153 param
= getNextEventLogParam(param
);
156 } while ((*d
++ = *s
++));
159 /* If no %s tokens to expand, just copy message */
160 (void) strcpy(buf
, alertMessage
);
163 return (strlen(buf
));
168 ADM_Process_old_event_log()
172 char eventMsgBuf
[256];
174 struct timespec Timeout
;
175 dp_get_event_log_r_t
*rscReply
;
177 dp_event_log_entry_t entry
;
178 int i
, len
, entryhdrsize
;
182 Message
.type
= DP_GET_EVENT_LOG
;
188 Timeout
.tv_sec
= ADM_TIMEOUT
;
189 ADM_Recv(&Message
, &Timeout
,
190 DP_GET_EVENT_LOG_R
, sizeof (*rscReply
));
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
,
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
;
216 ADM_Process_new_event_log(int all
)
220 char eventMsgBuf
[256];
222 struct timespec Timeout
;
223 dp_get_event_log2_r_t
*rscReply
;
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
;
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.
241 * If the command fails, we quietly return failure here so
242 * that the caller can re-try with the old/legacy command.
244 rscCmd
.start_seq
= 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) {
254 Timeout
.tv_sec
= ADM_TIMEOUT
;
255 ADM_Recv(&Message
, &Timeout
,
256 DP_GET_EVENT_LOG2_R
, sizeof (*rscReply
));
258 rscReply
= (dp_get_event_log2_r_t
*)Message
.data
;
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.
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
;
271 events_remaining
= rscReply
->remaining_log_events
;
272 seqno
= rscReply
->next_seq
;
274 request_size
= sizeof (rscReply
->buffer
);
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.
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
;
292 Timeout
.tv_sec
= ADM_TIMEOUT
;
293 ADM_Recv(&Message
, &Timeout
,
294 DP_GET_EVENT_LOG2_R
, sizeof (*rscReply
));
296 rscReply
= (dp_get_event_log2_r_t
*)Message
.data
;
298 /* If ALOM returns zero events, we're done. */
299 returned_events
= rscReply
->num_events
;
300 if (returned_events
== 0) {
306 * if the event at the original sequence number is no
307 * longer in the log, print a message
309 if (seqno
+ returned_events
< rscReply
->next_seq
) {
310 printf(gettext("\nscadm: lost %d events\n"),
311 rscReply
->next_seq
- (seqno
+ returned_events
));
315 * get ready for next main loop iteration
317 seqno
= rscReply
->next_seq
;
318 events_remaining
-= returned_events
;
320 /* Print the event log messages */
321 datap
= rscReply
->buffer
;
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
),
330 gmtime((time_t *)&entry
.eventTime
));
331 (void) sprintf(messBuff
, "%s : %08lx: \"", timebuf
,
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
;
347 ADM_Process_event_log(int all
)
349 if (ADM_Process_new_event_log(all
) != 0) {
350 ADM_Process_old_event_log();