xref: /illumos-gate/usr/src/cmd/fm/fmdump/common/fault.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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
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
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
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
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
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, *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