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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/utsname.h>
34 #include <stdarg.h>
35 #include <syslog.h>
36 #include <sys/openpromio.h>
37 #include <libintl.h>
38 #include "pdevinfo.h"
39 #include "display.h"
40
41 #if !defined(TEXT_DOMAIN)
42 #define TEXT_DOMAIN "SYS_TEST"
43 #endif
44
45 /*
46 * external data
47 */
48 extern int print_flag;
49 extern int logging;
50
51 /*
52 * The following macros for dealing with raw output from the Mostek 48T02
53 * were borrowed from the kernel. Openboot passes the raw Mostek data
54 * thru the device tree, and there are no library routines to deal with
55 * this data.
56 */
57
58 /*
59 * Tables to convert a single byte from binary-coded decimal (BCD).
60 */
61 static uchar_t bcd_to_byte[256] = { /* CSTYLED */
62 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
63 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0,
64 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0,
65 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0,
66 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0, 0, 0, 0, 0, 0,
67 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, 0, 0,
68 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, 0, 0, 0, 0, 0,
69 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, 0, 0, 0,
70 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0,
71 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
72 };
73
74 #define BCD_TO_BYTE(x) bcd_to_byte[(x) & 0xff]
75 #define YRBASE 68
76
77 static int days_thru_month[64] = {
78 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366, 0, 0,
79 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0,
80 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0,
81 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0,
82 };
83
84 /*
85 * This function takes the raw Mostek data from the device tree translates
86 * it into UNIXC time (secs since Jan 1, 1970) and returns a string from
87 * ctime(3c).
88 */
89 char *
get_time(uchar_t * mostek)90 get_time(uchar_t *mostek)
91 {
92 time_t utc;
93 int sec, min, hour, day, month, year;
94
95 year = BCD_TO_BYTE(mostek[6]) + YRBASE;
96 month = BCD_TO_BYTE(mostek[5] & 0x1f) + ((year & 3) << 4);
97 day = BCD_TO_BYTE(mostek[4] & 0x3f);
98 hour = BCD_TO_BYTE(mostek[2] & 0x3f);
99 min = BCD_TO_BYTE(mostek[1] & 0x7f);
100 sec = BCD_TO_BYTE(mostek[0] & 0x7f);
101
102 utc = (year - 70); /* next 3 lines: utc = 365y + y/4 */
103 utc += (utc << 3) + (utc << 6);
104 utc += (utc << 2) + ((year - 69) >> 2);
105 utc += days_thru_month[month] + day - 1;
106 utc = (utc << 3) + (utc << 4) + hour; /* 24 * day + hour */
107 utc = (utc << 6) - (utc << 2) + min; /* 60 * hour + min */
108 utc = (utc << 6) - (utc << 2) + sec; /* 60 * min + sec */
109
110 return (ctime((time_t *)&utc));
111 }
112
113 void
disp_powerfail(Prom_node * root)114 disp_powerfail(Prom_node *root)
115 {
116 Prom_node *pnode;
117 char *option_str = "options";
118 char *pf_str = "powerfail-time";
119 char *value_str;
120 time_t value;
121
122 pnode = dev_find_node(root, option_str);
123 if (pnode == NULL) {
124 return;
125 }
126
127 value_str = get_prop_val(find_prop(pnode, pf_str));
128 if (value_str == NULL) {
129 return;
130 }
131
132 value = (time_t)atoi(value_str);
133 if (value == 0)
134 return;
135
136 (void) log_printf(
137 dgettext(TEXT_DOMAIN,
138 "Most recent AC Power Failure:\n"));
139 (void) log_printf("=============================\n");
140 (void) log_printf("%s", ctime(&value));
141 (void) log_printf("\n");
142 }
143
144
145 /*VARARGS1*/
146 void
log_printf(char * fmt,...)147 log_printf(char *fmt, ...)
148 {
149 va_list ap;
150 int len;
151 static char bigbuf[4096];
152 char buffer[1024];
153
154 if (print_flag == 0) {
155 return;
156 }
157
158 va_start(ap, fmt);
159 if (logging != 0) {
160 len = vsprintf(buffer, fmt, ap);
161 (void) strcat(bigbuf, buffer);
162
163 /* we only call to syslog when we get the entire line. */
164 if (buffer[len-1] == '\n') {
165 syslog(LOG_DAEMON|LOG_NOTICE, bigbuf);
166 bigbuf[0] = 0;
167 }
168
169 } else {
170 (void) vprintf(fmt, ap);
171 }
172 va_end(ap);
173 }
174
175 void
print_header(int board)176 print_header(int board)
177 {
178 log_printf("\n");
179 log_printf(dgettext(TEXT_DOMAIN,
180 "Analysis for Board %d\n"), board, 0);
181 log_printf("--------------------\n", 0);
182 }
183