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