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 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
24 */
25
26 #include <fmdump.h>
27 #include <stdio.h>
28 #include <strings.h>
29 #include <alloca.h>
30
31 /*ARGSUSED*/
32 static int
33 flt_short(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
34 {
35 char buf[32], str[32];
36 char *class = NULL, *uuid = "-", *code = "-";
37
38 static const struct {
39 const char *class;
40 const char *tag;
41 } tags[] = {
42 { FM_LIST_SUSPECT_CLASS, "Diagnosed" },
43 { FM_LIST_REPAIRED_CLASS, "Repaired" },
44 { FM_LIST_RESOLVED_CLASS, "Resolved" },
45 { FM_LIST_UPDATED_CLASS, "Updated" },
46 { FM_LIST_ISOLATED_CLASS, "Isolated" },
47 };
48
49 (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_UUID, &uuid);
50 (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_DIAG_CODE, &code);
51
52 (void) nvlist_lookup_string(rp->rec_nvl, FM_CLASS, &class);
53 if (class != NULL) {
54 int i;
55
56 for (i = 0; i < sizeof (tags) / sizeof (tags[0]); i++) {
57 if (strcmp(class, tags[i].class) == 0) {
58 (void) snprintf(str, sizeof (str), "%s %s",
59 code, tags[i].tag);
60 code = str;
61 break;
62 }
63 }
64 }
65
66 fmdump_printf(fp, "%-20s %-32s %s\n",
67 fmdump_date(buf, sizeof (buf), rp), uuid, code);
68
69 return (0);
70 }
71
72 static int
73 flt_verb1(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
74 {
75 uint_t i, size = 0;
76 nvlist_t **nva;
77 uint8_t *ba;
78
79 (void) flt_short(lp, rp, fp);
80 (void) nvlist_lookup_uint32(rp->rec_nvl, FM_SUSPECT_FAULT_SZ, &size);
81
82 if (size != 0) {
83 (void) nvlist_lookup_nvlist_array(rp->rec_nvl,
84 FM_SUSPECT_FAULT_LIST, &nva, &size);
85 (void) nvlist_lookup_uint8_array(rp->rec_nvl,
86 FM_SUSPECT_FAULT_STATUS, &ba, &size);
87 }
88
89 for (i = 0; i < size; i++) {
90 char *class = NULL, *rname = NULL, *aname = NULL, *fname = NULL;
91 char *loc = NULL;
92 nvlist_t *fru, *asru, *rsrc;
93 uint8_t pct = 0;
94
95 (void) nvlist_lookup_uint8(nva[i], FM_FAULT_CERTAINTY, &pct);
96 (void) nvlist_lookup_string(nva[i], FM_CLASS, &class);
97
98 if (nvlist_lookup_nvlist(nva[i], FM_FAULT_FRU, &fru) == 0)
99 fname = fmdump_nvl2str(fru);
100
101 if (nvlist_lookup_nvlist(nva[i], FM_FAULT_ASRU, &asru) == 0)
102 aname = fmdump_nvl2str(asru);
103
104 if (nvlist_lookup_nvlist(nva[i], FM_FAULT_RESOURCE, &rsrc) == 0)
105 rname = fmdump_nvl2str(rsrc);
106
107 if (nvlist_lookup_string(nva[i], FM_FAULT_LOCATION, &loc)
108 == 0) {
109 if (fname && strncmp(fname, FM_FMRI_LEGACY_HC_PREFIX,
110 sizeof (FM_FMRI_LEGACY_HC_PREFIX)) == 0)
111 loc = fname + sizeof (FM_FMRI_LEGACY_HC_PREFIX);
112 }
113
114
115 fmdump_printf(fp, " %3u%% %s",
116 pct, class ? class : "-");
117
118 if (ba[i] & FM_SUSPECT_FAULTY)
119 fmdump_printf(fp, "\n\n");
120 else if (ba[i] & FM_SUSPECT_NOT_PRESENT)
121 fmdump_printf(fp, "\tRemoved\n\n");
122 else if (ba[i] & FM_SUSPECT_REPLACED)
123 fmdump_printf(fp, "\tReplaced\n\n");
124 else if (ba[i] & FM_SUSPECT_REPAIRED)
125 fmdump_printf(fp, "\tRepair Attempted\n\n");
126 else if (ba[i] & FM_SUSPECT_ACQUITTED)
127 fmdump_printf(fp, "\tAcquitted\n\n");
128 else
129 fmdump_printf(fp, "\n\n");
130
131 fmdump_printf(fp, " Problem in: %s\n",
132 rname ? rname : "-");
133
134 fmdump_printf(fp, " Affects: %s\n",
135 aname ? aname : "-");
136
137 fmdump_printf(fp, " FRU: %s\n",
138 fname ? fname : "-");
139
140 fmdump_printf(fp, " Location: %s\n\n",
141 loc ? loc : "-");
142
143 free(fname);
144 free(aname);
145 free(rname);
146 }
147
148 return (0);
149 }
150
151 static int
152 flt_verb23_cmn(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp,
153 nvlist_prtctl_t pctl)
154 {
155 const struct fmdump_fmt *efp = &fmdump_err_ops.do_formats[FMDUMP_VERB1];
156 const struct fmdump_fmt *ffp = &fmdump_flt_ops.do_formats[FMDUMP_VERB2];
157 uint_t i;
158 char buf[32], str[32];
159 char *class = NULL, *uuid = "-", *code = "-";
160
161 (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_UUID, &uuid);
162 (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_DIAG_CODE, &code);
163
164 (void) nvlist_lookup_string(rp->rec_nvl, FM_CLASS, &class);
165 if (class != NULL && strcmp(class, FM_LIST_REPAIRED_CLASS) == 0) {
166 (void) snprintf(str, sizeof (str), "%s %s", code, "Repaired");
167 code = str;
168 }
169 if (class != NULL && strcmp(class, FM_LIST_RESOLVED_CLASS) == 0) {
170 (void) snprintf(str, sizeof (str), "%s %s", code, "Resolved");
171 code = str;
172 }
173 if (class != NULL && strcmp(class, FM_LIST_UPDATED_CLASS) == 0) {
174 (void) snprintf(str, sizeof (str), "%s %s", code, "Updated");
175 code = str;
176 }
177
178 fmdump_printf(fp, "%s\n", ffp->do_hdr);
179 fmdump_printf(fp, "%-20s.%9.9llu %-32s %s\n",
180 fmdump_year(buf, sizeof (buf), rp), rp->rec_nsec, uuid, code);
181
182 if (rp->rec_nrefs != 0)
183 fmdump_printf(fp, "\n %s\n", efp->do_hdr);
184
185 for (i = 0; i < rp->rec_nrefs; i++) {
186 fmdump_printf(fp, " ");
187 efp->do_func(lp, &rp->rec_xrefs[i], fp);
188 }
189
190 fmdump_printf(fp, "\n");
191 if (pctl)
192 nvlist_prt(rp->rec_nvl, pctl);
193 else
194 nvlist_print(fp, rp->rec_nvl);
195 fmdump_printf(fp, "\n");
196
197 return (0);
198 }
199
200 static int
201 flt_verb2(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
202 {
203 return (flt_verb23_cmn(lp, rp, fp, NULL));
204 }
205
206 static int
207 flt_pretty(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
208 {
209 nvlist_prtctl_t pctl;
210 int rc;
211
212 if ((pctl = nvlist_prtctl_alloc()) != NULL) {
213 nvlist_prtctl_setdest(pctl, fp);
214 nvlist_prtctlop_nvlist(pctl, fmdump_render_nvlist, NULL);
215 }
216
217 rc = flt_verb23_cmn(lp, rp, fp, pctl);
218
219 nvlist_prtctl_free(pctl);
220 return (rc);
221 }
222
223 /*
224 * There is a lack of uniformity in how the various entries in our diagnosis
225 * are terminated. Some end with one newline, others with two. This makes the
226 * output of fmdump -m look a bit ugly. Therefore we postprocess the message
227 * before printing it, removing consecutive occurences of newlines.
228 */
229 static void
230 postprocess_msg(char *msg)
231 {
232 int i = 0, j = 0;
233 char *buf;
234
235 if ((buf = malloc(strlen(msg) + 1)) == NULL)
236 return;
237
238 buf[j++] = msg[i++];
239 for (i = 1; i < strlen(msg); i++) {
240 if (!(msg[i] == '\n' && msg[i - 1] == '\n'))
241 buf[j++] = msg[i];
242 }
243 buf[j] = '\0';
244 (void) strncpy(msg, buf, j+1);
245 free(buf);
246 }
247
248 /*ARGSUSED*/
249 static int
250 flt_msg(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
251 {
252 char *msg;
253
254 if ((msg = fmd_msg_gettext_nv(g_msg, NULL, rp->rec_nvl)) == NULL) {
255 (void) fprintf(stderr, "%s: failed to format message: %s\n",
256 g_pname, strerror(errno));
257 g_errs++;
258 return (-1);
259 } else {
260 postprocess_msg(msg);
261 fmdump_printf(fp, "%s\n", msg);
262 free(msg);
263 }
264
265 return (0);
266 }
267
268 const fmdump_ops_t fmdump_flt_ops = {
269 "fault", {
270 {
271 "TIME UUID SUNW-MSG-ID "
272 "EVENT",
273 (fmd_log_rec_f *)flt_short
274 }, {
275 "TIME UUID SUNW-MSG-ID "
276 "EVENT",
277 (fmd_log_rec_f *)flt_verb1
278 }, {
279 "TIME UUID"
280 " SUNW-MSG-ID",
281 (fmd_log_rec_f *)flt_verb2
282 }, {
283 "TIME UUID"
284 " SUNW-MSG-ID",
285 (fmd_log_rec_f *)flt_pretty
286 }, {
287 NULL,
288 (fmd_log_rec_f *)flt_msg
289 }, {
290 NULL,
291 (fmd_log_rec_f *)fmdump_print_json
292 } }
293 };