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