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 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * consolelog.c: support for the scadm consolelog option (to display the
29  * service processor console log)
30  */
31 
32 #include <libintl.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <time.h>  /* required by librsc.h */
36 #include <limits.h>
37 
38 #include "librsc.h"
39 #include "adm.h"
40 
41 /* #define DEBUG */
42 
43 void
ADM_Process_console_log(int all)44 ADM_Process_console_log(int all)
45 {
46 	rscp_msg_t		Message;
47 	struct timespec		Timeout;
48 	dp_get_console_log_r_t	*rscReply;
49 	rsci64			bytes_remaining, seqno;
50 	rsci16			request_size, response_size;
51 	dp_get_console_log_t	rscCmd;
52 
53 	ADM_Start();
54 
55 	/*
56 	 * Start by sending a zero-length request to ALOM, so that
57 	 * we can learn the length of the console log.  We expect
58 	 * ALOM to return the length of the entire log.  We get
59 	 * a snapshot of the length of the log here - it may however
60 	 * continue to grow as we're reading it.  We read only as
61 	 * much of the log as we get in this snapshot.
62 	 */
63 	rscCmd.start_seq = 0;
64 	rscCmd.length = 0;
65 	Message.type = DP_GET_CONSOLE_LOG;
66 	Message.len = sizeof (rscCmd);
67 	Message.data = (char *)&rscCmd;
68 	ADM_Send(&Message);
69 
70 	Timeout.tv_nsec = 0;
71 	Timeout.tv_sec  = ADM_TIMEOUT;
72 	ADM_Recv(&Message, &Timeout,
73 	    DP_GET_CONSOLE_LOG_R, sizeof (*rscReply));
74 
75 	rscReply = (dp_get_console_log_r_t *)Message.data;
76 
77 	/*
78 	 * If we do not want the whole log, and the log is bigger than
79 	 * the length limit, then fetch just the last ADM_DEFAULT_LOG_LENGTH
80 	 * bytes from the log.  Else just get the whole thing.
81 	 */
82 	if ((all == 0) && (rscReply->remaining_log_bytes >
83 	    ADM_DEFAULT_LOG_LENGTH)) {
84 		bytes_remaining = ADM_DEFAULT_LOG_LENGTH;
85 		seqno = (rscReply->remaining_log_bytes +
86 		    rscReply->next_seq) - bytes_remaining;
87 	} else {
88 		bytes_remaining = rscReply->remaining_log_bytes;
89 		seqno = rscReply->next_seq;
90 	}
91 	request_size = sizeof (rscReply->buffer);
92 	ADM_Free(&Message);
93 
94 	/*
95 	 * Timeout for RSC response.
96 	 */
97 	Timeout.tv_nsec = 0;
98 	Timeout.tv_sec  = ADM_TIMEOUT;
99 
100 	/*
101 	 * This loop runs as long as there is data in the log, or until
102 	 * we hit the default limit (above).  It's possible that ALOM may
103 	 * shrink the log - we need to account for this.  If ALOM returns
104 	 * no data, we bail out.
105 	 */
106 	while (bytes_remaining) {
107 		rscCmd.start_seq = seqno;
108 		rscCmd.length = (bytes_remaining < request_size) ?
109 		    bytes_remaining : request_size;
110 		Message.type = DP_GET_CONSOLE_LOG;
111 		Message.len = sizeof (rscCmd);
112 		Message.data = (char *)&rscCmd;
113 		ADM_Send(&Message);
114 
115 		ADM_Recv(&Message, &Timeout,
116 		    DP_GET_CONSOLE_LOG_R, sizeof (*rscReply));
117 
118 		rscReply = (dp_get_console_log_r_t *)Message.data;
119 
120 		/* If ALOM returns zero bytes, we're done. */
121 		response_size = rscReply->length;
122 		if (response_size == 0) {
123 			ADM_Free(&Message);
124 			break;
125 		}
126 		bytes_remaining -= response_size;
127 		if (rscReply->remaining_log_bytes < bytes_remaining) {
128 			bytes_remaining = rscReply->remaining_log_bytes;
129 		}
130 
131 		/*
132 		 * If the byte at the original sequence number is no
133 		 * longer in the log, print a message.
134 		 */
135 		if (rscReply->next_seq > seqno + response_size) {
136 			printf(gettext("\nscadm: lost %d bytes of log data\n"),
137 			    rscReply->next_seq - (seqno + response_size));
138 		}
139 		seqno = rscReply->next_seq;
140 
141 		/* Print the console log */
142 		if (fwrite(rscReply->buffer, sizeof (char), response_size,
143 		    stdout) != response_size) {
144 			perror(gettext("\ncouldn't write console log buffer"
145 			    " to stdout"));
146 			ADM_Free(&Message);
147 			break;
148 		}
149 		ADM_Free(&Message);
150 	}
151 	putchar('\n');
152 }
153