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) 2018, Joyent, Inc.
24 */
25
26 #include <fmdump.h>
27 #include <stdio.h>
28 #include <strings.h>
29
30 /*ARGSUSED*/
31 static int
flt_short(fmd_log_t * lp,const fmd_log_record_t * rp,FILE * fp)32 flt_short(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
33 {
34 char buf[32], str[32];
35 char *class = NULL, *uuid = "-", *code = "-";
36
37 static const struct {
38 const char *class;
39 const char *tag;
40 } tags[] = {
41 { FM_LIST_SUSPECT_CLASS, "Diagnosed" },
42 { FM_LIST_REPAIRED_CLASS, "Repaired" },
43 { FM_LIST_RESOLVED_CLASS, "Resolved" },
44 { FM_LIST_UPDATED_CLASS, "Updated" },
45 { FM_LIST_ISOLATED_CLASS, "Isolated" },
46 };
47
48 (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_UUID, &uuid);
49 (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_DIAG_CODE, &code);
50
51 (void) nvlist_lookup_string(rp->rec_nvl, FM_CLASS, &class);
52 if (class != NULL) {
53 int i;
54
55 for (i = 0; i < sizeof (tags) / sizeof (tags[0]); i++) {
56 if (strcmp(class, tags[i].class) == 0) {
57 (void) snprintf(str, sizeof (str), "%s %s",
58 code, tags[i].tag);
59 code = str;
60 break;
61 }
62 }
63 }
64
65 fmdump_printf(fp, "%-20s %-32s %s\n",
66 fmdump_date(buf, sizeof (buf), rp), uuid, code);
67
68 return (0);
69 }
70
71 static int
flt_verb1(fmd_log_t * lp,const fmd_log_record_t * rp,FILE * fp)72 flt_verb1(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
73 {
74 uint_t i, size = 0;
75 nvlist_t **nva;
76 uint8_t *ba;
77
78 (void) flt_short(lp, rp, fp);
79 (void) nvlist_lookup_uint32(rp->rec_nvl, FM_SUSPECT_FAULT_SZ, &size);
80
81 if (size != 0) {
82 (void) nvlist_lookup_nvlist_array(rp->rec_nvl,
83 FM_SUSPECT_FAULT_LIST, &nva, &size);
84 (void) nvlist_lookup_uint8_array(rp->rec_nvl,
85 FM_SUSPECT_FAULT_STATUS, &ba, &size);
86 }
87
88 for (i = 0; i < size; i++) {
89 char *class = NULL, *rname = NULL, *aname = NULL, *fname = NULL;
90 char *loc = NULL;
91 nvlist_t *fru, *asru, *rsrc;
92 uint8_t pct = 0;
93
94 (void) nvlist_lookup_uint8(nva[i], FM_FAULT_CERTAINTY, &pct);
95 (void) nvlist_lookup_string(nva[i], FM_CLASS, &class);
96
97 if (nvlist_lookup_nvlist(nva[i], FM_FAULT_FRU, &fru) == 0)
98 fname = fmdump_nvl2str(fru);
99
100 if (nvlist_lookup_nvlist(nva[i], FM_FAULT_ASRU, &asru) == 0)
101 aname = fmdump_nvl2str(asru);
102
103 if (nvlist_lookup_nvlist(nva[i], FM_FAULT_RESOURCE, &rsrc) == 0)
104 rname = fmdump_nvl2str(rsrc);
105
106 if (nvlist_lookup_string(nva[i], FM_FAULT_LOCATION, &loc)
107 == 0) {
108 if (fname && strncmp(fname, FM_FMRI_LEGACY_HC_PREFIX,
109 sizeof (FM_FMRI_LEGACY_HC_PREFIX)) == 0)
110 loc = fname + sizeof (FM_FMRI_LEGACY_HC_PREFIX);
111 }
112
113
114 fmdump_printf(fp, " %3u%% %s",
115 pct, class ? class : "-");
116
117 if (ba[i] & FM_SUSPECT_FAULTY)
118 fmdump_printf(fp, "\n\n");
119 else if (ba[i] & FM_SUSPECT_NOT_PRESENT)
120 fmdump_printf(fp, "\tRemoved\n\n");
121 else if (ba[i] & FM_SUSPECT_REPLACED)
122 fmdump_printf(fp, "\tReplaced\n\n");
123 else if (ba[i] & FM_SUSPECT_REPAIRED)
124 fmdump_printf(fp, "\tRepair Attempted\n\n");
125 else if (ba[i] & FM_SUSPECT_ACQUITTED)
126 fmdump_printf(fp, "\tAcquitted\n\n");
127 else
128 fmdump_printf(fp, "\n\n");
129
130 fmdump_printf(fp, " Problem in: %s\n",
131 rname ? rname : "-");
132
133 fmdump_printf(fp, " Affects: %s\n",
134 aname ? aname : "-");
135
136 fmdump_printf(fp, " FRU: %s\n",
137 fname ? fname : "-");
138
139 fmdump_printf(fp, " Location: %s\n\n",
140 loc ? loc : "-");
141
142 free(fname);
143 free(aname);
144 free(rname);
145 }
146
147 return (0);
148 }
149
150 static int
flt_verb23_cmn(fmd_log_t * lp,const fmd_log_record_t * rp,FILE * fp,nvlist_prtctl_t pctl)151 flt_verb23_cmn(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp,
152 nvlist_prtctl_t pctl)
153 {
154 const struct fmdump_fmt *efp = &fmdump_err_ops.do_formats[FMDUMP_VERB1];
155 const struct fmdump_fmt *ffp = &fmdump_flt_ops.do_formats[FMDUMP_VERB2];
156 uint_t i;
157 char buf[32], str[32];
158 char *class = NULL, *uuid = "-", *code = "-";
159
160 (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_UUID, &uuid);
161 (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_DIAG_CODE, &code);
162
163 (void) nvlist_lookup_string(rp->rec_nvl, FM_CLASS, &class);
164 if (class != NULL && strcmp(class, FM_LIST_REPAIRED_CLASS) == 0) {
165 (void) snprintf(str, sizeof (str), "%s %s", code, "Repaired");
166 code = str;
167 }
168 if (class != NULL && strcmp(class, FM_LIST_RESOLVED_CLASS) == 0) {
169 (void) snprintf(str, sizeof (str), "%s %s", code, "Resolved");
170 code = str;
171 }
172 if (class != NULL && strcmp(class, FM_LIST_UPDATED_CLASS) == 0) {
173 (void) snprintf(str, sizeof (str), "%s %s", code, "Updated");
174 code = str;
175 }
176
177 fmdump_printf(fp, "%s\n", ffp->do_hdr);
178 fmdump_printf(fp, "%-20s.%9.9llu %-32s %s\n",
179 fmdump_year(buf, sizeof (buf), rp), rp->rec_nsec, uuid, code);
180
181 if (rp->rec_nrefs != 0)
182 fmdump_printf(fp, "\n %s\n", efp->do_hdr);
183
184 for (i = 0; i < rp->rec_nrefs; i++) {
185 fmdump_printf(fp, " ");
186 (void) efp->do_func(lp, &rp->rec_xrefs[i], fp);
187 }
188
189 fmdump_printf(fp, "\n");
190 if (pctl)
191 nvlist_prt(rp->rec_nvl, pctl);
192 else
193 nvlist_print(fp, rp->rec_nvl);
194 fmdump_printf(fp, "\n");
195
196 return (0);
197 }
198
199 static int
flt_verb2(fmd_log_t * lp,const fmd_log_record_t * rp,FILE * fp)200 flt_verb2(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
201 {
202 return (flt_verb23_cmn(lp, rp, fp, NULL));
203 }
204
205
206 static int
flt_pretty(fmd_log_t * lp,const fmd_log_record_t * rp,FILE * fp)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
postprocess_msg(char * msg)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
flt_msg(fmd_log_t * lp,const fmd_log_record_t * rp,FILE * fp)250 flt_msg(fmd_log_t *lp, const fmd_log_record_t *rp, FILE *fp)
251 {
252 char *msg, *uuid = "-", *code = "-";
253
254 if ((msg = fmd_msg_gettext_nv(g_msg, NULL, rp->rec_nvl)) == NULL) {
255 (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_UUID,
256 &uuid);
257 (void) nvlist_lookup_string(rp->rec_nvl, FM_SUSPECT_DIAG_CODE,
258 &code);
259 (void) fprintf(stderr, "%s: failed to format message for "
260 "diagcode %s, event %s: %s\n\n", g_pname, code, uuid,
261 strerror(errno));
262 g_errs++;
263 } else {
264 postprocess_msg(msg);
265 fmdump_printf(fp, "%s\n", msg);
266 free(msg);
267 }
268
269 return (0);
270 }
271
272 const fmdump_ops_t fmdump_flt_ops = {
273 "fault", {
274 {
275 "TIME UUID SUNW-MSG-ID "
276 "EVENT",
277 (fmd_log_rec_f *)flt_short
278 }, {
279 "TIME UUID SUNW-MSG-ID "
280 "EVENT",
281 (fmd_log_rec_f *)flt_verb1
282 }, {
283 "TIME UUID"
284 " SUNW-MSG-ID",
285 (fmd_log_rec_f *)flt_verb2
286 }, {
287 "TIME UUID"
288 " SUNW-MSG-ID",
289 (fmd_log_rec_f *)flt_pretty
290 }, {
291 NULL,
292 (fmd_log_rec_f *)flt_msg
293 }, {
294 NULL,
295 (fmd_log_rec_f *)fmdump_print_json
296 } }
297 };
298