xref: /illumos-gate/usr/src/cmd/scadm/sparc/mpxu/common/eventlog.c (revision 03831d35f7499c87d51205817c93e9a8d42c4bae)
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