xref: /onnv-gate/usr/src/cmd/fm/fmadm/common/faulty.c (revision 5255:8dc347a9bd70)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*5255Sstephh  * Common Development and Distribution License (the "License").
6*5255Sstephh  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*5255Sstephh  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
28*5255Sstephh #include <sys/types.h>
29*5255Sstephh #include <fmadm.h>
30*5255Sstephh #include <errno.h>
31*5255Sstephh #include <limits.h>
320Sstevel@tonic-gate #include <strings.h>
33*5255Sstephh #include <stdio.h>
34*5255Sstephh #include <unistd.h>
35*5255Sstephh #include <sys/wait.h>
36*5255Sstephh #include <sys/stat.h>
37*5255Sstephh #include <fcntl.h>
38*5255Sstephh #include <fm/fmd_log.h>
39*5255Sstephh #include <sys/fm/protocol.h>
40*5255Sstephh #include <fm/libtopo.h>
41*5255Sstephh #include <fm/fmd_adm.h>
42*5255Sstephh #include <dlfcn.h>
43*5255Sstephh #include <sys/systeminfo.h>
44*5255Sstephh #include <sys/utsname.h>
45*5255Sstephh #include <libintl.h>
46*5255Sstephh #include <locale.h>
47*5255Sstephh #include <sys/smbios.h>
48*5255Sstephh #include <libdevinfo.h>
49*5255Sstephh #include <stdlib.h>
50*5255Sstephh 
51*5255Sstephh #define	offsetof(s, m)	((size_t)(&(((s*)0)->m)))
52*5255Sstephh 
53*5255Sstephh /*
54*5255Sstephh  * catalog_setup() must be called to setup support functions.
55*5255Sstephh  * Fault records are added to catalog by calling add_fault_record_to_catalog()
56*5255Sstephh  * records are stored in order of importance to the system.
57*5255Sstephh  * If -g flag is set or not_suppressed is not set and the class fru, fault,
58*5255Sstephh  * type are the same then details are merged into an existing record, with uuid
59*5255Sstephh  * records are stored in time order.
60*5255Sstephh  * For each record information is extracted from nvlist and merged into linked
61*5255Sstephh  * list each is checked for identical records for which percentage certainty are
62*5255Sstephh  * added together.
63*5255Sstephh  * print_catalog() is called to print out catalog and release external resources
64*5255Sstephh  *
65*5255Sstephh  *                         /---------------\
66*5255Sstephh  *	status_rec_list -> |               | -|
67*5255Sstephh  *                         \---------------/
68*5255Sstephh  *                                \/
69*5255Sstephh  *                         /---------------\    /-------\    /-------\
70*5255Sstephh  *      status_fru_list    | status_record | -> | uurec | -> | uurec | -|
71*5255Sstephh  *            \/           |               | |- |       | <- |       |
72*5255Sstephh  *      /-------------\    |               |    \-------/    \-------/
73*5255Sstephh  *      |             | -> |               |       \/           \/
74*5255Sstephh  *      \-------------/    |               |    /-------\    /-------\
75*5255Sstephh  *            \/           |               | -> | asru  | -> | asru  |
76*5255Sstephh  *            ---          |               |    |       | <- |       |
77*5255Sstephh  *                         |               |    \-------/    \-------/
78*5255Sstephh  *      status_asru_list   |  class        |
79*5255Sstephh  *            \/           |  resource     |    /-------\    /-------\
80*5255Sstephh  *      /-------------\    |  fru          | -> | list  | -> | list  |
81*5255Sstephh  *      |             | -> |  serial       |    |       | <- |       |
82*5255Sstephh  *      \-------------/    |               |    \-------/    \-------/
83*5255Sstephh  *            \/           \---------------/
84*5255Sstephh  *            ---               \/    /\
85*5255Sstephh  *                         /---------------\
86*5255Sstephh  *                         | status_record |
87*5255Sstephh  *                         \---------------/
88*5255Sstephh  *
89*5255Sstephh  * Fmadm faulty takes a number of options which affect the format of the
90*5255Sstephh  * output displayed. By default, the display reports the FRU and ASRU along
91*5255Sstephh  * with other information on per-case basis as in the example below.
92*5255Sstephh  *
93*5255Sstephh  * --------------- ------------------------------------  -------------- -------
94*5255Sstephh  * TIME            EVENT-ID                              MSG-ID         SEVERITY
95*5255Sstephh  * --------------- ------------------------------------  -------------- -------
96*5255Sstephh  * Sep 21 10:01:36 d482f935-5c8f-e9ab-9f25-d0aaafec1e6c  AMD-8000-2F    Major
97*5255Sstephh  *
98*5255Sstephh  * Fault class	: fault.memory.dimm_sb
99*5255Sstephh  * Affects	: mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0
100*5255Sstephh  *		    degraded but still in service
101*5255Sstephh  * FRU		: "CPU 0 DIMM 0" (hc://.../memory-controller=0/dimm=0)
102*5255Sstephh  *		    faulty
103*5255Sstephh  *
104*5255Sstephh  * Description	: The number of errors associated with this memory module has
105*5255Sstephh  *		exceeded acceptable levels.  Refer to
106*5255Sstephh  *		http://sun.com/msg/AMD-8000-2F for more information.
107*5255Sstephh  *
108*5255Sstephh  * Response	: Pages of memory associated with this memory module are being
109*5255Sstephh  *		removed from service as errors are reported.
110*5255Sstephh  *
111*5255Sstephh  * Impact	: Total system memory capacity will be reduced as pages are
112*5255Sstephh  *		retired.
113*5255Sstephh  *
114*5255Sstephh  * Action	: Schedule a repair procedure to replace the affected memory
115*5255Sstephh  *		module.  Use fmdump -v -u <EVENT_ID> to identify the module.
116*5255Sstephh  *
117*5255Sstephh  * The -v flag is similar, but adds some additonal information such as the
118*5255Sstephh  * resource. The -s flag is also similar but just gives the top line summary.
119*5255Sstephh  * All these options (ie without the -f or -r flags) use the print_catalog()
120*5255Sstephh  * function to do the display.
121*5255Sstephh  *
122*5255Sstephh  * The -f flag changes the output so that it appears sorted on a per-fru basis.
123*5255Sstephh  * The output is somewhat cut down compared to the default output. If -f is
124*5255Sstephh  * used, then print_fru() is used to print the output.
125*5255Sstephh  *
126*5255Sstephh  * -----------------------------------------------------------------------------
127*5255Sstephh  * "SLOT 2" (hc://.../hostbridge=3/pciexrc=3/pciexbus=4/pciexdev=0) faulty
128*5255Sstephh  * 5ca4aeb3-36...f6be-c2e8166dc484 2 suspects in this FRU total certainty 100%
129*5255Sstephh  *
130*5255Sstephh  * Description	: A problem was detected for a PCI device.
131*5255Sstephh  *		Refer to http://sun.com/msg/PCI-8000-7J for more information.
132*5255Sstephh  *
133*5255Sstephh  * Response	: One or more device instances may be disabled
134*5255Sstephh  *
135*5255Sstephh  * Impact	: Possible loss of services provided by the device instances
136*5255Sstephh  *		associated with this fault
137*5255Sstephh  *
138*5255Sstephh  * Action	: Schedule a repair procedure to replace the affected device.
139*5255Sstephh  * 		Use fmdump -v -u <EVENT_ID> to identify the device or contact
140*5255Sstephh  *		Sun for support.
141*5255Sstephh  *
142*5255Sstephh  * The -r flag changes the output so that it appears sorted on a per-asru basis.
143*5255Sstephh  * The output is very much cut down compared to the default output, just giving
144*5255Sstephh  * the asru fmri and state. Here print_asru() is used to print the output.
145*5255Sstephh  *
146*5255Sstephh  * mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0	degraded
147*5255Sstephh  *
148*5255Sstephh  * For all fmadm faulty options, the sequence of events is
149*5255Sstephh  *
150*5255Sstephh  * 1) Walk through all the cases in the system using fmd_adm_case_iter() and
151*5255Sstephh  * for each case call dfault_rec(). This will call add_fault_record_to_catalog()
152*5255Sstephh  * This will extract the data from the nvlist and call catalog_new_record() to
153*5255Sstephh  * save the data away in various linked lists in the catalogue.
154*5255Sstephh  *
155*5255Sstephh  * 2) Once this is done, the data can be supplemented by using
156*5255Sstephh  * fmd_adm_rsrc_iter(). However this is now only necessary for the -i option.
157*5255Sstephh  *
158*5255Sstephh  * 3) Finally print_catalog(), print_fru() or print_asru() are called as
159*5255Sstephh  * appropriate to display the information from the catalogue sorted in the
160*5255Sstephh  * requested way.
161*5255Sstephh  *
162*5255Sstephh  */
163*5255Sstephh 
164*5255Sstephh typedef struct name_list {
165*5255Sstephh 	struct name_list *next;
166*5255Sstephh 	struct name_list *prev;
167*5255Sstephh 	char *name;
168*5255Sstephh 	uint8_t pct;
169*5255Sstephh 	uint8_t max_pct;
170*5255Sstephh 	ushort_t count;
171*5255Sstephh 	int status;
172*5255Sstephh } name_list_t;
173*5255Sstephh 
174*5255Sstephh typedef struct ari_list {
175*5255Sstephh 	char *ari_uuid;
176*5255Sstephh 	struct ari_list *next;
177*5255Sstephh } ari_list_t;
178*5255Sstephh 
179*5255Sstephh typedef struct uurec {
180*5255Sstephh 	struct uurec *next;
181*5255Sstephh 	struct uurec *prev;
182*5255Sstephh 	char *uuid;
183*5255Sstephh 	ari_list_t *ari_uuid_list;
184*5255Sstephh 	name_list_t *asru;
185*5255Sstephh 	uint64_t sec;
186*5255Sstephh } uurec_t;
187*5255Sstephh 
188*5255Sstephh typedef struct uurec_select {
189*5255Sstephh 	struct uurec_select *next;
190*5255Sstephh 	char *uuid;
191*5255Sstephh } uurec_select_t;
192*5255Sstephh 
193*5255Sstephh typedef struct host_id {
194*5255Sstephh 	char *chassis;
195*5255Sstephh 	char *server;
196*5255Sstephh 	char *platform;
197*5255Sstephh } hostid_t;
198*5255Sstephh 
199*5255Sstephh typedef struct host_id_list {
200*5255Sstephh 	hostid_t hostid;
201*5255Sstephh 	struct host_id_list *next;
202*5255Sstephh } host_id_list_t;
203*5255Sstephh 
204*5255Sstephh typedef struct status_record {
205*5255Sstephh 	hostid_t *host;
206*5255Sstephh 	int nrecs;
207*5255Sstephh 	uurec_t *uurec;
208*5255Sstephh 	char *severity;			/* in C locale */
209*5255Sstephh 	char *msgid;
210*5255Sstephh 	name_list_t *class;
211*5255Sstephh 	name_list_t *resource;
212*5255Sstephh 	name_list_t *asru;
213*5255Sstephh 	name_list_t *fru;
214*5255Sstephh 	name_list_t *serial;
215*5255Sstephh 	char *url;
216*5255Sstephh 	uint8_t not_suppressed;
217*5255Sstephh } status_record_t;
218*5255Sstephh 
219*5255Sstephh typedef struct sr_list {
220*5255Sstephh 	struct sr_list *next;
221*5255Sstephh 	struct sr_list *prev;
222*5255Sstephh 	struct status_record *status_record;
223*5255Sstephh } sr_list_t;
224*5255Sstephh 
225*5255Sstephh typedef struct resource_list {
226*5255Sstephh 	struct resource_list *next;
227*5255Sstephh 	struct resource_list *prev;
228*5255Sstephh 	sr_list_t *status_rec_list;
229*5255Sstephh 	char *resource;
230*5255Sstephh 	uint8_t not_suppressed;
231*5255Sstephh 	uint8_t max_pct;
232*5255Sstephh } resource_list_t;
233*5255Sstephh 
234*5255Sstephh typedef struct tgetlabel_data {
235*5255Sstephh 	char *label;
236*5255Sstephh 	char *fru;
237*5255Sstephh } tgetlabel_data_t;
2380Sstevel@tonic-gate 
239*5255Sstephh sr_list_t *status_rec_list;
240*5255Sstephh resource_list_t *status_fru_list;
241*5255Sstephh resource_list_t *status_asru_list;
242*5255Sstephh 
243*5255Sstephh static char *locale;
244*5255Sstephh static char *nlspath;
245*5255Sstephh static int max_display;
246*5255Sstephh static int max_fault = 0;
247*5255Sstephh static topo_hdl_t *topo_handle;
248*5255Sstephh static char *topo_handle_uuid;
249*5255Sstephh static host_id_list_t *host_list;
250*5255Sstephh static int n_server;
251*5255Sstephh static int opt_g;
252*5255Sstephh 
253*5255Sstephh static char *
254*5255Sstephh format_date(char *buf, size_t len, uint64_t sec)
255*5255Sstephh {
256*5255Sstephh 	if (sec > LONG_MAX) {
257*5255Sstephh 		(void) fprintf(stderr,
258*5255Sstephh 		    "record time is too large for 32-bit utility\n");
259*5255Sstephh 		(void) snprintf(buf, len, "0x%llx", sec);
260*5255Sstephh 	} else {
261*5255Sstephh 		time_t tod = (time_t)sec;
262*5255Sstephh 		(void) strftime(buf, len, "%b %d %T", localtime(&tod));
263*5255Sstephh 	}
264*5255Sstephh 
265*5255Sstephh 	return (buf);
266*5255Sstephh }
267*5255Sstephh 
268*5255Sstephh static hostid_t *
269*5255Sstephh find_hostid_in_list(char *platform, char *chassis, char *server)
270*5255Sstephh {
271*5255Sstephh 	hostid_t *rt = NULL;
272*5255Sstephh 	host_id_list_t *hostp;
273*5255Sstephh 
274*5255Sstephh 	if (platform == NULL)
275*5255Sstephh 		platform = "-";
276*5255Sstephh 	if (server == NULL)
277*5255Sstephh 		server = "-";
278*5255Sstephh 	hostp = host_list;
279*5255Sstephh 	while (hostp) {
280*5255Sstephh 		if (hostp->hostid.platform &&
281*5255Sstephh 		    strcmp(hostp->hostid.platform, platform) == 0 &&
282*5255Sstephh 		    hostp->hostid.server &&
283*5255Sstephh 		    strcmp(hostp->hostid.server, server) == 0 &&
284*5255Sstephh 		    (chassis == NULL || hostp->hostid.chassis == NULL ||
285*5255Sstephh 		    strcmp(chassis, hostp->hostid.chassis) == 0)) {
286*5255Sstephh 			rt = &hostp->hostid;
287*5255Sstephh 			break;
288*5255Sstephh 		}
289*5255Sstephh 		hostp = hostp->next;
290*5255Sstephh 	}
291*5255Sstephh 	if (rt == NULL) {
292*5255Sstephh 		hostp = malloc(sizeof (host_id_list_t));
293*5255Sstephh 		hostp->hostid.platform = strdup(platform);
294*5255Sstephh 		hostp->hostid.server = strdup(server);
295*5255Sstephh 		hostp->hostid.chassis = chassis ? strdup(chassis) : NULL;
296*5255Sstephh 		hostp->next = host_list;
297*5255Sstephh 		host_list = hostp;
298*5255Sstephh 		rt = &hostp->hostid;
299*5255Sstephh 		n_server++;
300*5255Sstephh 	}
301*5255Sstephh 	return (rt);
302*5255Sstephh }
303*5255Sstephh 
304*5255Sstephh static hostid_t *
305*5255Sstephh find_hostid(nvlist_t *nvl)
306*5255Sstephh {
307*5255Sstephh 	char *platform = NULL, *chassis = NULL, *server = NULL;
308*5255Sstephh 	nvlist_t *auth, *fmri;
309*5255Sstephh 	hostid_t *rt = NULL;
310*5255Sstephh 
311*5255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &fmri) == 0 &&
312*5255Sstephh 	    nvlist_lookup_nvlist(fmri, FM_FMRI_AUTHORITY, &auth) == 0) {
313*5255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT,
314*5255Sstephh 		    &platform);
315*5255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server);
316*5255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS,
317*5255Sstephh 		    &chassis);
318*5255Sstephh 		rt = find_hostid_in_list(platform, chassis, server);
319*5255Sstephh 	}
320*5255Sstephh 	return (rt);
321*5255Sstephh }
322*5255Sstephh 
323*5255Sstephh static void
324*5255Sstephh catalog_setup(void)
325*5255Sstephh {
326*5255Sstephh 	char *tp;
327*5255Sstephh 	int pl;
328*5255Sstephh 
329*5255Sstephh 	/*
330*5255Sstephh 	 * All FMA event dictionaries use msgfmt(1) message objects to produce
331*5255Sstephh 	 * messages, even for the C locale.  We therefore want to use dgettext
332*5255Sstephh 	 * for all message lookups, but its defined behavior in the C locale is
333*5255Sstephh 	 * to return the input string.  Since our input strings are event codes
334*5255Sstephh 	 * and not format strings, this doesn't help us.  We resolve this nit
335*5255Sstephh 	 * by setting NLSPATH to a non-existent file: the presence of NLSPATH
336*5255Sstephh 	 * is defined to force dgettext(3C) to do a full lookup even for C.
337*5255Sstephh 	 */
338*5255Sstephh 	nlspath = getenv("NLSPATH");
339*5255Sstephh 	if (nlspath == NULL)
340*5255Sstephh 		putenv("NLSPATH=/usr/lib/fm/fmd/fmd.cat");
341*5255Sstephh 	else {
342*5255Sstephh 		pl = strlen(nlspath) + sizeof ("NLSPATH=") + 1;
343*5255Sstephh 		tp = malloc(pl);
344*5255Sstephh 		(void) snprintf(tp, pl, "NLSPATH=%s", nlspath);
345*5255Sstephh 		nlspath = tp;
346*5255Sstephh 	}
347*5255Sstephh 
348*5255Sstephh 	locale = setlocale(LC_MESSAGES, "");
349*5255Sstephh }
350*5255Sstephh 
351*5255Sstephh static char *
352*5255Sstephh get_dict_url(char *id)
353*5255Sstephh {
354*5255Sstephh 	char *url = "http://sun.com/msg/";
355*5255Sstephh 	int msz = sizeof (url) + strlen(id) + 1;
356*5255Sstephh 	char *cp;
357*5255Sstephh 
358*5255Sstephh 	cp = malloc(msz);
359*5255Sstephh 	(void) snprintf(cp, msz, "%s%s", url, id);
360*5255Sstephh 	return (cp);
361*5255Sstephh }
362*5255Sstephh 
363*5255Sstephh static char *
364*5255Sstephh get_dict_msg(char *id, char *idx, int unknown, int translate)
365*5255Sstephh {
366*5255Sstephh 	char mbuf[128];
367*5255Sstephh 	char *msg;
368*5255Sstephh 	char dbuf[32];
369*5255Sstephh 	char *p;
370*5255Sstephh 	int restore_env = 0;
371*5255Sstephh 	int restore_locale = 0;
372*5255Sstephh 
373*5255Sstephh 	p = strchr(id, '-');
374*5255Sstephh 	if (p == NULL || p == id || (p - id) >= 32) {
375*5255Sstephh 		msg = mbuf;
376*5255Sstephh 	} else {
377*5255Sstephh 		strncpy(dbuf, id, (size_t)(p - id));
378*5255Sstephh 		dbuf[(size_t)(p - id)] = 0;
379*5255Sstephh 
380*5255Sstephh 		(void) snprintf(mbuf, sizeof (mbuf), "%s.%s", id, idx);
381*5255Sstephh 		if (translate == 0 || nlspath == NULL) {
382*5255Sstephh 			(void) setlocale(LC_MESSAGES, "C");
383*5255Sstephh 			restore_locale = 1;
384*5255Sstephh 		}
385*5255Sstephh 		bindtextdomain("FMD", "/usr/lib/locale");
386*5255Sstephh 		msg = dgettext(dbuf, mbuf);
387*5255Sstephh 		if (msg == mbuf) {
388*5255Sstephh 			(void) setlocale(LC_MESSAGES, "C");
389*5255Sstephh 			restore_locale = 1;
390*5255Sstephh 			msg = dgettext(dbuf, mbuf);
391*5255Sstephh 		}
392*5255Sstephh 		if (msg == mbuf) {
393*5255Sstephh 			putenv("NLSPATH=/usr/lib/fm/fmd/fmd.cat");
394*5255Sstephh 			restore_env = 1;
395*5255Sstephh 			(void) setlocale(LC_MESSAGES, "C");
396*5255Sstephh 			msg = dgettext(dbuf, mbuf);
397*5255Sstephh 		}
398*5255Sstephh 		if (restore_locale)
399*5255Sstephh 			(void) setlocale(LC_MESSAGES, locale);
400*5255Sstephh 		if (restore_env && nlspath)
401*5255Sstephh 			putenv(nlspath);
402*5255Sstephh 	}
403*5255Sstephh 	if (msg == mbuf) {
404*5255Sstephh 		if (unknown)
405*5255Sstephh 			msg = "unknown";
406*5255Sstephh 		else
407*5255Sstephh 			msg = NULL;
408*5255Sstephh 	}
409*5255Sstephh 	return (msg);
410*5255Sstephh }
411*5255Sstephh 
412*5255Sstephh /*
413*5255Sstephh  * compare two fru strings which are made up of substrings seperated by '/'
414*5255Sstephh  * return true if every substring is the same in the two strings, or if a
415*5255Sstephh  * substring is null in one.
416*5255Sstephh  */
417*5255Sstephh 
418*5255Sstephh static int
419*5255Sstephh frucmp(char *f1, char *f2)
420*5255Sstephh {
421*5255Sstephh 	char c1, c2;
422*5255Sstephh 	int i = 0;
423*5255Sstephh 
424*5255Sstephh 	for (;;) {
425*5255Sstephh 		c1 = *f1;
426*5255Sstephh 		c2 = *f2;
427*5255Sstephh 		if (c1 == c2) {
428*5255Sstephh 			i = (c1 == '/') ? 0 : i + 1;
429*5255Sstephh 		} else if (i == 0) {
430*5255Sstephh 			if (c1 == '/') {
431*5255Sstephh 				do {
432*5255Sstephh 					f2++;
433*5255Sstephh 				} while ((c2 = *f2) != 0 && c2 != '/');
434*5255Sstephh 				if (c2 == NULL)
435*5255Sstephh 					break;
436*5255Sstephh 			} else if (c2 == '/') {
437*5255Sstephh 				do {
438*5255Sstephh 					f1++;
439*5255Sstephh 				} while ((c1 = *f1) != 0 && c1 != '/');
440*5255Sstephh 				if (c1 == NULL)
441*5255Sstephh 					break;
442*5255Sstephh 			} else
443*5255Sstephh 				break;
444*5255Sstephh 		} else
445*5255Sstephh 			break;
446*5255Sstephh 		if (c1 == NULL)
447*5255Sstephh 			return (0);
448*5255Sstephh 		f1++;
449*5255Sstephh 		f2++;
450*5255Sstephh 	}
451*5255Sstephh 	return (1);
452*5255Sstephh }
453*5255Sstephh 
454*5255Sstephh static int
455*5255Sstephh tgetlabel(topo_hdl_t *thp, tnode_t *node, void *arg)
4560Sstevel@tonic-gate {
457*5255Sstephh 	int err;
458*5255Sstephh 	char *fru_name, *lname;
459*5255Sstephh 	nvlist_t *fru = NULL;
460*5255Sstephh 	int rt = TOPO_WALK_NEXT;
461*5255Sstephh 	tgetlabel_data_t *tdp = (tgetlabel_data_t *)arg;
462*5255Sstephh 
463*5255Sstephh 	if (topo_node_fru(node, &fru, NULL, &err) == 0) {
464*5255Sstephh 		if (topo_fmri_nvl2str(thp, fru, &fru_name, &err) == 0) {
465*5255Sstephh 			if (frucmp(tdp->fru, fru_name) == 0 &&
466*5255Sstephh 			    topo_node_label(node, &lname, &err) == 0) {
467*5255Sstephh 				tdp->label = strdup(lname);
468*5255Sstephh 				topo_hdl_strfree(thp, lname);
469*5255Sstephh 				rt = TOPO_WALK_TERMINATE;
470*5255Sstephh 			}
471*5255Sstephh 			topo_hdl_strfree(thp, fru_name);
472*5255Sstephh 		}
473*5255Sstephh 		nvlist_free(fru);
474*5255Sstephh 	}
475*5255Sstephh 	return (rt);
476*5255Sstephh }
477*5255Sstephh 
478*5255Sstephh static void
479*5255Sstephh label_get_topo(void)
480*5255Sstephh {
481*5255Sstephh 	int err;
482*5255Sstephh 
483*5255Sstephh 	topo_handle = topo_open(TOPO_VERSION, 0, &err);
484*5255Sstephh 	if (topo_handle) {
485*5255Sstephh 		topo_handle_uuid = topo_snap_hold(topo_handle, NULL, &err);
486*5255Sstephh 	}
487*5255Sstephh }
488*5255Sstephh 
489*5255Sstephh static void
490*5255Sstephh label_release_topo(void)
491*5255Sstephh {
492*5255Sstephh 	if (topo_handle_uuid)
493*5255Sstephh 		topo_hdl_strfree(topo_handle, topo_handle_uuid);
494*5255Sstephh 	if (topo_handle) {
495*5255Sstephh 		topo_snap_release(topo_handle);
496*5255Sstephh 		topo_close(topo_handle);
497*5255Sstephh 	}
498*5255Sstephh }
499*5255Sstephh 
500*5255Sstephh static char *
501*5255Sstephh get_fmri_label(char *fru)
502*5255Sstephh {
503*5255Sstephh 	topo_walk_t *twp;
504*5255Sstephh 	tgetlabel_data_t td;
505*5255Sstephh 	int err;
506*5255Sstephh 
507*5255Sstephh 	td.label = NULL;
508*5255Sstephh 	td.fru = fru;
509*5255Sstephh 	if (topo_handle == NULL)
510*5255Sstephh 		label_get_topo();
511*5255Sstephh 	if (topo_handle_uuid) {
512*5255Sstephh 		twp = topo_walk_init(topo_handle, FM_FMRI_SCHEME_HC,
513*5255Sstephh 		    tgetlabel, &td, &err);
514*5255Sstephh 		if (twp) {
515*5255Sstephh 			topo_walk_step(twp, TOPO_WALK_CHILD);
516*5255Sstephh 			topo_walk_fini(twp);
517*5255Sstephh 		}
518*5255Sstephh 	}
519*5255Sstephh 	return (td.label);
520*5255Sstephh }
521*5255Sstephh 
522*5255Sstephh static char *
523*5255Sstephh get_nvl2str_topo(nvlist_t *nvl)
524*5255Sstephh {
525*5255Sstephh 	char *name = NULL;
526*5255Sstephh 	char *tname;
527*5255Sstephh 	int err;
528*5255Sstephh 	char *scheme = NULL;
529*5255Sstephh 	char *mod_name = NULL;
530*5255Sstephh 	char buf[128];
531*5255Sstephh 
532*5255Sstephh 	if (topo_handle == NULL)
533*5255Sstephh 		label_get_topo();
534*5255Sstephh 	if (topo_fmri_nvl2str(topo_handle, nvl, &tname, &err) == 0) {
535*5255Sstephh 		name = strdup(tname);
536*5255Sstephh 		topo_hdl_strfree(topo_handle, tname);
537*5255Sstephh 	} else {
538*5255Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme);
539*5255Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_MOD_NAME, &mod_name);
540*5255Sstephh 		if (scheme && strcmp(scheme, FM_FMRI_SCHEME_FMD) == 0 &&
541*5255Sstephh 		    mod_name) {
542*5255Sstephh 			(void) snprintf(buf, sizeof (buf), "%s:///module/%s",
543*5255Sstephh 			    scheme, mod_name);
544*5255Sstephh 			name = strdup(buf);
545*5255Sstephh 		}
546*5255Sstephh 	}
547*5255Sstephh 	return (name);
548*5255Sstephh }
549*5255Sstephh 
550*5255Sstephh static int
551*5255Sstephh set_priority(char *s)
552*5255Sstephh {
553*5255Sstephh 	int rt = 0;
554*5255Sstephh 
555*5255Sstephh 	if (s) {
556*5255Sstephh 		if (strcmp(s, "Minor") == 0)
557*5255Sstephh 			rt = 1;
558*5255Sstephh 		else if (strcmp(s, "Major") == 0)
559*5255Sstephh 			rt = 10;
560*5255Sstephh 		else if (strcmp(s, "Critical") == 0)
561*5255Sstephh 			rt = 100;
562*5255Sstephh 	}
563*5255Sstephh 	return (rt);
564*5255Sstephh }
565*5255Sstephh 
566*5255Sstephh static int
567*5255Sstephh cmp_priority(char *s1, char *s2, uint64_t t1, uint64_t t2, uint8_t p1,
568*5255Sstephh     uint8_t p2)
569*5255Sstephh {
570*5255Sstephh 	int r1, r2;
571*5255Sstephh 	int rt;
572*5255Sstephh 
573*5255Sstephh 	r1 = set_priority(s1);
574*5255Sstephh 	r2 = set_priority(s2);
575*5255Sstephh 	rt = r1 - r2;
576*5255Sstephh 	if (rt == 0) {
577*5255Sstephh 		if (t1 > t2)
578*5255Sstephh 			rt = 1;
579*5255Sstephh 		else if (t1 < t2)
580*5255Sstephh 			rt = -1;
581*5255Sstephh 		else
582*5255Sstephh 			rt = p1 - p2;
583*5255Sstephh 	}
584*5255Sstephh 	return (rt);
585*5255Sstephh }
586*5255Sstephh 
587*5255Sstephh /*
588*5255Sstephh  * merge two lists into one, by comparing enties in new and moving into list if
589*5255Sstephh  * name is not there or free off memory for names which are already there
590*5255Sstephh  * add_pct indicates if pct is the sum or highest pct
591*5255Sstephh  */
592*5255Sstephh static name_list_t *
593*5255Sstephh merge_name_list(name_list_t **list, name_list_t *new, int add_pct)
594*5255Sstephh {
595*5255Sstephh 	name_list_t *lp, *np, *sp, *rt = NULL;
596*5255Sstephh 	int max_pct;
597*5255Sstephh 
598*5255Sstephh 	rt = *list;
599*5255Sstephh 	np = new;
600*5255Sstephh 	while (np) {
601*5255Sstephh 		lp = *list;
602*5255Sstephh 		while (lp) {
603*5255Sstephh 			if (strcmp(lp->name, np->name) == 0)
604*5255Sstephh 				break;
605*5255Sstephh 			lp = lp->next;
606*5255Sstephh 			if (lp == *list)
607*5255Sstephh 				lp = NULL;
608*5255Sstephh 		}
609*5255Sstephh 		if (np->next == new)
610*5255Sstephh 			sp = NULL;
611*5255Sstephh 		else
612*5255Sstephh 			sp = np->next;
613*5255Sstephh 		if (lp) {
614*5255Sstephh 			lp->status |= (np->status & FM_SUSPECT_FAULTY);
615*5255Sstephh 			if (add_pct) {
616*5255Sstephh 				lp->pct += np->pct;
617*5255Sstephh 				lp->count += np->count;
618*5255Sstephh 			} else if (np->pct > lp->pct) {
619*5255Sstephh 				lp->pct = np->pct;
620*5255Sstephh 			}
621*5255Sstephh 			max_pct = np->max_pct;
622*5255Sstephh 			free(np->name);
623*5255Sstephh 			free(np);
624*5255Sstephh 			np = NULL;
625*5255Sstephh 			if (max_pct > lp->max_pct) {
626*5255Sstephh 				lp->max_pct = max_pct;
627*5255Sstephh 				if (lp->max_pct > lp->prev->max_pct &&
628*5255Sstephh 				    lp != *list) {
629*5255Sstephh 					lp->prev->next = lp->next;
630*5255Sstephh 					lp->next->prev = lp->prev;
631*5255Sstephh 					np = lp;
632*5255Sstephh 				}
633*5255Sstephh 			}
634*5255Sstephh 		}
635*5255Sstephh 		if (np) {
636*5255Sstephh 			lp = *list;
637*5255Sstephh 			if (lp) {
638*5255Sstephh 				if (np->max_pct > lp->max_pct) {
639*5255Sstephh 					np->next = lp;
640*5255Sstephh 					np->prev = lp->prev;
641*5255Sstephh 					lp->prev->next = np;
642*5255Sstephh 					lp->prev = np;
643*5255Sstephh 					*list = np;
644*5255Sstephh 					rt = np;
645*5255Sstephh 				} else {
646*5255Sstephh 					lp = lp->next;
647*5255Sstephh 					while (lp != *list &&
648*5255Sstephh 					    np->max_pct < lp->max_pct) {
649*5255Sstephh 						lp = lp->next;
650*5255Sstephh 					}
651*5255Sstephh 					np->next = lp;
652*5255Sstephh 					np->prev = lp->prev;
653*5255Sstephh 					lp->prev->next = np;
654*5255Sstephh 					lp->prev = np;
655*5255Sstephh 				}
656*5255Sstephh 			} else {
657*5255Sstephh 				*list = np;
658*5255Sstephh 				np->next = np;
659*5255Sstephh 				np->prev = np;
660*5255Sstephh 				rt = np;
661*5255Sstephh 			}
662*5255Sstephh 		}
663*5255Sstephh 		np = sp;
664*5255Sstephh 	}
665*5255Sstephh 	return (rt);
666*5255Sstephh }
667*5255Sstephh 
668*5255Sstephh /*
669*5255Sstephh  * compare entries in two lists return true if the two lists have identical
670*5255Sstephh  * content. The two lists may not have entries in the same order, so we compare
671*5255Sstephh  * the size of the list as well as trying to find every entry from one list in
672*5255Sstephh  * the other.
673*5255Sstephh  */
674*5255Sstephh static int
675*5255Sstephh cmp_name_list(name_list_t *lxp1, name_list_t *lxp2)
676*5255Sstephh {
677*5255Sstephh 	name_list_t *lp1, *lp2;
678*5255Sstephh 	int l1 = 0, l2 = 0, common = 0;
679*5255Sstephh 
680*5255Sstephh 	lp2 = lxp2;
681*5255Sstephh 	while (lp2) {
682*5255Sstephh 		l2++;
683*5255Sstephh 		lp2 = lp2->next;
684*5255Sstephh 		if (lp2 == lxp2)
685*5255Sstephh 			break;
686*5255Sstephh 	}
687*5255Sstephh 	lp1 = lxp1;
688*5255Sstephh 	while (lp1) {
689*5255Sstephh 		l1++;
690*5255Sstephh 		lp2 = lxp2;
691*5255Sstephh 		while (lp2) {
692*5255Sstephh 			if (strcmp(lp2->name, lp1->name) == 0) {
693*5255Sstephh 				common++;
694*5255Sstephh 				break;
695*5255Sstephh 			}
696*5255Sstephh 			lp2 = lp2->next;
697*5255Sstephh 			if (lp2 == lxp2)
698*5255Sstephh 				break;
699*5255Sstephh 		}
700*5255Sstephh 		lp1 = lp1->next;
701*5255Sstephh 		if (lp1 == lxp1)
702*5255Sstephh 			break;
703*5255Sstephh 	}
704*5255Sstephh 	if (l1 == l2 && l2 == common)
705*5255Sstephh 		return (0);
706*5255Sstephh 	else
707*5255Sstephh 		return (1);
708*5255Sstephh }
709*5255Sstephh 
710*5255Sstephh static name_list_t *
711*5255Sstephh alloc_name_list(char *name, uint8_t pct)
712*5255Sstephh {
713*5255Sstephh 	name_list_t *nlp;
714*5255Sstephh 
715*5255Sstephh 	nlp = malloc(sizeof (*nlp));
716*5255Sstephh 	nlp->name = strdup(name);
717*5255Sstephh 	nlp->pct = pct;
718*5255Sstephh 	nlp->max_pct = pct;
719*5255Sstephh 	nlp->count = 1;
720*5255Sstephh 	nlp->next = nlp;
721*5255Sstephh 	nlp->prev = nlp;
722*5255Sstephh 	nlp->status = 0;
723*5255Sstephh 	return (nlp);
724*5255Sstephh }
725*5255Sstephh 
726*5255Sstephh static void
727*5255Sstephh free_name_list(name_list_t *list)
728*5255Sstephh {
729*5255Sstephh 	name_list_t *next = list;
730*5255Sstephh 	name_list_t *lp;
731*5255Sstephh 
732*5255Sstephh 	if (list) {
733*5255Sstephh 		do {
734*5255Sstephh 			lp = next;
735*5255Sstephh 			next = lp->next;
736*5255Sstephh 			free(lp->name);
737*5255Sstephh 			free(lp);
738*5255Sstephh 		} while (next != list);
739*5255Sstephh 	}
740*5255Sstephh }
741*5255Sstephh 
742*5255Sstephh static status_record_t *
743*5255Sstephh new_record_init(uurec_t *uurec_p, char *msgid, name_list_t *class,
744*5255Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
745*5255Sstephh     name_list_t *serial, const char *url, boolean_t not_suppressed,
746*5255Sstephh     hostid_t *hostid)
747*5255Sstephh {
748*5255Sstephh 	status_record_t *status_rec_p;
749*5255Sstephh 
750*5255Sstephh 	status_rec_p = (status_record_t *)malloc(sizeof (status_record_t));
751*5255Sstephh 	status_rec_p->nrecs = 1;
752*5255Sstephh 	status_rec_p->host = hostid;
753*5255Sstephh 	status_rec_p->uurec = uurec_p;
754*5255Sstephh 	uurec_p->next = NULL;
755*5255Sstephh 	uurec_p->prev = NULL;
756*5255Sstephh 	uurec_p->asru = asru;
757*5255Sstephh 	status_rec_p->severity = get_dict_msg(msgid, "severity", 1, 0);
758*5255Sstephh 	status_rec_p->class = class;
759*5255Sstephh 	status_rec_p->fru = fru;
760*5255Sstephh 	status_rec_p->asru = asru;
761*5255Sstephh 	status_rec_p->resource = resource;
762*5255Sstephh 	status_rec_p->serial = serial;
763*5255Sstephh 	status_rec_p->url = url ? strdup(url) : NULL;
764*5255Sstephh 	status_rec_p->msgid = strdup(msgid);
765*5255Sstephh 	status_rec_p->not_suppressed = not_suppressed;
766*5255Sstephh 	return (status_rec_p);
767*5255Sstephh }
768*5255Sstephh 
769*5255Sstephh /*
770*5255Sstephh  * add record to given list maintaining order higher priority first.
771*5255Sstephh  */
772*5255Sstephh static void
773*5255Sstephh add_rec_list(status_record_t *status_rec_p, sr_list_t **list_pp)
774*5255Sstephh {
775*5255Sstephh 	sr_list_t *tp, *np, *sp;
776*5255Sstephh 	int order;
777*5255Sstephh 	uint64_t sec;
778*5255Sstephh 
779*5255Sstephh 	np = malloc(sizeof (sr_list_t));
780*5255Sstephh 	np->status_record = status_rec_p;
781*5255Sstephh 	sec = status_rec_p->uurec->sec;
782*5255Sstephh 	if ((sp = *list_pp) == NULL) {
783*5255Sstephh 		*list_pp = np;
784*5255Sstephh 		np->next = np;
785*5255Sstephh 		np->prev = np;
786*5255Sstephh 	} else {
787*5255Sstephh 		/* insert new record in front of lower priority */
788*5255Sstephh 		tp = sp;
789*5255Sstephh 		order = cmp_priority(status_rec_p->severity,
790*5255Sstephh 		    sp->status_record->severity, sec,
791*5255Sstephh 		    tp->status_record->uurec->sec, 0, 0);
792*5255Sstephh 		if (order > 0) {
793*5255Sstephh 			*list_pp = np;
794*5255Sstephh 		} else {
795*5255Sstephh 			tp = sp->next;
796*5255Sstephh 			while (tp != sp &&
797*5255Sstephh 			    cmp_priority(status_rec_p->severity,
798*5255Sstephh 			    tp->status_record->severity, sec,
799*5255Sstephh 			    tp->status_record->uurec->sec, 0, 0)) {
800*5255Sstephh 				tp = tp->next;
801*5255Sstephh 			}
802*5255Sstephh 		}
803*5255Sstephh 		np->next = tp;
804*5255Sstephh 		np->prev = tp->prev;
805*5255Sstephh 		tp->prev->next = np;
806*5255Sstephh 		tp->prev = np;
807*5255Sstephh 	}
808*5255Sstephh }
809*5255Sstephh 
810*5255Sstephh static void
811*5255Sstephh add_resource(status_record_t *status_rec_p, resource_list_t **rp,
812*5255Sstephh     resource_list_t *np)
813*5255Sstephh {
814*5255Sstephh 	int order;
815*5255Sstephh 	uint64_t sec;
816*5255Sstephh 	resource_list_t *sp, *tp;
817*5255Sstephh 	status_record_t *srp;
818*5255Sstephh 	char *severity = status_rec_p->severity;
819*5255Sstephh 
820*5255Sstephh 	add_rec_list(status_rec_p, &np->status_rec_list);
821*5255Sstephh 	if ((sp = *rp) == NULL) {
822*5255Sstephh 		np->next = np;
823*5255Sstephh 		np->prev = np;
824*5255Sstephh 		*rp = np;
825*5255Sstephh 	} else {
826*5255Sstephh 		/*
827*5255Sstephh 		 * insert new record in front of lower priority
828*5255Sstephh 		 */
829*5255Sstephh 		tp = sp->next;
830*5255Sstephh 		srp = sp->status_rec_list->status_record;
831*5255Sstephh 		sec = status_rec_p->uurec->sec;
832*5255Sstephh 		order = cmp_priority(severity, srp->severity, sec,
833*5255Sstephh 		    srp->uurec->sec, np->max_pct, sp->max_pct);
834*5255Sstephh 		if (order > 0) {
835*5255Sstephh 			*rp = np;
836*5255Sstephh 		} else {
837*5255Sstephh 			srp = tp->status_rec_list->status_record;
838*5255Sstephh 			while (tp != sp &&
839*5255Sstephh 			    cmp_priority(severity, srp->severity, sec,
840*5255Sstephh 			    srp->uurec->sec, np->max_pct, sp->max_pct) < 0) {
841*5255Sstephh 				tp = tp->next;
842*5255Sstephh 				srp = tp->status_rec_list->status_record;
843*5255Sstephh 			}
844*5255Sstephh 		}
845*5255Sstephh 		np->next = tp;
846*5255Sstephh 		np->prev = tp->prev;
847*5255Sstephh 		tp->prev->next = np;
848*5255Sstephh 		tp->prev = np;
849*5255Sstephh 	}
850*5255Sstephh }
851*5255Sstephh 
852*5255Sstephh static void
853*5255Sstephh add_resource_list(status_record_t *status_rec_p, name_list_t *fp,
854*5255Sstephh     resource_list_t **rpp)
855*5255Sstephh {
856*5255Sstephh 	int order;
857*5255Sstephh 	resource_list_t *np, *end;
858*5255Sstephh 	status_record_t *srp;
859*5255Sstephh 
860*5255Sstephh 	np = *rpp;
861*5255Sstephh 	end = np;
862*5255Sstephh 	while (np) {
863*5255Sstephh 		if (strcmp(fp->name, np->resource) == 0) {
864*5255Sstephh 			np->not_suppressed |= status_rec_p->not_suppressed;
865*5255Sstephh 			srp = np->status_rec_list->status_record;
866*5255Sstephh 			order = cmp_priority(status_rec_p->severity,
867*5255Sstephh 			    srp->severity, status_rec_p->uurec->sec,
868*5255Sstephh 			    srp->uurec->sec, fp->max_pct, np->max_pct);
869*5255Sstephh 			if (order > 0 && np != end) {
870*5255Sstephh 				/*
871*5255Sstephh 				 * remove from list and add again using
872*5255Sstephh 				 * new priority
873*5255Sstephh 				 */
874*5255Sstephh 				np->prev->next = np->next;
875*5255Sstephh 				np->next->prev = np->prev;
876*5255Sstephh 				add_resource(status_rec_p,
877*5255Sstephh 				    rpp, np);
878*5255Sstephh 			} else {
879*5255Sstephh 				add_rec_list(status_rec_p,
880*5255Sstephh 				    &np->status_rec_list);
881*5255Sstephh 			}
882*5255Sstephh 			break;
883*5255Sstephh 		}
884*5255Sstephh 		np = np->next;
885*5255Sstephh 		if (np == end) {
886*5255Sstephh 			np = NULL;
887*5255Sstephh 			break;
888*5255Sstephh 		}
889*5255Sstephh 	}
890*5255Sstephh 	if (np == NULL) {
891*5255Sstephh 		np = malloc(sizeof (resource_list_t));
892*5255Sstephh 		np->resource = fp->name;
893*5255Sstephh 		np->not_suppressed = status_rec_p->not_suppressed;
894*5255Sstephh 		np->status_rec_list = NULL;
895*5255Sstephh 		np->max_pct = fp->max_pct;
896*5255Sstephh 		add_resource(status_rec_p, rpp, np);
8970Sstevel@tonic-gate 	}
8980Sstevel@tonic-gate }
8990Sstevel@tonic-gate 
900*5255Sstephh static void
901*5255Sstephh add_list(status_record_t *status_rec_p, name_list_t *listp,
902*5255Sstephh     resource_list_t **glistp)
903*5255Sstephh {
904*5255Sstephh 	name_list_t *fp, *end;
905*5255Sstephh 
906*5255Sstephh 	fp = listp;
907*5255Sstephh 	end = fp;
908*5255Sstephh 	while (fp) {
909*5255Sstephh 		add_resource_list(status_rec_p, fp, glistp);
910*5255Sstephh 		fp = fp->next;
911*5255Sstephh 		if (fp == end)
912*5255Sstephh 			break;
913*5255Sstephh 	}
914*5255Sstephh }
915*5255Sstephh 
916*5255Sstephh /*
917*5255Sstephh  * add record to rec, fru and asru lists.
918*5255Sstephh  */
919*5255Sstephh static void
920*5255Sstephh catalog_new_record(uurec_t *uurec_p, char *msgid, name_list_t *class,
921*5255Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
922*5255Sstephh     name_list_t *serial, const char *url, boolean_t not_suppressed,
923*5255Sstephh     hostid_t *hostid)
924*5255Sstephh {
925*5255Sstephh 	status_record_t *status_rec_p;
926*5255Sstephh 
927*5255Sstephh 	status_rec_p = new_record_init(uurec_p, msgid, class, fru, asru,
928*5255Sstephh 	    resource, serial, url, not_suppressed, hostid);
929*5255Sstephh 	add_rec_list(status_rec_p, &status_rec_list);
930*5255Sstephh 	if (status_rec_p->fru)
931*5255Sstephh 		add_list(status_rec_p, status_rec_p->fru, &status_fru_list);
932*5255Sstephh 	if (status_rec_p->asru)
933*5255Sstephh 		add_list(status_rec_p, status_rec_p->asru, &status_asru_list);
934*5255Sstephh }
935*5255Sstephh 
936*5255Sstephh /*
937*5255Sstephh  * add uuid and diagnoses time to an existing record for similar fault on the
938*5255Sstephh  * same fru
939*5255Sstephh  */
940*5255Sstephh static void
941*5255Sstephh catalog_merge_record(status_record_t *status_rec_p, uurec_t *uurec_p,
942*5255Sstephh     name_list_t *asru, name_list_t *resource, name_list_t *serial,
943*5255Sstephh     const char *url, boolean_t not_suppressed)
944*5255Sstephh {
945*5255Sstephh 	uurec_t *uurec1_p;
9460Sstevel@tonic-gate 
947*5255Sstephh 	status_rec_p->nrecs++;
948*5255Sstephh 	/* add uurec in time order */
949*5255Sstephh 	if (status_rec_p->uurec->sec > uurec_p->sec) {
950*5255Sstephh 		uurec_p->next = status_rec_p->uurec;
951*5255Sstephh 		uurec_p->prev = NULL;
952*5255Sstephh 		status_rec_p->uurec = uurec_p;
953*5255Sstephh 	} else {
954*5255Sstephh 		uurec1_p = status_rec_p->uurec;
955*5255Sstephh 		while (uurec1_p->next && uurec1_p->next->sec <= uurec_p->sec)
956*5255Sstephh 			uurec1_p = uurec1_p->next;
957*5255Sstephh 		if (uurec1_p->next)
958*5255Sstephh 			uurec1_p->next->prev = uurec_p;
959*5255Sstephh 		uurec_p->next = uurec1_p->next;
960*5255Sstephh 		uurec_p->prev = uurec1_p;
961*5255Sstephh 		uurec1_p->next = uurec_p;
962*5255Sstephh 	}
963*5255Sstephh 	if (status_rec_p->url == NULL && url != NULL)
964*5255Sstephh 		status_rec_p->url = strdup(url);
965*5255Sstephh 	status_rec_p->not_suppressed |= not_suppressed;
966*5255Sstephh 	uurec_p->asru = merge_name_list(&status_rec_p->asru, asru, 0);
967*5255Sstephh 	(void) merge_name_list(&status_rec_p->resource, resource, 0);
968*5255Sstephh 	(void) merge_name_list(&status_rec_p->serial, serial, 0);
969*5255Sstephh }
970*5255Sstephh 
971*5255Sstephh static status_record_t *
972*5255Sstephh record_in_catalog(name_list_t *class, name_list_t *fru,
973*5255Sstephh     char *msgid, hostid_t *host)
974*5255Sstephh {
975*5255Sstephh 	sr_list_t *status_rec_p;
976*5255Sstephh 	status_record_t *srp = NULL;
977*5255Sstephh 
978*5255Sstephh 	status_rec_p = status_rec_list;
979*5255Sstephh 	while (status_rec_p) {
980*5255Sstephh 		srp = status_rec_p->status_record;
981*5255Sstephh 		if (host == srp->host &&
982*5255Sstephh 		    cmp_name_list(class, srp->class) == 0 &&
983*5255Sstephh 		    cmp_name_list(fru, srp->fru) == 0 &&
984*5255Sstephh 		    strcmp(msgid, srp->msgid) == 0)
985*5255Sstephh 			break;
986*5255Sstephh 		if (status_rec_p->next == status_rec_list) {
987*5255Sstephh 			srp = NULL;
988*5255Sstephh 			break;
989*5255Sstephh 		} else {
990*5255Sstephh 			status_rec_p = status_rec_p->next;
991*5255Sstephh 		}
992*5255Sstephh 	}
993*5255Sstephh 	return (srp);
994*5255Sstephh }
995*5255Sstephh 
996*5255Sstephh static void
997*5255Sstephh get_serial_no(nvlist_t *nvl, name_list_t **serial_p, uint8_t pct)
998*5255Sstephh {
999*5255Sstephh 	char *name;
1000*5255Sstephh 	char *serial = NULL;
1001*5255Sstephh 	char **lserial = NULL;
1002*5255Sstephh 	uint64_t serint;
1003*5255Sstephh 	name_list_t *nlp;
1004*5255Sstephh 	int j;
1005*5255Sstephh 	uint_t nelem;
1006*5255Sstephh 	char buf[64];
10070Sstevel@tonic-gate 
1008*5255Sstephh 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) == 0) {
1009*5255Sstephh 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
1010*5255Sstephh 			if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
1011*5255Sstephh 			    &serint) == 0) {
1012*5255Sstephh 				(void) snprintf(buf, sizeof (buf), "%llX",
1013*5255Sstephh 				    serint);
1014*5255Sstephh 				nlp = alloc_name_list(buf, pct);
1015*5255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
1016*5255Sstephh 			}
1017*5255Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
1018*5255Sstephh 			if (nvlist_lookup_string_array(nvl,
1019*5255Sstephh 			    FM_FMRI_MEM_SERIAL_ID, &lserial, &nelem) == 0) {
1020*5255Sstephh 				nlp = alloc_name_list(lserial[0], pct);
1021*5255Sstephh 				for (j = 1; j < nelem; j++) {
1022*5255Sstephh 					name_list_t *n1lp;
1023*5255Sstephh 					n1lp = alloc_name_list(lserial[j], pct);
1024*5255Sstephh 					(void) merge_name_list(&nlp, n1lp, 1);
1025*5255Sstephh 				}
1026*5255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
1027*5255Sstephh 			}
1028*5255Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_HC) == 0) {
1029*5255Sstephh 			if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID,
1030*5255Sstephh 			    &serial) == 0) {
1031*5255Sstephh 				nlp = alloc_name_list(serial, pct);
1032*5255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
1033*5255Sstephh 			}
1034*5255Sstephh 		}
1035*5255Sstephh 	}
1036*5255Sstephh }
1037*5255Sstephh 
1038*5255Sstephh static void
1039*5255Sstephh extract_record_info(nvlist_t *nvl, name_list_t **class_p,
1040*5255Sstephh     name_list_t **fru_p, name_list_t **serial_p,
1041*5255Sstephh     name_list_t **resource_p, name_list_t **asru_p, uint8_t status)
10420Sstevel@tonic-gate {
1043*5255Sstephh 	nvlist_t *lfru, *lasru, *rsrc;
1044*5255Sstephh 	name_list_t *nlp;
1045*5255Sstephh 	char *name;
1046*5255Sstephh 	uint8_t lpct = 0;
1047*5255Sstephh 	char *lclass = NULL;
1048*5255Sstephh 
1049*5255Sstephh 	(void) nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &lpct);
1050*5255Sstephh 	if (nvlist_lookup_string(nvl, FM_CLASS, &lclass) == 0) {
1051*5255Sstephh 		nlp = alloc_name_list(lclass, lpct);
1052*5255Sstephh 		(void) merge_name_list(class_p, nlp, 1);
1053*5255Sstephh 	}
1054*5255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &lfru) == 0) {
1055*5255Sstephh 		name = get_nvl2str_topo(lfru);
1056*5255Sstephh 		if (name != NULL) {
1057*5255Sstephh 			nlp = alloc_name_list(name, lpct);
1058*5255Sstephh 			free(name);
1059*5255Sstephh 			(void) merge_name_list(fru_p, nlp, 1);
1060*5255Sstephh 		}
1061*5255Sstephh 		get_serial_no(lfru, serial_p, lpct);
1062*5255Sstephh 	}
1063*5255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &lasru) == 0) {
1064*5255Sstephh 		name = get_nvl2str_topo(lasru);
1065*5255Sstephh 		if (name != NULL) {
1066*5255Sstephh 			nlp = alloc_name_list(name, lpct);
1067*5255Sstephh 			nlp->status = status & ~FM_SUSPECT_NOT_PRESENT;
1068*5255Sstephh 			free(name);
1069*5255Sstephh 			(void) merge_name_list(asru_p, nlp, 1);
1070*5255Sstephh 		}
1071*5255Sstephh 		get_serial_no(lasru, serial_p, lpct);
1072*5255Sstephh 	}
1073*5255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
1074*5255Sstephh 		name = get_nvl2str_topo(rsrc);
1075*5255Sstephh 		if (name != NULL) {
1076*5255Sstephh 			nlp = alloc_name_list(name, lpct);
1077*5255Sstephh 			free(name);
1078*5255Sstephh 			(void) merge_name_list(resource_p, nlp, 1);
1079*5255Sstephh 		}
1080*5255Sstephh 	}
1081*5255Sstephh }
1082*5255Sstephh 
1083*5255Sstephh static void
1084*5255Sstephh add_fault_record_to_catalog(nvlist_t *nvl, uint64_t sec, char *uuid,
1085*5255Sstephh     const char *url)
1086*5255Sstephh {
1087*5255Sstephh 	char *msgid = "-";
1088*5255Sstephh 	uint_t i, size = 0;
1089*5255Sstephh 	name_list_t *class = NULL, *resource = NULL;
1090*5255Sstephh 	name_list_t *asru = NULL, *fru = NULL, *serial = NULL;
1091*5255Sstephh 	nvlist_t **nva;
1092*5255Sstephh 	uint8_t *ba;
1093*5255Sstephh 	status_record_t *status_rec_p;
1094*5255Sstephh 	uurec_t *uurec_p;
1095*5255Sstephh 	hostid_t *host;
1096*5255Sstephh 	boolean_t not_suppressed = 1;
1097*5255Sstephh 	boolean_t any_present = 0;
1098*5255Sstephh 
1099*5255Sstephh 	(void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &msgid);
1100*5255Sstephh 	(void) nvlist_lookup_uint32(nvl, FM_SUSPECT_FAULT_SZ, &size);
1101*5255Sstephh 	(void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_MESSAGE,
1102*5255Sstephh 	    &not_suppressed);
1103*5255Sstephh 
1104*5255Sstephh 	if (size != 0) {
1105*5255Sstephh 		(void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
1106*5255Sstephh 		    &nva, &size);
1107*5255Sstephh 		(void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS,
1108*5255Sstephh 		    &ba, &size);
1109*5255Sstephh 		for (i = 0; i < size; i++) {
1110*5255Sstephh 			extract_record_info(nva[i], &class, &fru, &serial,
1111*5255Sstephh 			    &resource, &asru, ba[i]);
1112*5255Sstephh 			if (!(ba[i] & FM_SUSPECT_NOT_PRESENT) &&
1113*5255Sstephh 			    (ba[i] & FM_SUSPECT_FAULTY))
1114*5255Sstephh 				any_present = 1;
1115*5255Sstephh 		}
1116*5255Sstephh 		/*
1117*5255Sstephh 		 * also suppress if no resources present
1118*5255Sstephh 		 */
1119*5255Sstephh 		if (any_present == 0)
1120*5255Sstephh 			not_suppressed = 0;
11210Sstevel@tonic-gate 	}
11220Sstevel@tonic-gate 
1123*5255Sstephh 	uurec_p = (uurec_t *)malloc(sizeof (uurec_t));
1124*5255Sstephh 	uurec_p->uuid = strdup(uuid);
1125*5255Sstephh 	uurec_p->sec = sec;
1126*5255Sstephh 	uurec_p->ari_uuid_list = NULL;
1127*5255Sstephh 	host = find_hostid(nvl);
1128*5255Sstephh 	if (not_suppressed && !opt_g)
1129*5255Sstephh 		status_rec_p = NULL;
1130*5255Sstephh 	else
1131*5255Sstephh 		status_rec_p = record_in_catalog(class, fru, msgid, host);
1132*5255Sstephh 	if (status_rec_p) {
1133*5255Sstephh 		catalog_merge_record(status_rec_p, uurec_p, asru, resource,
1134*5255Sstephh 		    serial, url, not_suppressed);
1135*5255Sstephh 		free_name_list(class);
1136*5255Sstephh 		free_name_list(fru);
1137*5255Sstephh 	} else {
1138*5255Sstephh 		catalog_new_record(uurec_p, msgid, class, fru, asru,
1139*5255Sstephh 		    resource, serial, url, not_suppressed, host);
1140*5255Sstephh 	}
1141*5255Sstephh }
1142*5255Sstephh 
1143*5255Sstephh static void
1144*5255Sstephh update_asru_state_in_catalog(const char *uuid, const char *ari_uuid)
1145*5255Sstephh {
1146*5255Sstephh 	sr_list_t *srp;
1147*5255Sstephh 	uurec_t *uurp;
1148*5255Sstephh 	ari_list_t *ari_list;
1149*5255Sstephh 
1150*5255Sstephh 	srp = status_rec_list;
1151*5255Sstephh 	if (srp) {
1152*5255Sstephh 		for (;;) {
1153*5255Sstephh 			uurp = srp->status_record->uurec;
1154*5255Sstephh 			while (uurp) {
1155*5255Sstephh 				if (strcmp(uuid, uurp->uuid) == 0) {
1156*5255Sstephh 					ari_list = (ari_list_t *)
1157*5255Sstephh 					    malloc(sizeof (ari_list_t));
1158*5255Sstephh 					ari_list->ari_uuid = strdup(ari_uuid);
1159*5255Sstephh 					ari_list->next = uurp->ari_uuid_list;
1160*5255Sstephh 					uurp->ari_uuid_list = ari_list;
1161*5255Sstephh 					return;
1162*5255Sstephh 				}
1163*5255Sstephh 				uurp = uurp->next;
1164*5255Sstephh 			}
1165*5255Sstephh 			if (srp->next == status_rec_list)
1166*5255Sstephh 				break;
1167*5255Sstephh 			srp = srp->next;
1168*5255Sstephh 		}
1169*5255Sstephh 	}
1170*5255Sstephh }
1171*5255Sstephh 
1172*5255Sstephh static void
1173*5255Sstephh print_line(char *label, char *buf)
1174*5255Sstephh {
1175*5255Sstephh 	char *cp, *ep, *wp;
1176*5255Sstephh 	char c;
1177*5255Sstephh 	int i;
1178*5255Sstephh 	int lsz;
1179*5255Sstephh 	char *padding;
1180*5255Sstephh 
1181*5255Sstephh 	lsz = strlen(label);
1182*5255Sstephh 	padding = malloc(lsz + 1);
1183*5255Sstephh 	for (i = 0; i < lsz; i++)
1184*5255Sstephh 		padding[i] = ' ';
1185*5255Sstephh 	padding[i] = 0;
1186*5255Sstephh 	cp = buf;
1187*5255Sstephh 	ep = buf;
1188*5255Sstephh 	c = *ep;
1189*5255Sstephh 	(void) printf("\n");
1190*5255Sstephh 	while (c) {
1191*5255Sstephh 		i = lsz;
1192*5255Sstephh 		wp = NULL;
1193*5255Sstephh 		while ((c = *ep) != NULL && (wp == NULL || i < 80)) {
1194*5255Sstephh 			if (c == ' ')
1195*5255Sstephh 				wp = ep;
1196*5255Sstephh 			else if (c == '\n') {
1197*5255Sstephh 				i = 0;
1198*5255Sstephh 				*ep = 0;
1199*5255Sstephh 				do {
1200*5255Sstephh 					ep++;
1201*5255Sstephh 				} while ((c = *ep) != NULL && c == ' ');
1202*5255Sstephh 				break;
1203*5255Sstephh 			}
1204*5255Sstephh 			ep++;
1205*5255Sstephh 			i++;
1206*5255Sstephh 		}
1207*5255Sstephh 		if (i >= 80 && wp) {
1208*5255Sstephh 			*wp = 0;
1209*5255Sstephh 			ep = wp + 1;
1210*5255Sstephh 			c = *ep;
1211*5255Sstephh 		}
1212*5255Sstephh 		(void) printf("%s%s\n", label, cp);
1213*5255Sstephh 		cp = ep;
1214*5255Sstephh 		label = padding;
1215*5255Sstephh 	}
1216*5255Sstephh 	free(padding);
1217*5255Sstephh }
1218*5255Sstephh 
1219*5255Sstephh static void
1220*5255Sstephh print_dict_info(char *msgid, char *url)
1221*5255Sstephh {
1222*5255Sstephh 	const char *cp;
1223*5255Sstephh 	char *l_url;
1224*5255Sstephh 	char *buf;
1225*5255Sstephh 	int bufsz;
1226*5255Sstephh 
1227*5255Sstephh 	cp = get_dict_msg(msgid, "description", 0, 1);
1228*5255Sstephh 	if (cp) {
1229*5255Sstephh 		if (url)
1230*5255Sstephh 			l_url = url;
1231*5255Sstephh 		else
1232*5255Sstephh 			l_url = get_dict_url(msgid);
1233*5255Sstephh 		bufsz = strlen(cp) + strlen(l_url) + 1;
1234*5255Sstephh 		buf = malloc(bufsz);
1235*5255Sstephh 		(void) snprintf(buf, bufsz, cp, l_url);
1236*5255Sstephh 		print_line(dgettext("FMD", "Description : "), buf);
1237*5255Sstephh 		free(buf);
1238*5255Sstephh 		if (!url)
1239*5255Sstephh 			free(l_url);
1240*5255Sstephh 	}
1241*5255Sstephh 	cp = get_dict_msg(msgid, "response", 0, 1);
1242*5255Sstephh 	if (cp) {
1243*5255Sstephh 		buf = strdup(cp);
1244*5255Sstephh 		print_line(dgettext("FMD", "Response    : "), buf);
1245*5255Sstephh 		free(buf);
1246*5255Sstephh 	}
1247*5255Sstephh 	cp = get_dict_msg(msgid, "impact", 0, 1);
1248*5255Sstephh 	if (cp) {
1249*5255Sstephh 		buf = strdup(cp);
1250*5255Sstephh 		print_line(dgettext("FMD", "Impact      : "), buf);
1251*5255Sstephh 		free(buf);
1252*5255Sstephh 	}
1253*5255Sstephh 	cp = get_dict_msg(msgid, "action", 0, 1);
1254*5255Sstephh 	if (cp) {
1255*5255Sstephh 		buf = strdup(cp);
1256*5255Sstephh 		print_line(dgettext("FMD", "Action      : "), buf);
1257*5255Sstephh 		free(buf);
1258*5255Sstephh 	}
1259*5255Sstephh }
1260*5255Sstephh 
1261*5255Sstephh static void
1262*5255Sstephh print_name(name_list_t *list, char *(func)(char *), char *padding, int *np,
1263*5255Sstephh     int pct, int full)
1264*5255Sstephh {
1265*5255Sstephh 	char *name, *fru = NULL;
1266*5255Sstephh 
1267*5255Sstephh 	name = list->name;
1268*5255Sstephh 	if (func)
1269*5255Sstephh 		fru = func(list->name);
1270*5255Sstephh 	if (fru) {
1271*5255Sstephh 		(void) printf("%s \"%s\" (%s)", padding, fru, name);
1272*5255Sstephh 		*np += 1;
1273*5255Sstephh 		free(fru);
1274*5255Sstephh 	} else {
1275*5255Sstephh 		(void) printf("%s %s", padding, name);
1276*5255Sstephh 		*np += 1;
1277*5255Sstephh 	}
1278*5255Sstephh 	if (list->pct && pct > 0 && pct < 100) {
1279*5255Sstephh 		if (list->count > 1) {
1280*5255Sstephh 			if (full) {
1281*5255Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
1282*5255Sstephh 				    dgettext("FMD", "max"),
1283*5255Sstephh 				    list->max_pct);
1284*5255Sstephh 			} else {
1285*5255Sstephh 				(void) printf(" %s %d%%\n",
1286*5255Sstephh 				    dgettext("FMD", "max"),
1287*5255Sstephh 				    list->max_pct);
1288*5255Sstephh 			}
1289*5255Sstephh 		} else {
1290*5255Sstephh 			(void) printf(" %d%%\n", list->pct);
1291*5255Sstephh 		}
1292*5255Sstephh 	} else {
1293*5255Sstephh 		(void) printf("\n");
1294*5255Sstephh 	}
1295*5255Sstephh }
1296*5255Sstephh 
1297*5255Sstephh static void
1298*5255Sstephh print_asru_status(int status, char *label)
1299*5255Sstephh {
1300*5255Sstephh 	char *msg = NULL;
1301*5255Sstephh 
1302*5255Sstephh 	switch (status) {
1303*5255Sstephh 	case 0:
1304*5255Sstephh 		msg = dgettext("FMD", "ok and in service");
1305*5255Sstephh 		break;
1306*5255Sstephh 	case FM_SUSPECT_FAULTY:
1307*5255Sstephh 		msg = dgettext("FMD", "degraded but still in service");
1308*5255Sstephh 		break;
1309*5255Sstephh 	case FM_SUSPECT_UNUSABLE:
1310*5255Sstephh 		msg = dgettext("FMD", "unknown, not present or disabled");
1311*5255Sstephh 		break;
1312*5255Sstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
1313*5255Sstephh 		msg = dgettext("FMD", "faulted and taken out of service");
1314*5255Sstephh 		break;
1315*5255Sstephh 	default:
1316*5255Sstephh 		break;
1317*5255Sstephh 	}
1318*5255Sstephh 	if (msg) {
1319*5255Sstephh 		(void) printf("%s     %s\n", label, msg);
1320*5255Sstephh 	}
1321*5255Sstephh }
1322*5255Sstephh 
1323*5255Sstephh static void
1324*5255Sstephh print_name_list(name_list_t *list, char *label, char *(func)(char *),
1325*5255Sstephh     int limit, int pct, void (func1)(int, char *), int full)
1326*5255Sstephh {
1327*5255Sstephh 	char *name, *fru = NULL;
1328*5255Sstephh 	char *padding;
1329*5255Sstephh 	int i, j, l, n;
1330*5255Sstephh 	name_list_t *end = list;
1331*5255Sstephh 
1332*5255Sstephh 	l = strlen(label);
1333*5255Sstephh 	padding = malloc(l + 1);
1334*5255Sstephh 	for (i = 0; i < l; i++)
1335*5255Sstephh 		padding[i] = ' ';
1336*5255Sstephh 	padding[l] = 0;
1337*5255Sstephh 	(void) printf("%s", label);
1338*5255Sstephh 	name = list->name;
1339*5255Sstephh 	if (func)
1340*5255Sstephh 		fru = func(list->name);
1341*5255Sstephh 	if (fru) {
1342*5255Sstephh 		(void) printf(" \"%s\" (%s)", fru, name);
1343*5255Sstephh 		free(fru);
1344*5255Sstephh 	} else {
1345*5255Sstephh 		(void) printf(" %s", name);
1346*5255Sstephh 	}
1347*5255Sstephh 	if (list->pct && pct > 0 && pct < 100) {
1348*5255Sstephh 		if (list->count > 1) {
1349*5255Sstephh 			if (full) {
1350*5255Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
1351*5255Sstephh 				    dgettext("FMD", "max"), list->max_pct);
1352*5255Sstephh 			} else {
1353*5255Sstephh 				(void) printf(" %s %d%%\n",
1354*5255Sstephh 				    dgettext("FMD", "max"), list->max_pct);
1355*5255Sstephh 			}
1356*5255Sstephh 		} else {
1357*5255Sstephh 			(void) printf(" %d%%\n", list->pct);
1358*5255Sstephh 		}
1359*5255Sstephh 	} else {
1360*5255Sstephh 		(void) printf("\n");
1361*5255Sstephh 	}
1362*5255Sstephh 	if (func1)
1363*5255Sstephh 		func1(list->status, padding);
1364*5255Sstephh 	n = 1;
1365*5255Sstephh 	j = 0;
1366*5255Sstephh 	while ((list = list->next) != end) {
1367*5255Sstephh 		if (limit == 0 || n < limit) {
1368*5255Sstephh 			print_name(list, func, padding, &n, pct, full);
1369*5255Sstephh 			if (func1)
1370*5255Sstephh 				func1(list->status, padding);
1371*5255Sstephh 		} else
1372*5255Sstephh 			j++;
1373*5255Sstephh 	}
1374*5255Sstephh 	if (j == 1) {
1375*5255Sstephh 		print_name(list->prev, func, padding, &n, pct, full);
1376*5255Sstephh 	} else if (j > 1) {
1377*5255Sstephh 		(void) printf("%s... %d %s\n", padding, j,
1378*5255Sstephh 		    dgettext("FMD", "more entries suppressed,"
1379*5255Sstephh 		    " use -v option for full list"));
1380*5255Sstephh 	}
1381*5255Sstephh 	free(padding);
1382*5255Sstephh }
1383*5255Sstephh 
1384*5255Sstephh static int
1385*5255Sstephh asru_same_status(name_list_t *list)
1386*5255Sstephh {
1387*5255Sstephh 	name_list_t *end = list;
1388*5255Sstephh 	int status = list->status;
1389*5255Sstephh 
1390*5255Sstephh 	while ((list = list->next) != end) {
1391*5255Sstephh 		if (status == -1) {
1392*5255Sstephh 			status = list->status;
1393*5255Sstephh 			continue;
1394*5255Sstephh 		}
1395*5255Sstephh 		if (list->status != -1 && status != list->status) {
1396*5255Sstephh 			status = -1;
1397*5255Sstephh 			break;
1398*5255Sstephh 		}
1399*5255Sstephh 	}
1400*5255Sstephh 	return (status);
1401*5255Sstephh }
1402*5255Sstephh 
1403*5255Sstephh static int
1404*5255Sstephh serial_in_fru(name_list_t *fru, name_list_t *serial)
1405*5255Sstephh {
1406*5255Sstephh 	name_list_t *sp = serial;
1407*5255Sstephh 	name_list_t *fp;
1408*5255Sstephh 	int nserial = 0;
1409*5255Sstephh 	int found = 0;
1410*5255Sstephh 	char buf[128];
1411*5255Sstephh 
1412*5255Sstephh 	while (sp) {
1413*5255Sstephh 		fp = fru;
1414*5255Sstephh 		nserial++;
1415*5255Sstephh 		(void) snprintf(buf, sizeof (buf), "serial=%s", sp->name);
1416*5255Sstephh 		buf[sizeof (buf) - 1] = 0;
1417*5255Sstephh 		while (fp) {
1418*5255Sstephh 			if (strstr(fp->name, buf) != NULL) {
1419*5255Sstephh 				found++;
1420*5255Sstephh 				break;
1421*5255Sstephh 			}
1422*5255Sstephh 			fp = fp->next;
1423*5255Sstephh 			if (fp == fru)
1424*5255Sstephh 				break;
1425*5255Sstephh 		}
1426*5255Sstephh 		sp = sp->next;
1427*5255Sstephh 		if (sp == serial)
1428*5255Sstephh 			break;
1429*5255Sstephh 	}
1430*5255Sstephh 	return (found == nserial ? 1 : 0);
1431*5255Sstephh }
1432*5255Sstephh 
1433*5255Sstephh static void
1434*5255Sstephh print_server_name(hostid_t *host, char *label)
1435*5255Sstephh {
1436*5255Sstephh 	(void) printf("%s %s %s %s\n", label, host->server, host->platform,
1437*5255Sstephh 	    host->chassis ? host->chassis : "");
1438*5255Sstephh }
1439*5255Sstephh 
1440*5255Sstephh static void
1441*5255Sstephh print_sup_record(status_record_t *srp, int opt_i, int full)
1442*5255Sstephh {
1443*5255Sstephh 	char buf[32];
1444*5255Sstephh 	uurec_t *uurp = srp->uurec;
1445*5255Sstephh 	int n, j, k, max;
1446*5255Sstephh 	int status;
1447*5255Sstephh 	ari_list_t *ari_list;
1448*5255Sstephh 
1449*5255Sstephh 	n = 0;
1450*5255Sstephh 	max = max_fault;
1451*5255Sstephh 	if (max < 0) {
1452*5255Sstephh 		max = 0;
1453*5255Sstephh 	}
1454*5255Sstephh 	j = max / 2;
1455*5255Sstephh 	max -= j;
1456*5255Sstephh 	k = srp->nrecs - max;
1457*5255Sstephh 	while ((uurp = uurp->next) != NULL) {
1458*5255Sstephh 		if (full || n < j || n >= k || max_fault == 0 ||
1459*5255Sstephh 		    srp->nrecs == max_fault+1) {
1460*5255Sstephh 			if (opt_i) {
1461*5255Sstephh 				ari_list = uurp->ari_uuid_list;
1462*5255Sstephh 				while (ari_list) {
1463*5255Sstephh 					(void) printf("%-15s %s\n",
1464*5255Sstephh 					    format_date(buf, sizeof (buf),
1465*5255Sstephh 					    uurp->sec), ari_list->ari_uuid);
1466*5255Sstephh 					ari_list = ari_list->next;
1467*5255Sstephh 				}
1468*5255Sstephh 			} else {
1469*5255Sstephh 				(void) printf("%-15s %s\n",
1470*5255Sstephh 				    format_date(buf, sizeof (buf), uurp->sec),
1471*5255Sstephh 				    uurp->uuid);
1472*5255Sstephh 			}
1473*5255Sstephh 		} else if (n == j)
1474*5255Sstephh 			(void) printf("... %d %s\n", srp->nrecs - max_fault,
1475*5255Sstephh 			    dgettext("FMD", "more entries suppressed"));
1476*5255Sstephh 		n++;
1477*5255Sstephh 	}
1478*5255Sstephh 	(void) printf("\n");
1479*5255Sstephh 	if (n_server > 1)
1480*5255Sstephh 		print_server_name(srp->host, dgettext("FMD", "Host        :"));
1481*5255Sstephh 	if (srp->class)
1482*5255Sstephh 		print_name_list(srp->class,
1483*5255Sstephh 		    dgettext("FMD", "Fault class :"), NULL, 0, srp->class->pct,
1484*5255Sstephh 		    NULL, full);
1485*5255Sstephh 	if (srp->asru) {
1486*5255Sstephh 		status = asru_same_status(srp->asru);
1487*5255Sstephh 		if (status != -1) {
1488*5255Sstephh 			print_name_list(srp->asru,
1489*5255Sstephh 			    dgettext("FMD", "Affects     :"), NULL,
1490*5255Sstephh 			    full ? 0 : max_display, 0, NULL, full);
1491*5255Sstephh 			print_asru_status(status, "             ");
1492*5255Sstephh 		} else
1493*5255Sstephh 			print_name_list(srp->asru,
1494*5255Sstephh 			    dgettext("FMD", "Affects     :"), NULL,
1495*5255Sstephh 			    full ? 0 : max_display, 0, print_asru_status, full);
1496*5255Sstephh 	}
1497*5255Sstephh 	if (full || srp->fru == NULL) {
1498*5255Sstephh 		if (srp->resource) {
1499*5255Sstephh 			print_name_list(srp->resource,
1500*5255Sstephh 			    dgettext("FMD", "Problem in  :"),
1501*5255Sstephh 			    NULL, full ? 0 : max_display, 0, NULL, full);
1502*5255Sstephh 		}
1503*5255Sstephh 	}
1504*5255Sstephh 	if (srp->fru) {
1505*5255Sstephh 		print_name_list(srp->fru, dgettext("FMD", "FRU         :"),
1506*5255Sstephh 		    get_fmri_label, 0,
1507*5255Sstephh 		    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
1508*5255Sstephh 		    NULL, full);
1509*5255Sstephh 	}
1510*5255Sstephh 	if (srp->serial && !serial_in_fru(srp->fru, srp->serial) &&
1511*5255Sstephh 	    !serial_in_fru(srp->asru, srp->serial)) {
1512*5255Sstephh 		print_name_list(srp->serial, dgettext("FMD", "Serial ID.  :"),
1513*5255Sstephh 		    NULL, 0, 0, NULL, full);
1514*5255Sstephh 	}
1515*5255Sstephh 	print_dict_info(srp->msgid, srp->url);
1516*5255Sstephh 	(void) printf("\n");
1517*5255Sstephh }
1518*5255Sstephh 
1519*5255Sstephh static void
1520*5255Sstephh print_status_record(status_record_t *srp, int summary, int opt_i, int full)
1521*5255Sstephh {
1522*5255Sstephh 	char buf[32];
1523*5255Sstephh 	uurec_t *uurp = srp->uurec;
1524*5255Sstephh 	char *severity;
1525*5255Sstephh 	static int header = 0;
1526*5255Sstephh 	char *head;
1527*5255Sstephh 	ari_list_t *ari_list;
1528*5255Sstephh 
1529*5255Sstephh 	if (nlspath)
1530*5255Sstephh 		severity = get_dict_msg(srp->msgid, "severity", 1, 1);
1531*5255Sstephh 	else
1532*5255Sstephh 		severity = srp->severity;
1533*5255Sstephh 
1534*5255Sstephh 	if (!summary || !header) {
1535*5255Sstephh 		if (opt_i) {
1536*5255Sstephh 			head = "--------------- "
1537*5255Sstephh 			    "------------------------------------  "
1538*5255Sstephh 			    "-------------- ---------\n"
1539*5255Sstephh 			    "TIME            CACHE-ID"
1540*5255Sstephh 			    "                              MSG-ID"
1541*5255Sstephh 			    "         SEVERITY\n--------------- "
1542*5255Sstephh 			    "------------------------------------ "
1543*5255Sstephh 			    " -------------- ---------";
1544*5255Sstephh 		} else {
1545*5255Sstephh 			head = "--------------- "
1546*5255Sstephh 			    "------------------------------------  "
1547*5255Sstephh 			    "-------------- ---------\n"
1548*5255Sstephh 			    "TIME            EVENT-ID"
1549*5255Sstephh 			    "                              MSG-ID"
1550*5255Sstephh 			    "         SEVERITY\n--------------- "
1551*5255Sstephh 			    "------------------------------------ "
1552*5255Sstephh 			    " -------------- ---------";
1553*5255Sstephh 		}
1554*5255Sstephh 		(void) printf("%s\n", dgettext("FMD", head));
1555*5255Sstephh 		header = 1;
1556*5255Sstephh 	}
1557*5255Sstephh 	if (opt_i) {
1558*5255Sstephh 		ari_list = uurp->ari_uuid_list;
1559*5255Sstephh 		while (ari_list) {
1560*5255Sstephh 			(void) printf("%-15s %-37s %-14s %-9s\n",
1561*5255Sstephh 			    format_date(buf, sizeof (buf), uurp->sec),
1562*5255Sstephh 			    ari_list->ari_uuid, srp->msgid, severity);
1563*5255Sstephh 			ari_list = ari_list->next;
1564*5255Sstephh 		}
1565*5255Sstephh 	} else {
1566*5255Sstephh 		(void) printf("%-15s %-37s %-14s %-9s\n",
1567*5255Sstephh 		    format_date(buf, sizeof (buf), uurp->sec),
1568*5255Sstephh 		    uurp->uuid, srp->msgid, severity);
1569*5255Sstephh 	}
1570*5255Sstephh 
1571*5255Sstephh 	if (!summary)
1572*5255Sstephh 		print_sup_record(srp, opt_i, full);
1573*5255Sstephh }
1574*5255Sstephh 
1575*5255Sstephh static void
1576*5255Sstephh print_catalog(int summary, int opt_a, int full, int opt_i, int page_feed)
1577*5255Sstephh {
1578*5255Sstephh 	status_record_t *srp;
1579*5255Sstephh 	sr_list_t *slp;
1580*5255Sstephh 
1581*5255Sstephh 	slp = status_rec_list;
1582*5255Sstephh 	if (slp) {
1583*5255Sstephh 		for (;;) {
1584*5255Sstephh 			srp = slp->status_record;
1585*5255Sstephh 			if (opt_a || srp->not_suppressed) {
1586*5255Sstephh 				if (page_feed)
1587*5255Sstephh 					(void) printf("\f\n");
1588*5255Sstephh 				print_status_record(srp, summary, opt_i, full);
1589*5255Sstephh 			}
1590*5255Sstephh 			if (slp->next == status_rec_list)
1591*5255Sstephh 				break;
1592*5255Sstephh 			slp = slp->next;
1593*5255Sstephh 		}
1594*5255Sstephh 	}
1595*5255Sstephh }
1596*5255Sstephh 
1597*5255Sstephh static name_list_t *
1598*5255Sstephh find_fru(status_record_t *srp, char *resource)
1599*5255Sstephh {
1600*5255Sstephh 	name_list_t *rt = NULL;
1601*5255Sstephh 	name_list_t *fru = srp->fru;
1602*5255Sstephh 
1603*5255Sstephh 	while (fru) {
1604*5255Sstephh 		if (strcmp(resource, fru->name) == 0) {
1605*5255Sstephh 			rt = fru;
1606*5255Sstephh 			break;
1607*5255Sstephh 		}
1608*5255Sstephh 		fru = fru->next;
1609*5255Sstephh 		if (fru == srp->fru)
1610*5255Sstephh 			break;
1611*5255Sstephh 	}
1612*5255Sstephh 	return (rt);
1613*5255Sstephh }
1614*5255Sstephh 
1615*5255Sstephh static void
1616*5255Sstephh print_fru_line(name_list_t *fru, char *uuid)
1617*5255Sstephh {
1618*5255Sstephh 	if (fru->pct == 100) {
1619*5255Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
1620*5255Sstephh 		    dgettext("FMD", "suspects in this FRU total certainty"),
1621*5255Sstephh 		    100);
1622*5255Sstephh 	} else {
1623*5255Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
1624*5255Sstephh 		    dgettext("FMD", "suspects in this FRU max certainty"),
1625*5255Sstephh 		    fru->max_pct);
1626*5255Sstephh 	}
1627*5255Sstephh }
1628*5255Sstephh 
1629*5255Sstephh static void
1630*5255Sstephh print_fru(int summary, int opt_a, int opt_i, int page_feed)
1631*5255Sstephh {
1632*5255Sstephh 	resource_list_t *tp = status_fru_list;
1633*5255Sstephh 	status_record_t *srp;
1634*5255Sstephh 	sr_list_t *slp, *end;
1635*5255Sstephh 	char *msgid, *fru_label;
1636*5255Sstephh 	uurec_t *uurp;
1637*5255Sstephh 	name_list_t *fru;
1638*5255Sstephh 	ari_list_t *ari_list;
1639*5255Sstephh 
1640*5255Sstephh 	while (tp) {
1641*5255Sstephh 		if (opt_a || tp->not_suppressed) {
1642*5255Sstephh 			if (page_feed)
1643*5255Sstephh 				(void) printf("\f\n");
1644*5255Sstephh 			if (!summary)
1645*5255Sstephh 				(void) printf("-----------------------------"
1646*5255Sstephh 				    "---------------------------------------"
1647*5255Sstephh 				    "----------\n");
1648*5255Sstephh 			fru_label = get_fmri_label(tp->resource);
1649*5255Sstephh 			if (fru_label) {
1650*5255Sstephh 				(void) printf("\"%s\" (%s)\n", fru_label,
1651*5255Sstephh 				    tp->resource);
1652*5255Sstephh 				free(fru_label);
1653*5255Sstephh 			} else {
1654*5255Sstephh 				(void) printf("%s\n", tp->resource);
1655*5255Sstephh 			}
1656*5255Sstephh 			slp = tp->status_rec_list;
1657*5255Sstephh 			end = slp;
1658*5255Sstephh 			do {
1659*5255Sstephh 				srp = slp->status_record;
1660*5255Sstephh 				uurp = srp->uurec;
1661*5255Sstephh 				fru = find_fru(srp, tp->resource);
1662*5255Sstephh 				if (fru) {
1663*5255Sstephh 					if (opt_i) {
1664*5255Sstephh 						ari_list = uurp->ari_uuid_list;
1665*5255Sstephh 						while (ari_list) {
1666*5255Sstephh 							print_fru_line(fru,
1667*5255Sstephh 							    ari_list->ari_uuid);
1668*5255Sstephh 							ari_list =
1669*5255Sstephh 							    ari_list->next;
1670*5255Sstephh 						}
1671*5255Sstephh 					} else {
1672*5255Sstephh 						print_fru_line(fru, uurp->uuid);
1673*5255Sstephh 					}
1674*5255Sstephh 				}
1675*5255Sstephh 				slp = slp->next;
1676*5255Sstephh 			} while (slp != end);
1677*5255Sstephh 			if (!summary) {
1678*5255Sstephh 				slp = tp->status_rec_list;
1679*5255Sstephh 				end = slp;
1680*5255Sstephh 				srp = slp->status_record;
1681*5255Sstephh 				if (srp->serial &&
1682*5255Sstephh 				    !serial_in_fru(srp->fru, srp->serial)) {
1683*5255Sstephh 					print_name_list(srp->serial,
1684*5255Sstephh 					    dgettext("FMD", "Serial ID.  :"),
1685*5255Sstephh 					    NULL, 0, 0, NULL, 1);
1686*5255Sstephh 				}
1687*5255Sstephh 				msgid = NULL;
1688*5255Sstephh 				do {
1689*5255Sstephh 					if (msgid == NULL ||
1690*5255Sstephh 					    strcmp(msgid, srp->msgid) != 0) {
1691*5255Sstephh 						msgid = srp->msgid;
1692*5255Sstephh 						print_dict_info(srp->msgid,
1693*5255Sstephh 						    srp->url);
1694*5255Sstephh 					}
1695*5255Sstephh 					slp = slp->next;
1696*5255Sstephh 				} while (slp != end);
1697*5255Sstephh 			}
1698*5255Sstephh 		}
1699*5255Sstephh 		tp = tp->next;
1700*5255Sstephh 		if (tp == status_fru_list)
1701*5255Sstephh 			break;
1702*5255Sstephh 	}
1703*5255Sstephh }
1704*5255Sstephh 
1705*5255Sstephh static void
1706*5255Sstephh print_asru(int opt_a)
1707*5255Sstephh {
1708*5255Sstephh 	resource_list_t *tp = status_asru_list;
1709*5255Sstephh 	status_record_t *srp;
1710*5255Sstephh 	sr_list_t *slp, *end;
1711*5255Sstephh 	char *msg;
1712*5255Sstephh 	int status;
1713*5255Sstephh 	name_list_t *asru;
1714*5255Sstephh 
1715*5255Sstephh 	while (tp) {
1716*5255Sstephh 		if (opt_a || tp->not_suppressed) {
1717*5255Sstephh 			status = 0;
1718*5255Sstephh 			slp = tp->status_rec_list;
1719*5255Sstephh 			end = slp;
1720*5255Sstephh 			do {
1721*5255Sstephh 				srp = slp->status_record;
1722*5255Sstephh 				asru = srp->asru;
1723*5255Sstephh 				while (asru) {
1724*5255Sstephh 					if (strcmp(tp->resource,
1725*5255Sstephh 					    asru->name) == 0)
1726*5255Sstephh 						status |= asru->status;
1727*5255Sstephh 					asru = asru->next;
1728*5255Sstephh 					if (asru == srp->asru)
1729*5255Sstephh 						break;
1730*5255Sstephh 				}
1731*5255Sstephh 				slp = slp->next;
1732*5255Sstephh 			} while (slp != end);
1733*5255Sstephh 			switch (status) {
1734*5255Sstephh 			case 0:
1735*5255Sstephh 				msg = dgettext("FMD", "ok");
1736*5255Sstephh 				break;
1737*5255Sstephh 			case FM_SUSPECT_FAULTY:
1738*5255Sstephh 				msg = dgettext("FMD", "degraded");
1739*5255Sstephh 				break;
1740*5255Sstephh 			case FM_SUSPECT_UNUSABLE:
1741*5255Sstephh 				msg = dgettext("FMD", "unknown");
1742*5255Sstephh 				break;
1743*5255Sstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
1744*5255Sstephh 				msg = dgettext("FMD", "faulted");
1745*5255Sstephh 				break;
1746*5255Sstephh 			default:
1747*5255Sstephh 				msg = "";
1748*5255Sstephh 				break;
1749*5255Sstephh 			}
1750*5255Sstephh 			(void) printf("%-69s %s\n", tp->resource, msg);
1751*5255Sstephh 		}
1752*5255Sstephh 		tp = tp->next;
1753*5255Sstephh 		if (tp == status_asru_list)
1754*5255Sstephh 			break;
1755*5255Sstephh 	}
1756*5255Sstephh }
1757*5255Sstephh 
1758*5255Sstephh static int
1759*5255Sstephh uuid_in_list(char *uuid, uurec_select_t *uurecp)
1760*5255Sstephh {
1761*5255Sstephh 	while (uurecp) {
1762*5255Sstephh 		if (strcmp(uuid, uurecp->uuid) == 0)
1763*5255Sstephh 			return (1);
1764*5255Sstephh 		uurecp = uurecp->next;
1765*5255Sstephh 	}
17660Sstevel@tonic-gate 	return (0);
17670Sstevel@tonic-gate }
17680Sstevel@tonic-gate 
1769*5255Sstephh static int
1770*5255Sstephh dfault_rec(const fmd_adm_caseinfo_t *acp, void *arg)
1771*5255Sstephh {
1772*5255Sstephh 	int64_t *diag_time;
1773*5255Sstephh 	uint_t nelem;
1774*5255Sstephh 	int rt = 0;
1775*5255Sstephh 	char *uuid = "-";
1776*5255Sstephh 	uurec_select_t *uurecp = (uurec_select_t *)arg;
1777*5255Sstephh 
1778*5255Sstephh 	if (nvlist_lookup_int64_array(acp->aci_event, FM_SUSPECT_DIAG_TIME,
1779*5255Sstephh 	    &diag_time, &nelem) == 0 && nelem >= 2) {
1780*5255Sstephh 		(void) nvlist_lookup_string(acp->aci_event, FM_SUSPECT_UUID,
1781*5255Sstephh 		    &uuid);
1782*5255Sstephh 		if (uurecp == NULL || uuid_in_list(uuid, uurecp))
1783*5255Sstephh 			add_fault_record_to_catalog(acp->aci_event, *diag_time,
1784*5255Sstephh 			    uuid, acp->aci_url);
1785*5255Sstephh 	} else {
1786*5255Sstephh 		rt = -1;
1787*5255Sstephh 	}
1788*5255Sstephh 	return (rt);
1789*5255Sstephh }
1790*5255Sstephh 
17910Sstevel@tonic-gate /*ARGSUSED*/
17920Sstevel@tonic-gate static int
1793*5255Sstephh dstatus_rec(const fmd_adm_rsrcinfo_t *ari, void *unused)
17940Sstevel@tonic-gate {
1795*5255Sstephh 	update_asru_state_in_catalog(ari->ari_case, ari->ari_uuid);
17960Sstevel@tonic-gate 	return (0);
17970Sstevel@tonic-gate }
17980Sstevel@tonic-gate 
1799*5255Sstephh static int
1800*5255Sstephh get_cases_from_fmd(fmd_adm_t *adm, uurec_select_t *uurecp, int opt_i)
1801*5255Sstephh {
1802*5255Sstephh 	int rt = FMADM_EXIT_SUCCESS;
1803*5255Sstephh 
1804*5255Sstephh 	/*
1805*5255Sstephh 	 * These calls may fail with Protocol error if message payload is to big
1806*5255Sstephh 	 */
1807*5255Sstephh 	if (fmd_adm_case_iter(adm, NULL, dfault_rec, uurecp) != 0)
1808*5255Sstephh 		die("failed to get case list from fmd");
1809*5255Sstephh 	if (opt_i && fmd_adm_rsrc_iter(adm, 1, dstatus_rec, NULL) != 0)
1810*5255Sstephh 		die("failed to get case status from fmd");
1811*5255Sstephh 	return (rt);
1812*5255Sstephh }
1813*5255Sstephh 
1814*5255Sstephh /*
1815*5255Sstephh  * fmadm faulty command
1816*5255Sstephh  *
1817*5255Sstephh  *	-a		show hidden fault records
1818*5255Sstephh  *	-f		show faulty fru's
1819*5255Sstephh  *	-g		force grouping of similar faults on the same fru
1820*5255Sstephh  *	-n		number of fault records to display
1821*5255Sstephh  *	-p		pipe output through pager
1822*5255Sstephh  *	-r		show faulty asru's
1823*5255Sstephh  *	-s		print summary of first fault
1824*5255Sstephh  *	-u		print listed uuid's only
1825*5255Sstephh  *	-v		full output
1826*5255Sstephh  */
1827*5255Sstephh 
18280Sstevel@tonic-gate int
18290Sstevel@tonic-gate cmd_faulty(fmd_adm_t *adm, int argc, char *argv[])
18300Sstevel@tonic-gate {
1831*5255Sstephh 	int opt_a = 0, opt_v = 0, opt_p = 0, opt_s = 0, opt_r = 0, opt_f = 0;
1832*5255Sstephh 	int opt_i = 0;
1833*5255Sstephh 	char *pager;
1834*5255Sstephh 	FILE *fp;
1835*5255Sstephh 	int rt, c, stat;
1836*5255Sstephh 	uurec_select_t *tp;
1837*5255Sstephh 	uurec_select_t *uurecp = NULL;
18380Sstevel@tonic-gate 
1839*5255Sstephh 	catalog_setup();
1840*5255Sstephh 	while ((c = getopt(argc, argv, "afgin:prsu:v")) != EOF) {
18410Sstevel@tonic-gate 		switch (c) {
18420Sstevel@tonic-gate 		case 'a':
18430Sstevel@tonic-gate 			opt_a++;
18440Sstevel@tonic-gate 			break;
1845*5255Sstephh 		case 'f':
1846*5255Sstephh 			opt_f++;
1847*5255Sstephh 			break;
1848*5255Sstephh 		case 'g':
1849*5255Sstephh 			opt_g++;
1850*5255Sstephh 			break;
18510Sstevel@tonic-gate 		case 'i':
1852*5255Sstephh 			opt_i++;
1853*5255Sstephh 			break;
1854*5255Sstephh 		case 'n':
1855*5255Sstephh 			max_fault = atoi(optarg);
1856*5255Sstephh 			break;
1857*5255Sstephh 		case 'p':
1858*5255Sstephh 			opt_p++;
1859*5255Sstephh 			break;
1860*5255Sstephh 		case 'r':
1861*5255Sstephh 			opt_r++;
1862*5255Sstephh 			break;
1863*5255Sstephh 		case 's':
1864*5255Sstephh 			opt_s++;
1865*5255Sstephh 			break;
1866*5255Sstephh 		case 'u':
1867*5255Sstephh 			tp = (uurec_select_t *)malloc(sizeof (uurec_select_t));
1868*5255Sstephh 			tp->uuid = optarg;
1869*5255Sstephh 			tp->next = uurecp;
1870*5255Sstephh 			uurecp = tp;
1871*5255Sstephh 			opt_a = 1;
1872*5255Sstephh 			break;
1873*5255Sstephh 		case 'v':
1874*5255Sstephh 			opt_v++;
18750Sstevel@tonic-gate 			break;
18760Sstevel@tonic-gate 		default:
18770Sstevel@tonic-gate 			return (FMADM_EXIT_USAGE);
18780Sstevel@tonic-gate 		}
18790Sstevel@tonic-gate 	}
18800Sstevel@tonic-gate 	if (optind < argc)
18810Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
18820Sstevel@tonic-gate 
1883*5255Sstephh 	rt = get_cases_from_fmd(adm, uurecp, opt_i);
1884*5255Sstephh 	if (opt_p) {
1885*5255Sstephh 		if ((pager = getenv("PAGER")) == NULL)
1886*5255Sstephh 			pager = "/usr/bin/more";
1887*5255Sstephh 		fp = popen(pager, "w");
1888*5255Sstephh 		if (fp == NULL) {
1889*5255Sstephh 			rt = FMADM_EXIT_ERROR;
1890*5255Sstephh 			opt_p = 0;
1891*5255Sstephh 		} else {
1892*5255Sstephh 			dup2(fileno(fp), 1);
1893*5255Sstephh 			setbuf(stdout, NULL);
1894*5255Sstephh 			(void) fclose(fp);
1895*5255Sstephh 		}
1896*5255Sstephh 	}
1897*5255Sstephh 	max_display = max_fault;
1898*5255Sstephh 	if (opt_f)
1899*5255Sstephh 		print_fru(opt_s, opt_a, opt_i, opt_p && !opt_s);
1900*5255Sstephh 	if (opt_r)
1901*5255Sstephh 		print_asru(opt_a);
1902*5255Sstephh 	if (opt_f == 0 && opt_r == 0)
1903*5255Sstephh 		print_catalog(opt_s, opt_a, opt_v, opt_i, opt_p && !opt_s);
1904*5255Sstephh 	label_release_topo();
1905*5255Sstephh 	if (opt_p) {
1906*5255Sstephh 		(void) fclose(stdout);
1907*5255Sstephh 		(void) wait(&stat);
1908*5255Sstephh 	}
1909*5255Sstephh 	return (rt);
19100Sstevel@tonic-gate }
19110Sstevel@tonic-gate 
19120Sstevel@tonic-gate int
19130Sstevel@tonic-gate cmd_flush(fmd_adm_t *adm, int argc, char *argv[])
19140Sstevel@tonic-gate {
19150Sstevel@tonic-gate 	int i, status = FMADM_EXIT_SUCCESS;
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate 	if (argc < 2 || (i = getopt(argc, argv, "")) != EOF)
19180Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	for (i = 1; i < argc; i++) {
19210Sstevel@tonic-gate 		if (fmd_adm_rsrc_flush(adm, argv[i]) != 0) {
19220Sstevel@tonic-gate 			warn("failed to flush %s", argv[i]);
19230Sstevel@tonic-gate 			status = FMADM_EXIT_ERROR;
19240Sstevel@tonic-gate 		} else
19250Sstevel@tonic-gate 			note("flushed resource history for %s\n", argv[i]);
19260Sstevel@tonic-gate 	}
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 	return (status);
19290Sstevel@tonic-gate }
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate int
19320Sstevel@tonic-gate cmd_repair(fmd_adm_t *adm, int argc, char *argv[])
19330Sstevel@tonic-gate {
19340Sstevel@tonic-gate 	int err;
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	if (getopt(argc, argv, "") != EOF)
19370Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	if (argc - optind != 1)
19400Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 	/*
19430Sstevel@tonic-gate 	 * For now, we assume that if the input string contains a colon, it is
19440Sstevel@tonic-gate 	 * an FMRI and if it does not it is a UUID.  If things get more complex
19450Sstevel@tonic-gate 	 * in the future with multiple UUID formats, an FMRI parser can be
19460Sstevel@tonic-gate 	 * added here to differentiate the input argument appropriately.
19470Sstevel@tonic-gate 	 */
19480Sstevel@tonic-gate 	if (strchr(argv[optind], ':') != NULL)
19490Sstevel@tonic-gate 		err = fmd_adm_rsrc_repair(adm, argv[optind]);
19500Sstevel@tonic-gate 	else
19510Sstevel@tonic-gate 		err = fmd_adm_case_repair(adm, argv[optind]);
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 	if (err != 0)
19540Sstevel@tonic-gate 		die("failed to record repair to %s", argv[optind]);
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	note("recorded repair to %s\n", argv[optind]);
19570Sstevel@tonic-gate 	return (FMADM_EXIT_SUCCESS);
19580Sstevel@tonic-gate }
1959