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