xref: /onnv-gate/usr/src/cmd/fm/fmadm/common/faulty.c (revision 10928:eb060666c73f)
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
55255Sstephh  * Common Development and Distribution License (the "License").
65255Sstephh  * 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 /*
229120SStephen.Hanson@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
265255Sstephh #include <sys/types.h>
275255Sstephh #include <fmadm.h>
285255Sstephh #include <errno.h>
295255Sstephh #include <limits.h>
300Sstevel@tonic-gate #include <strings.h>
315255Sstephh #include <stdio.h>
325255Sstephh #include <unistd.h>
335255Sstephh #include <sys/wait.h>
345255Sstephh #include <sys/stat.h>
355255Sstephh #include <fcntl.h>
365255Sstephh #include <fm/fmd_log.h>
375255Sstephh #include <sys/fm/protocol.h>
385255Sstephh #include <fm/libtopo.h>
395255Sstephh #include <fm/fmd_adm.h>
409501SRobert.Johnston@Sun.COM #include <fm/fmd_msg.h>
415255Sstephh #include <dlfcn.h>
425255Sstephh #include <sys/systeminfo.h>
435255Sstephh #include <sys/utsname.h>
445255Sstephh #include <libintl.h>
455255Sstephh #include <locale.h>
465255Sstephh #include <sys/smbios.h>
475255Sstephh #include <libdevinfo.h>
485255Sstephh #include <stdlib.h>
495255Sstephh 
505255Sstephh #define	offsetof(s, m)	((size_t)(&(((s*)0)->m)))
515255Sstephh 
525255Sstephh /*
535255Sstephh  * Fault records are added to catalog by calling add_fault_record_to_catalog()
545255Sstephh  * records are stored in order of importance to the system.
555255Sstephh  * If -g flag is set or not_suppressed is not set and the class fru, fault,
565255Sstephh  * type are the same then details are merged into an existing record, with uuid
575255Sstephh  * records are stored in time order.
585255Sstephh  * For each record information is extracted from nvlist and merged into linked
595255Sstephh  * list each is checked for identical records for which percentage certainty are
605255Sstephh  * added together.
615255Sstephh  * print_catalog() is called to print out catalog and release external resources
625255Sstephh  *
635255Sstephh  *                         /---------------\
645255Sstephh  *	status_rec_list -> |               | -|
655255Sstephh  *                         \---------------/
665255Sstephh  *                                \/
675255Sstephh  *                         /---------------\    /-------\    /-------\
685255Sstephh  *      status_fru_list    | status_record | -> | uurec | -> | uurec | -|
695255Sstephh  *            \/           |               | |- |       | <- |       |
705255Sstephh  *      /-------------\    |               |    \-------/    \-------/
715255Sstephh  *      |             | -> |               |       \/           \/
725255Sstephh  *      \-------------/    |               |    /-------\    /-------\
735255Sstephh  *            \/           |               | -> | asru  | -> | asru  |
745255Sstephh  *            ---          |               |    |       | <- |       |
755255Sstephh  *                         |               |    \-------/    \-------/
765255Sstephh  *      status_asru_list   |  class        |
775255Sstephh  *            \/           |  resource     |    /-------\    /-------\
785255Sstephh  *      /-------------\    |  fru          | -> | list  | -> | list  |
795255Sstephh  *      |             | -> |  serial       |    |       | <- |       |
805255Sstephh  *      \-------------/    |               |    \-------/    \-------/
815255Sstephh  *            \/           \---------------/
825255Sstephh  *            ---               \/    /\
835255Sstephh  *                         /---------------\
845255Sstephh  *                         | status_record |
855255Sstephh  *                         \---------------/
865255Sstephh  *
875255Sstephh  * Fmadm faulty takes a number of options which affect the format of the
885255Sstephh  * output displayed. By default, the display reports the FRU and ASRU along
895255Sstephh  * with other information on per-case basis as in the example below.
905255Sstephh  *
915255Sstephh  * --------------- ------------------------------------  -------------- -------
925255Sstephh  * TIME            EVENT-ID                              MSG-ID         SEVERITY
935255Sstephh  * --------------- ------------------------------------  -------------- -------
945255Sstephh  * Sep 21 10:01:36 d482f935-5c8f-e9ab-9f25-d0aaafec1e6c  AMD-8000-2F    Major
955255Sstephh  *
965255Sstephh  * Fault class	: fault.memory.dimm_sb
975255Sstephh  * Affects	: mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0
987275Sstephh  *		    faulted but still in service
995255Sstephh  * FRU		: "CPU 0 DIMM 0" (hc://.../memory-controller=0/dimm=0)
1005255Sstephh  *		    faulty
1015255Sstephh  *
1025255Sstephh  * Description	: The number of errors associated with this memory module has
1035255Sstephh  *		exceeded acceptable levels.  Refer to
1045255Sstephh  *		http://sun.com/msg/AMD-8000-2F for more information.
1055255Sstephh  *
1065255Sstephh  * Response	: Pages of memory associated with this memory module are being
1075255Sstephh  *		removed from service as errors are reported.
1085255Sstephh  *
1095255Sstephh  * Impact	: Total system memory capacity will be reduced as pages are
1105255Sstephh  *		retired.
1115255Sstephh  *
1125255Sstephh  * Action	: Schedule a repair procedure to replace the affected memory
1135255Sstephh  *		module.  Use fmdump -v -u <EVENT_ID> to identify the module.
1145255Sstephh  *
1155255Sstephh  * The -v flag is similar, but adds some additonal information such as the
1165255Sstephh  * resource. The -s flag is also similar but just gives the top line summary.
1175255Sstephh  * All these options (ie without the -f or -r flags) use the print_catalog()
1185255Sstephh  * function to do the display.
1195255Sstephh  *
1205255Sstephh  * The -f flag changes the output so that it appears sorted on a per-fru basis.
1215255Sstephh  * The output is somewhat cut down compared to the default output. If -f is
1225255Sstephh  * used, then print_fru() is used to print the output.
1235255Sstephh  *
1245255Sstephh  * -----------------------------------------------------------------------------
1255255Sstephh  * "SLOT 2" (hc://.../hostbridge=3/pciexrc=3/pciexbus=4/pciexdev=0) faulty
1265255Sstephh  * 5ca4aeb3-36...f6be-c2e8166dc484 2 suspects in this FRU total certainty 100%
1275255Sstephh  *
1285255Sstephh  * Description	: A problem was detected for a PCI device.
1295255Sstephh  *		Refer to http://sun.com/msg/PCI-8000-7J for more information.
1305255Sstephh  *
1315255Sstephh  * Response	: One or more device instances may be disabled
1325255Sstephh  *
1335255Sstephh  * Impact	: Possible loss of services provided by the device instances
1345255Sstephh  *		associated with this fault
1355255Sstephh  *
1365255Sstephh  * Action	: Schedule a repair procedure to replace the affected device.
1375255Sstephh  * 		Use fmdump -v -u <EVENT_ID> to identify the device or contact
1385255Sstephh  *		Sun for support.
1395255Sstephh  *
1405255Sstephh  * The -r flag changes the output so that it appears sorted on a per-asru basis.
1415255Sstephh  * The output is very much cut down compared to the default output, just giving
1425255Sstephh  * the asru fmri and state. Here print_asru() is used to print the output.
1435255Sstephh  *
1445255Sstephh  * mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0	degraded
1455255Sstephh  *
1465255Sstephh  * For all fmadm faulty options, the sequence of events is
1475255Sstephh  *
1485255Sstephh  * 1) Walk through all the cases in the system using fmd_adm_case_iter() and
1495255Sstephh  * for each case call dfault_rec(). This will call add_fault_record_to_catalog()
1505255Sstephh  * This will extract the data from the nvlist and call catalog_new_record() to
1515255Sstephh  * save the data away in various linked lists in the catalogue.
1525255Sstephh  *
1535255Sstephh  * 2) Once this is done, the data can be supplemented by using
1545255Sstephh  * fmd_adm_rsrc_iter(). However this is now only necessary for the -i option.
1555255Sstephh  *
1565255Sstephh  * 3) Finally print_catalog(), print_fru() or print_asru() are called as
1575255Sstephh  * appropriate to display the information from the catalogue sorted in the
1585255Sstephh  * requested way.
1595255Sstephh  *
1605255Sstephh  */
1615255Sstephh 
1625255Sstephh typedef struct name_list {
1635255Sstephh 	struct name_list *next;
1645255Sstephh 	struct name_list *prev;
1655255Sstephh 	char *name;
1665255Sstephh 	uint8_t pct;
1675255Sstephh 	uint8_t max_pct;
1685255Sstephh 	ushort_t count;
1695255Sstephh 	int status;
1706002Sstephh 	char *label;
1715255Sstephh } name_list_t;
1725255Sstephh 
1735255Sstephh typedef struct ari_list {
1745255Sstephh 	char *ari_uuid;
1755255Sstephh 	struct ari_list *next;
1765255Sstephh } ari_list_t;
1775255Sstephh 
1785255Sstephh typedef struct uurec {
1795255Sstephh 	struct uurec *next;
1805255Sstephh 	struct uurec *prev;
1815255Sstephh 	char *uuid;
1825255Sstephh 	ari_list_t *ari_uuid_list;
1835255Sstephh 	name_list_t *asru;
1845255Sstephh 	uint64_t sec;
18510234SRobert.Johnston@Sun.COM 	nvlist_t *event;
1865255Sstephh } uurec_t;
1875255Sstephh 
1885255Sstephh typedef struct uurec_select {
1895255Sstephh 	struct uurec_select *next;
1905255Sstephh 	char *uuid;
1915255Sstephh } uurec_select_t;
1925255Sstephh 
1935255Sstephh typedef struct host_id {
1945255Sstephh 	char *chassis;
1955255Sstephh 	char *server;
1965255Sstephh 	char *platform;
1979120SStephen.Hanson@Sun.COM 	char *domain;
19810462SSean.Ye@Sun.COM 	char *product_sn;
1995255Sstephh } hostid_t;
2005255Sstephh 
2015255Sstephh typedef struct host_id_list {
2025255Sstephh 	hostid_t hostid;
2035255Sstephh 	struct host_id_list *next;
2045255Sstephh } host_id_list_t;
2055255Sstephh 
2065255Sstephh typedef struct status_record {
2075255Sstephh 	hostid_t *host;
2085255Sstephh 	int nrecs;
2095255Sstephh 	uurec_t *uurec;
2105255Sstephh 	char *severity;			/* in C locale */
2115255Sstephh 	char *msgid;
2125255Sstephh 	name_list_t *class;
2135255Sstephh 	name_list_t *resource;
2145255Sstephh 	name_list_t *asru;
2155255Sstephh 	name_list_t *fru;
2165255Sstephh 	name_list_t *serial;
2175255Sstephh 	uint8_t not_suppressed;
218*10928SStephen.Hanson@Sun.COM 	uint8_t injected;
2195255Sstephh } status_record_t;
2205255Sstephh 
2215255Sstephh typedef struct sr_list {
2225255Sstephh 	struct sr_list *next;
2235255Sstephh 	struct sr_list *prev;
2245255Sstephh 	struct status_record *status_record;
2255255Sstephh } sr_list_t;
2265255Sstephh 
2275255Sstephh typedef struct resource_list {
2285255Sstephh 	struct resource_list *next;
2295255Sstephh 	struct resource_list *prev;
2305255Sstephh 	sr_list_t *status_rec_list;
2315255Sstephh 	char *resource;
2325255Sstephh 	uint8_t not_suppressed;
233*10928SStephen.Hanson@Sun.COM 	uint8_t injected;
2345255Sstephh 	uint8_t max_pct;
2355255Sstephh } resource_list_t;
2365255Sstephh 
2375255Sstephh typedef struct tgetlabel_data {
2385255Sstephh 	char *label;
2395255Sstephh 	char *fru;
2405255Sstephh } tgetlabel_data_t;
2410Sstevel@tonic-gate 
2425255Sstephh sr_list_t *status_rec_list;
2435255Sstephh resource_list_t *status_fru_list;
2445255Sstephh resource_list_t *status_asru_list;
2455255Sstephh 
2465255Sstephh static int max_display;
2475255Sstephh static int max_fault = 0;
2485255Sstephh static topo_hdl_t *topo_handle;
2495255Sstephh static char *topo_handle_uuid;
2505255Sstephh static host_id_list_t *host_list;
2515255Sstephh static int n_server;
2525255Sstephh static int opt_g;
2539501SRobert.Johnston@Sun.COM static fmd_msg_hdl_t *fmadm_msghdl = NULL; /* handle for libfmd_msg calls */
2545255Sstephh 
2555255Sstephh static char *
2565255Sstephh format_date(char *buf, size_t len, uint64_t sec)
2575255Sstephh {
2585255Sstephh 	if (sec > LONG_MAX) {
2595255Sstephh 		(void) fprintf(stderr,
2605255Sstephh 		    "record time is too large for 32-bit utility\n");
2615255Sstephh 		(void) snprintf(buf, len, "0x%llx", sec);
2625255Sstephh 	} else {
2635255Sstephh 		time_t tod = (time_t)sec;
264*10928SStephen.Hanson@Sun.COM 		time_t now = time(NULL);
265*10928SStephen.Hanson@Sun.COM 		if (tod > now+60 ||
266*10928SStephen.Hanson@Sun.COM 		    tod < now - 6L*30L*24L*60L*60L) { /* 6 months ago */
267*10928SStephen.Hanson@Sun.COM 			(void) strftime(buf, len, "%b %d %Y    ",
268*10928SStephen.Hanson@Sun.COM 			    localtime(&tod));
269*10928SStephen.Hanson@Sun.COM 		} else {
270*10928SStephen.Hanson@Sun.COM 			(void) strftime(buf, len, "%b %d %T", localtime(&tod));
271*10928SStephen.Hanson@Sun.COM 		}
2725255Sstephh 	}
2735255Sstephh 
2745255Sstephh 	return (buf);
2755255Sstephh }
2765255Sstephh 
2775255Sstephh static hostid_t *
27810462SSean.Ye@Sun.COM find_hostid_in_list(char *platform, char *chassis, char *server, char *domain,
27910462SSean.Ye@Sun.COM     char *product_sn)
2805255Sstephh {
2815255Sstephh 	hostid_t *rt = NULL;
2825255Sstephh 	host_id_list_t *hostp;
2835255Sstephh 
2845255Sstephh 	if (platform == NULL)
2855255Sstephh 		platform = "-";
2865255Sstephh 	if (server == NULL)
2875255Sstephh 		server = "-";
2885255Sstephh 	hostp = host_list;
2895255Sstephh 	while (hostp) {
2905255Sstephh 		if (hostp->hostid.platform &&
2915255Sstephh 		    strcmp(hostp->hostid.platform, platform) == 0 &&
2925255Sstephh 		    hostp->hostid.server &&
2935255Sstephh 		    strcmp(hostp->hostid.server, server) == 0 &&
2945255Sstephh 		    (chassis == NULL || hostp->hostid.chassis == NULL ||
2959120SStephen.Hanson@Sun.COM 		    strcmp(chassis, hostp->hostid.chassis) == 0) &&
29610462SSean.Ye@Sun.COM 		    (product_sn == NULL || hostp->hostid.product_sn == NULL ||
29710462SSean.Ye@Sun.COM 		    strcmp(product_sn, hostp->hostid.product_sn) == 0) &&
2989120SStephen.Hanson@Sun.COM 		    (domain == NULL || hostp->hostid.domain == NULL ||
2999120SStephen.Hanson@Sun.COM 		    strcmp(domain, hostp->hostid.domain) == 0)) {
3005255Sstephh 			rt = &hostp->hostid;
3015255Sstephh 			break;
3025255Sstephh 		}
3035255Sstephh 		hostp = hostp->next;
3045255Sstephh 	}
3055255Sstephh 	if (rt == NULL) {
3065255Sstephh 		hostp = malloc(sizeof (host_id_list_t));
3075255Sstephh 		hostp->hostid.platform = strdup(platform);
30810462SSean.Ye@Sun.COM 		hostp->hostid.product_sn =
30910462SSean.Ye@Sun.COM 		    product_sn ? strdup(product_sn) : NULL;
3105255Sstephh 		hostp->hostid.server = strdup(server);
3115255Sstephh 		hostp->hostid.chassis = chassis ? strdup(chassis) : NULL;
3129120SStephen.Hanson@Sun.COM 		hostp->hostid.domain = domain ? strdup(domain) : NULL;
3135255Sstephh 		hostp->next = host_list;
3145255Sstephh 		host_list = hostp;
3155255Sstephh 		rt = &hostp->hostid;
3165255Sstephh 		n_server++;
3175255Sstephh 	}
3185255Sstephh 	return (rt);
3195255Sstephh }
3205255Sstephh 
3215255Sstephh static hostid_t *
3225255Sstephh find_hostid(nvlist_t *nvl)
3235255Sstephh {
3249120SStephen.Hanson@Sun.COM 	char *platform = NULL, *chassis = NULL, *server = NULL, *domain = NULL;
32510462SSean.Ye@Sun.COM 	char *product_sn = NULL;
3265255Sstephh 	nvlist_t *auth, *fmri;
3275255Sstephh 	hostid_t *rt = NULL;
3285255Sstephh 
3295255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &fmri) == 0 &&
3305255Sstephh 	    nvlist_lookup_nvlist(fmri, FM_FMRI_AUTHORITY, &auth) == 0) {
3315255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT,
3325255Sstephh 		    &platform);
33310462SSean.Ye@Sun.COM 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN,
33410462SSean.Ye@Sun.COM 		    &product_sn);
3355255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server);
3365255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS,
3375255Sstephh 		    &chassis);
3389120SStephen.Hanson@Sun.COM 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_DOMAIN, &domain);
33910462SSean.Ye@Sun.COM 		rt = find_hostid_in_list(platform, chassis, server,
34010462SSean.Ye@Sun.COM 		    domain, product_sn);
3415255Sstephh 	}
3425255Sstephh 	return (rt);
3435255Sstephh }
3445255Sstephh 
3455255Sstephh /*
3465255Sstephh  * compare two fru strings which are made up of substrings seperated by '/'
3475255Sstephh  * return true if every substring is the same in the two strings, or if a
3485255Sstephh  * substring is null in one.
3495255Sstephh  */
3505255Sstephh 
3515255Sstephh static int
3525255Sstephh frucmp(char *f1, char *f2)
3535255Sstephh {
3545255Sstephh 	char c1, c2;
3555255Sstephh 	int i = 0;
3565255Sstephh 
3575255Sstephh 	for (;;) {
3585255Sstephh 		c1 = *f1;
3595255Sstephh 		c2 = *f2;
3605255Sstephh 		if (c1 == c2) {
3615255Sstephh 			i = (c1 == '/') ? 0 : i + 1;
3625255Sstephh 		} else if (i == 0) {
3635255Sstephh 			if (c1 == '/') {
3645255Sstephh 				do {
3655255Sstephh 					f2++;
3665255Sstephh 				} while ((c2 = *f2) != 0 && c2 != '/');
3675255Sstephh 				if (c2 == NULL)
3685255Sstephh 					break;
3695255Sstephh 			} else if (c2 == '/') {
3705255Sstephh 				do {
3715255Sstephh 					f1++;
3725255Sstephh 				} while ((c1 = *f1) != 0 && c1 != '/');
3735255Sstephh 				if (c1 == NULL)
3745255Sstephh 					break;
3755255Sstephh 			} else
3765255Sstephh 				break;
3775255Sstephh 		} else
3785255Sstephh 			break;
3795255Sstephh 		if (c1 == NULL)
3805255Sstephh 			return (0);
3815255Sstephh 		f1++;
3825255Sstephh 		f2++;
3835255Sstephh 	}
3845255Sstephh 	return (1);
3855255Sstephh }
3865255Sstephh 
3875255Sstephh static int
3885255Sstephh tgetlabel(topo_hdl_t *thp, tnode_t *node, void *arg)
3890Sstevel@tonic-gate {
3905255Sstephh 	int err;
3915255Sstephh 	char *fru_name, *lname;
3925255Sstephh 	nvlist_t *fru = NULL;
3935255Sstephh 	int rt = TOPO_WALK_NEXT;
3945255Sstephh 	tgetlabel_data_t *tdp = (tgetlabel_data_t *)arg;
3955255Sstephh 
3965255Sstephh 	if (topo_node_fru(node, &fru, NULL, &err) == 0) {
3975255Sstephh 		if (topo_fmri_nvl2str(thp, fru, &fru_name, &err) == 0) {
3985255Sstephh 			if (frucmp(tdp->fru, fru_name) == 0 &&
3995255Sstephh 			    topo_node_label(node, &lname, &err) == 0) {
4005255Sstephh 				tdp->label = strdup(lname);
4015255Sstephh 				topo_hdl_strfree(thp, lname);
4025255Sstephh 				rt = TOPO_WALK_TERMINATE;
4035255Sstephh 			}
4045255Sstephh 			topo_hdl_strfree(thp, fru_name);
4055255Sstephh 		}
4065255Sstephh 		nvlist_free(fru);
4075255Sstephh 	}
4085255Sstephh 	return (rt);
4095255Sstephh }
4105255Sstephh 
4115255Sstephh static void
4125255Sstephh label_get_topo(void)
4135255Sstephh {
4145255Sstephh 	int err;
4155255Sstephh 
4165255Sstephh 	topo_handle = topo_open(TOPO_VERSION, 0, &err);
4175255Sstephh 	if (topo_handle) {
4185255Sstephh 		topo_handle_uuid = topo_snap_hold(topo_handle, NULL, &err);
4195255Sstephh 	}
4205255Sstephh }
4215255Sstephh 
4225255Sstephh static void
4235255Sstephh label_release_topo(void)
4245255Sstephh {
4255255Sstephh 	if (topo_handle_uuid)
4265255Sstephh 		topo_hdl_strfree(topo_handle, topo_handle_uuid);
4275255Sstephh 	if (topo_handle) {
4285255Sstephh 		topo_snap_release(topo_handle);
4295255Sstephh 		topo_close(topo_handle);
4305255Sstephh 	}
4315255Sstephh }
4325255Sstephh 
4335255Sstephh static char *
4345255Sstephh get_fmri_label(char *fru)
4355255Sstephh {
4365255Sstephh 	topo_walk_t *twp;
4375255Sstephh 	tgetlabel_data_t td;
4385255Sstephh 	int err;
4395255Sstephh 
4405255Sstephh 	td.label = NULL;
4415255Sstephh 	td.fru = fru;
4425255Sstephh 	if (topo_handle == NULL)
4435255Sstephh 		label_get_topo();
4445255Sstephh 	if (topo_handle_uuid) {
4455255Sstephh 		twp = topo_walk_init(topo_handle, FM_FMRI_SCHEME_HC,
4465255Sstephh 		    tgetlabel, &td, &err);
4475255Sstephh 		if (twp) {
4485255Sstephh 			topo_walk_step(twp, TOPO_WALK_CHILD);
4495255Sstephh 			topo_walk_fini(twp);
4505255Sstephh 		}
4515255Sstephh 	}
4525255Sstephh 	return (td.label);
4535255Sstephh }
4545255Sstephh 
4555255Sstephh static char *
4565255Sstephh get_nvl2str_topo(nvlist_t *nvl)
4575255Sstephh {
4585255Sstephh 	char *name = NULL;
4595255Sstephh 	char *tname;
4605255Sstephh 	int err;
4615255Sstephh 	char *scheme = NULL;
4625255Sstephh 	char *mod_name = NULL;
4635255Sstephh 	char buf[128];
4645255Sstephh 
4655255Sstephh 	if (topo_handle == NULL)
4665255Sstephh 		label_get_topo();
4675255Sstephh 	if (topo_fmri_nvl2str(topo_handle, nvl, &tname, &err) == 0) {
4685255Sstephh 		name = strdup(tname);
4695255Sstephh 		topo_hdl_strfree(topo_handle, tname);
4705255Sstephh 	} else {
4715255Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme);
4725255Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_MOD_NAME, &mod_name);
4735255Sstephh 		if (scheme && strcmp(scheme, FM_FMRI_SCHEME_FMD) == 0 &&
4745255Sstephh 		    mod_name) {
4755255Sstephh 			(void) snprintf(buf, sizeof (buf), "%s:///module/%s",
4765255Sstephh 			    scheme, mod_name);
4775255Sstephh 			name = strdup(buf);
4785255Sstephh 		}
4795255Sstephh 	}
4805255Sstephh 	return (name);
4815255Sstephh }
4825255Sstephh 
4835255Sstephh static int
4845255Sstephh set_priority(char *s)
4855255Sstephh {
4865255Sstephh 	int rt = 0;
4875255Sstephh 
4885255Sstephh 	if (s) {
4895255Sstephh 		if (strcmp(s, "Minor") == 0)
4905255Sstephh 			rt = 1;
4915255Sstephh 		else if (strcmp(s, "Major") == 0)
4925255Sstephh 			rt = 10;
4935255Sstephh 		else if (strcmp(s, "Critical") == 0)
4945255Sstephh 			rt = 100;
4955255Sstephh 	}
4965255Sstephh 	return (rt);
4975255Sstephh }
4985255Sstephh 
4995255Sstephh static int
5005255Sstephh cmp_priority(char *s1, char *s2, uint64_t t1, uint64_t t2, uint8_t p1,
5015255Sstephh     uint8_t p2)
5025255Sstephh {
5035255Sstephh 	int r1, r2;
5045255Sstephh 	int rt;
5055255Sstephh 
5065255Sstephh 	r1 = set_priority(s1);
5075255Sstephh 	r2 = set_priority(s2);
5085255Sstephh 	rt = r1 - r2;
5095255Sstephh 	if (rt == 0) {
5105255Sstephh 		if (t1 > t2)
5115255Sstephh 			rt = 1;
5125255Sstephh 		else if (t1 < t2)
5135255Sstephh 			rt = -1;
5145255Sstephh 		else
5155255Sstephh 			rt = p1 - p2;
5165255Sstephh 	}
5175255Sstephh 	return (rt);
5185255Sstephh }
5195255Sstephh 
5205255Sstephh /*
5215255Sstephh  * merge two lists into one, by comparing enties in new and moving into list if
5225255Sstephh  * name is not there or free off memory for names which are already there
5235255Sstephh  * add_pct indicates if pct is the sum or highest pct
5245255Sstephh  */
5255255Sstephh static name_list_t *
5265255Sstephh merge_name_list(name_list_t **list, name_list_t *new, int add_pct)
5275255Sstephh {
5285255Sstephh 	name_list_t *lp, *np, *sp, *rt = NULL;
5295255Sstephh 	int max_pct;
5305255Sstephh 
5315255Sstephh 	rt = *list;
5325255Sstephh 	np = new;
5335255Sstephh 	while (np) {
5345255Sstephh 		lp = *list;
5355255Sstephh 		while (lp) {
5365255Sstephh 			if (strcmp(lp->name, np->name) == 0)
5375255Sstephh 				break;
5385255Sstephh 			lp = lp->next;
5395255Sstephh 			if (lp == *list)
5405255Sstephh 				lp = NULL;
5415255Sstephh 		}
5425255Sstephh 		if (np->next == new)
5435255Sstephh 			sp = NULL;
5445255Sstephh 		else
5455255Sstephh 			sp = np->next;
5465255Sstephh 		if (lp) {
5475255Sstephh 			lp->status |= (np->status & FM_SUSPECT_FAULTY);
5485255Sstephh 			if (add_pct) {
5495255Sstephh 				lp->pct += np->pct;
5505255Sstephh 				lp->count += np->count;
5515255Sstephh 			} else if (np->pct > lp->pct) {
5525255Sstephh 				lp->pct = np->pct;
5535255Sstephh 			}
5545255Sstephh 			max_pct = np->max_pct;
5556002Sstephh 			if (np->label)
5566002Sstephh 				free(np->label);
5575255Sstephh 			free(np->name);
5585255Sstephh 			free(np);
5595255Sstephh 			np = NULL;
5605255Sstephh 			if (max_pct > lp->max_pct) {
5615255Sstephh 				lp->max_pct = max_pct;
5625255Sstephh 				if (lp->max_pct > lp->prev->max_pct &&
5635255Sstephh 				    lp != *list) {
5645255Sstephh 					lp->prev->next = lp->next;
5655255Sstephh 					lp->next->prev = lp->prev;
5665255Sstephh 					np = lp;
5675255Sstephh 				}
5685255Sstephh 			}
5695255Sstephh 		}
5705255Sstephh 		if (np) {
5715255Sstephh 			lp = *list;
5725255Sstephh 			if (lp) {
5735255Sstephh 				if (np->max_pct > lp->max_pct) {
5745255Sstephh 					np->next = lp;
5755255Sstephh 					np->prev = lp->prev;
5765255Sstephh 					lp->prev->next = np;
5775255Sstephh 					lp->prev = np;
5785255Sstephh 					*list = np;
5795255Sstephh 					rt = np;
5805255Sstephh 				} else {
5815255Sstephh 					lp = lp->next;
5825255Sstephh 					while (lp != *list &&
5835255Sstephh 					    np->max_pct < lp->max_pct) {
5845255Sstephh 						lp = lp->next;
5855255Sstephh 					}
5865255Sstephh 					np->next = lp;
5875255Sstephh 					np->prev = lp->prev;
5885255Sstephh 					lp->prev->next = np;
5895255Sstephh 					lp->prev = np;
5905255Sstephh 				}
5915255Sstephh 			} else {
5925255Sstephh 				*list = np;
5935255Sstephh 				np->next = np;
5945255Sstephh 				np->prev = np;
5955255Sstephh 				rt = np;
5965255Sstephh 			}
5975255Sstephh 		}
5985255Sstephh 		np = sp;
5995255Sstephh 	}
6005255Sstephh 	return (rt);
6015255Sstephh }
6025255Sstephh 
6035255Sstephh static name_list_t *
6045255Sstephh alloc_name_list(char *name, uint8_t pct)
6055255Sstephh {
6065255Sstephh 	name_list_t *nlp;
6075255Sstephh 
6085255Sstephh 	nlp = malloc(sizeof (*nlp));
6095255Sstephh 	nlp->name = strdup(name);
6105255Sstephh 	nlp->pct = pct;
6115255Sstephh 	nlp->max_pct = pct;
6125255Sstephh 	nlp->count = 1;
6135255Sstephh 	nlp->next = nlp;
6145255Sstephh 	nlp->prev = nlp;
6155255Sstephh 	nlp->status = 0;
6166002Sstephh 	nlp->label = NULL;
6175255Sstephh 	return (nlp);
6185255Sstephh }
6195255Sstephh 
6205255Sstephh static status_record_t *
6215255Sstephh new_record_init(uurec_t *uurec_p, char *msgid, name_list_t *class,
6225255Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
6239501SRobert.Johnston@Sun.COM     name_list_t *serial, boolean_t not_suppressed,
624*10928SStephen.Hanson@Sun.COM     hostid_t *hostid, boolean_t injected)
6255255Sstephh {
6265255Sstephh 	status_record_t *status_rec_p;
6275255Sstephh 
6285255Sstephh 	status_rec_p = (status_record_t *)malloc(sizeof (status_record_t));
6295255Sstephh 	status_rec_p->nrecs = 1;
6305255Sstephh 	status_rec_p->host = hostid;
6315255Sstephh 	status_rec_p->uurec = uurec_p;
6325255Sstephh 	uurec_p->next = NULL;
6335255Sstephh 	uurec_p->prev = NULL;
6345255Sstephh 	uurec_p->asru = asru;
6359501SRobert.Johnston@Sun.COM 	if ((status_rec_p->severity = fmd_msg_getitem_id(fmadm_msghdl, NULL,
6369501SRobert.Johnston@Sun.COM 	    msgid, FMD_MSG_ITEM_SEVERITY)) == NULL)
6379501SRobert.Johnston@Sun.COM 		status_rec_p->severity = strdup("unknown");
6385255Sstephh 	status_rec_p->class = class;
6395255Sstephh 	status_rec_p->fru = fru;
6405255Sstephh 	status_rec_p->asru = asru;
6415255Sstephh 	status_rec_p->resource = resource;
6425255Sstephh 	status_rec_p->serial = serial;
6435255Sstephh 	status_rec_p->msgid = strdup(msgid);
6445255Sstephh 	status_rec_p->not_suppressed = not_suppressed;
645*10928SStephen.Hanson@Sun.COM 	status_rec_p->injected = injected;
6465255Sstephh 	return (status_rec_p);
6475255Sstephh }
6485255Sstephh 
6495255Sstephh /*
6505255Sstephh  * add record to given list maintaining order higher priority first.
6515255Sstephh  */
6525255Sstephh static void
6535255Sstephh add_rec_list(status_record_t *status_rec_p, sr_list_t **list_pp)
6545255Sstephh {
6555255Sstephh 	sr_list_t *tp, *np, *sp;
6565255Sstephh 	int order;
6575255Sstephh 	uint64_t sec;
6585255Sstephh 
6595255Sstephh 	np = malloc(sizeof (sr_list_t));
6605255Sstephh 	np->status_record = status_rec_p;
6615255Sstephh 	sec = status_rec_p->uurec->sec;
6625255Sstephh 	if ((sp = *list_pp) == NULL) {
6635255Sstephh 		*list_pp = np;
6645255Sstephh 		np->next = np;
6655255Sstephh 		np->prev = np;
6665255Sstephh 	} else {
6675255Sstephh 		/* insert new record in front of lower priority */
6685255Sstephh 		tp = sp;
6695255Sstephh 		order = cmp_priority(status_rec_p->severity,
6705255Sstephh 		    sp->status_record->severity, sec,
6715255Sstephh 		    tp->status_record->uurec->sec, 0, 0);
6725255Sstephh 		if (order > 0) {
6735255Sstephh 			*list_pp = np;
6745255Sstephh 		} else {
6755255Sstephh 			tp = sp->next;
6765255Sstephh 			while (tp != sp &&
6775255Sstephh 			    cmp_priority(status_rec_p->severity,
6785255Sstephh 			    tp->status_record->severity, sec,
6795255Sstephh 			    tp->status_record->uurec->sec, 0, 0)) {
6805255Sstephh 				tp = tp->next;
6815255Sstephh 			}
6825255Sstephh 		}
6835255Sstephh 		np->next = tp;
6845255Sstephh 		np->prev = tp->prev;
6855255Sstephh 		tp->prev->next = np;
6865255Sstephh 		tp->prev = np;
6875255Sstephh 	}
6885255Sstephh }
6895255Sstephh 
6905255Sstephh static void
6915255Sstephh add_resource(status_record_t *status_rec_p, resource_list_t **rp,
6925255Sstephh     resource_list_t *np)
6935255Sstephh {
6945255Sstephh 	int order;
6955255Sstephh 	uint64_t sec;
6965255Sstephh 	resource_list_t *sp, *tp;
6975255Sstephh 	status_record_t *srp;
6985255Sstephh 	char *severity = status_rec_p->severity;
6995255Sstephh 
7005255Sstephh 	add_rec_list(status_rec_p, &np->status_rec_list);
7015255Sstephh 	if ((sp = *rp) == NULL) {
7025255Sstephh 		np->next = np;
7035255Sstephh 		np->prev = np;
7045255Sstephh 		*rp = np;
7055255Sstephh 	} else {
7065255Sstephh 		/*
7075255Sstephh 		 * insert new record in front of lower priority
7085255Sstephh 		 */
7095255Sstephh 		tp = sp->next;
7105255Sstephh 		srp = sp->status_rec_list->status_record;
7115255Sstephh 		sec = status_rec_p->uurec->sec;
7125255Sstephh 		order = cmp_priority(severity, srp->severity, sec,
7135255Sstephh 		    srp->uurec->sec, np->max_pct, sp->max_pct);
7145255Sstephh 		if (order > 0) {
7155255Sstephh 			*rp = np;
7165255Sstephh 		} else {
7175255Sstephh 			srp = tp->status_rec_list->status_record;
7185255Sstephh 			while (tp != sp &&
7195255Sstephh 			    cmp_priority(severity, srp->severity, sec,
7205255Sstephh 			    srp->uurec->sec, np->max_pct, sp->max_pct) < 0) {
7215255Sstephh 				tp = tp->next;
7225255Sstephh 				srp = tp->status_rec_list->status_record;
7235255Sstephh 			}
7245255Sstephh 		}
7255255Sstephh 		np->next = tp;
7265255Sstephh 		np->prev = tp->prev;
7275255Sstephh 		tp->prev->next = np;
7285255Sstephh 		tp->prev = np;
7295255Sstephh 	}
7305255Sstephh }
7315255Sstephh 
7325255Sstephh static void
7335255Sstephh add_resource_list(status_record_t *status_rec_p, name_list_t *fp,
7345255Sstephh     resource_list_t **rpp)
7355255Sstephh {
7365255Sstephh 	int order;
7375255Sstephh 	resource_list_t *np, *end;
7385255Sstephh 	status_record_t *srp;
7395255Sstephh 
7405255Sstephh 	np = *rpp;
7415255Sstephh 	end = np;
7425255Sstephh 	while (np) {
7435255Sstephh 		if (strcmp(fp->name, np->resource) == 0) {
7445255Sstephh 			np->not_suppressed |= status_rec_p->not_suppressed;
745*10928SStephen.Hanson@Sun.COM 			np->injected |= status_rec_p->injected;
7465255Sstephh 			srp = np->status_rec_list->status_record;
7475255Sstephh 			order = cmp_priority(status_rec_p->severity,
7485255Sstephh 			    srp->severity, status_rec_p->uurec->sec,
7495255Sstephh 			    srp->uurec->sec, fp->max_pct, np->max_pct);
7505255Sstephh 			if (order > 0 && np != end) {
7515255Sstephh 				/*
7525255Sstephh 				 * remove from list and add again using
7535255Sstephh 				 * new priority
7545255Sstephh 				 */
7555255Sstephh 				np->prev->next = np->next;
7565255Sstephh 				np->next->prev = np->prev;
7575255Sstephh 				add_resource(status_rec_p,
7585255Sstephh 				    rpp, np);
7595255Sstephh 			} else {
7605255Sstephh 				add_rec_list(status_rec_p,
7615255Sstephh 				    &np->status_rec_list);
7625255Sstephh 			}
7635255Sstephh 			break;
7645255Sstephh 		}
7655255Sstephh 		np = np->next;
7665255Sstephh 		if (np == end) {
7675255Sstephh 			np = NULL;
7685255Sstephh 			break;
7695255Sstephh 		}
7705255Sstephh 	}
7715255Sstephh 	if (np == NULL) {
7725255Sstephh 		np = malloc(sizeof (resource_list_t));
7735255Sstephh 		np->resource = fp->name;
7745255Sstephh 		np->not_suppressed = status_rec_p->not_suppressed;
775*10928SStephen.Hanson@Sun.COM 		np->injected = status_rec_p->injected;
7765255Sstephh 		np->status_rec_list = NULL;
7775255Sstephh 		np->max_pct = fp->max_pct;
7785255Sstephh 		add_resource(status_rec_p, rpp, np);
7790Sstevel@tonic-gate 	}
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate 
7825255Sstephh static void
7835255Sstephh add_list(status_record_t *status_rec_p, name_list_t *listp,
7845255Sstephh     resource_list_t **glistp)
7855255Sstephh {
7865255Sstephh 	name_list_t *fp, *end;
7875255Sstephh 
7885255Sstephh 	fp = listp;
7895255Sstephh 	end = fp;
7905255Sstephh 	while (fp) {
7915255Sstephh 		add_resource_list(status_rec_p, fp, glistp);
7925255Sstephh 		fp = fp->next;
7935255Sstephh 		if (fp == end)
7945255Sstephh 			break;
7955255Sstephh 	}
7965255Sstephh }
7975255Sstephh 
7985255Sstephh /*
7995255Sstephh  * add record to rec, fru and asru lists.
8005255Sstephh  */
8015255Sstephh static void
8025255Sstephh catalog_new_record(uurec_t *uurec_p, char *msgid, name_list_t *class,
8035255Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
8049501SRobert.Johnston@Sun.COM     name_list_t *serial, boolean_t not_suppressed,
805*10928SStephen.Hanson@Sun.COM     hostid_t *hostid, boolean_t injected)
8065255Sstephh {
8075255Sstephh 	status_record_t *status_rec_p;
8085255Sstephh 
8095255Sstephh 	status_rec_p = new_record_init(uurec_p, msgid, class, fru, asru,
810*10928SStephen.Hanson@Sun.COM 	    resource, serial, not_suppressed, hostid, injected);
8115255Sstephh 	add_rec_list(status_rec_p, &status_rec_list);
8125255Sstephh 	if (status_rec_p->fru)
8135255Sstephh 		add_list(status_rec_p, status_rec_p->fru, &status_fru_list);
8145255Sstephh 	if (status_rec_p->asru)
8155255Sstephh 		add_list(status_rec_p, status_rec_p->asru, &status_asru_list);
8165255Sstephh }
8175255Sstephh 
8185255Sstephh static void
8195255Sstephh get_serial_no(nvlist_t *nvl, name_list_t **serial_p, uint8_t pct)
8205255Sstephh {
8215255Sstephh 	char *name;
8225255Sstephh 	char *serial = NULL;
8235255Sstephh 	char **lserial = NULL;
8245255Sstephh 	uint64_t serint;
8255255Sstephh 	name_list_t *nlp;
8265255Sstephh 	int j;
8275255Sstephh 	uint_t nelem;
8285255Sstephh 	char buf[64];
8290Sstevel@tonic-gate 
8305255Sstephh 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) == 0) {
8315255Sstephh 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
8325255Sstephh 			if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
8335255Sstephh 			    &serint) == 0) {
8345255Sstephh 				(void) snprintf(buf, sizeof (buf), "%llX",
8355255Sstephh 				    serint);
8365255Sstephh 				nlp = alloc_name_list(buf, pct);
8375255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
8385255Sstephh 			}
8395255Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
8405255Sstephh 			if (nvlist_lookup_string_array(nvl,
8415255Sstephh 			    FM_FMRI_MEM_SERIAL_ID, &lserial, &nelem) == 0) {
8425255Sstephh 				nlp = alloc_name_list(lserial[0], pct);
8435255Sstephh 				for (j = 1; j < nelem; j++) {
8445255Sstephh 					name_list_t *n1lp;
8455255Sstephh 					n1lp = alloc_name_list(lserial[j], pct);
8465255Sstephh 					(void) merge_name_list(&nlp, n1lp, 1);
8475255Sstephh 				}
8485255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
8495255Sstephh 			}
8505255Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_HC) == 0) {
8515255Sstephh 			if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID,
8525255Sstephh 			    &serial) == 0) {
8535255Sstephh 				nlp = alloc_name_list(serial, pct);
8545255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
8555255Sstephh 			}
8565255Sstephh 		}
8575255Sstephh 	}
8585255Sstephh }
8595255Sstephh 
8605255Sstephh static void
8615255Sstephh extract_record_info(nvlist_t *nvl, name_list_t **class_p,
8625255Sstephh     name_list_t **fru_p, name_list_t **serial_p,
8635255Sstephh     name_list_t **resource_p, name_list_t **asru_p, uint8_t status)
8640Sstevel@tonic-gate {
8655255Sstephh 	nvlist_t *lfru, *lasru, *rsrc;
8665255Sstephh 	name_list_t *nlp;
8675255Sstephh 	char *name;
8685255Sstephh 	uint8_t lpct = 0;
8695255Sstephh 	char *lclass = NULL;
8706002Sstephh 	char *label;
8715255Sstephh 
8725255Sstephh 	(void) nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &lpct);
8735255Sstephh 	if (nvlist_lookup_string(nvl, FM_CLASS, &lclass) == 0) {
8745255Sstephh 		nlp = alloc_name_list(lclass, lpct);
8755255Sstephh 		(void) merge_name_list(class_p, nlp, 1);
8765255Sstephh 	}
8775255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &lfru) == 0) {
8785255Sstephh 		name = get_nvl2str_topo(lfru);
8795255Sstephh 		if (name != NULL) {
8805255Sstephh 			nlp = alloc_name_list(name, lpct);
8817275Sstephh 			nlp->status = status & ~(FM_SUSPECT_UNUSABLE |
8827275Sstephh 			    FM_SUSPECT_DEGRADED);
8835255Sstephh 			free(name);
8846002Sstephh 			if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION,
8856002Sstephh 			    &label) == 0)
8866002Sstephh 				nlp->label = strdup(label);
8875255Sstephh 			(void) merge_name_list(fru_p, nlp, 1);
8885255Sstephh 		}
8895255Sstephh 		get_serial_no(lfru, serial_p, lpct);
89010656SStephen.Hanson@Sun.COM 	} else if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) != 0) {
89110656SStephen.Hanson@Sun.COM 		/*
89210656SStephen.Hanson@Sun.COM 		 * No FRU or resource. But we want to display the repair status
89310656SStephen.Hanson@Sun.COM 		 * somehow, so create a dummy FRU field.
89410656SStephen.Hanson@Sun.COM 		 */
89510656SStephen.Hanson@Sun.COM 		nlp = alloc_name_list(dgettext("FMD", "None"), lpct);
89610656SStephen.Hanson@Sun.COM 		nlp->status = status & ~(FM_SUSPECT_UNUSABLE |
89710656SStephen.Hanson@Sun.COM 		    FM_SUSPECT_DEGRADED);
89810656SStephen.Hanson@Sun.COM 		(void) merge_name_list(fru_p, nlp, 1);
8995255Sstephh 	}
9005255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &lasru) == 0) {
9015255Sstephh 		name = get_nvl2str_topo(lasru);
9025255Sstephh 		if (name != NULL) {
9035255Sstephh 			nlp = alloc_name_list(name, lpct);
9047275Sstephh 			nlp->status = status & ~(FM_SUSPECT_NOT_PRESENT |
9057275Sstephh 			    FM_SUSPECT_REPAIRED | FM_SUSPECT_REPLACED |
9067275Sstephh 			    FM_SUSPECT_ACQUITTED);
9075255Sstephh 			free(name);
9085255Sstephh 			(void) merge_name_list(asru_p, nlp, 1);
9095255Sstephh 		}
9105255Sstephh 		get_serial_no(lasru, serial_p, lpct);
9115255Sstephh 	}
9125255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
9135255Sstephh 		name = get_nvl2str_topo(rsrc);
9145255Sstephh 		if (name != NULL) {
9155255Sstephh 			nlp = alloc_name_list(name, lpct);
9166228Sstephh 			nlp->status = status;
9175255Sstephh 			free(name);
9188245SStephen.Hanson@Sun.COM 			if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION,
9198245SStephen.Hanson@Sun.COM 			    &label) == 0)
9208245SStephen.Hanson@Sun.COM 				nlp->label = strdup(label);
9215255Sstephh 			(void) merge_name_list(resource_p, nlp, 1);
9225255Sstephh 		}
9235255Sstephh 	}
9245255Sstephh }
9255255Sstephh 
9265255Sstephh static void
9279501SRobert.Johnston@Sun.COM add_fault_record_to_catalog(nvlist_t *nvl, uint64_t sec, char *uuid)
9285255Sstephh {
9295255Sstephh 	char *msgid = "-";
9305255Sstephh 	uint_t i, size = 0;
9315255Sstephh 	name_list_t *class = NULL, *resource = NULL;
9325255Sstephh 	name_list_t *asru = NULL, *fru = NULL, *serial = NULL;
9335255Sstephh 	nvlist_t **nva;
9345255Sstephh 	uint8_t *ba;
9355255Sstephh 	uurec_t *uurec_p;
9365255Sstephh 	hostid_t *host;
9375255Sstephh 	boolean_t not_suppressed = 1;
9385255Sstephh 	boolean_t any_present = 0;
939*10928SStephen.Hanson@Sun.COM 	boolean_t injected = 0;
9405255Sstephh 
9415255Sstephh 	(void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &msgid);
9425255Sstephh 	(void) nvlist_lookup_uint32(nvl, FM_SUSPECT_FAULT_SZ, &size);
9435255Sstephh 	(void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_MESSAGE,
9445255Sstephh 	    &not_suppressed);
945*10928SStephen.Hanson@Sun.COM 	(void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED, &injected);
9465255Sstephh 
9475255Sstephh 	if (size != 0) {
9485255Sstephh 		(void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
9495255Sstephh 		    &nva, &size);
9505255Sstephh 		(void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS,
9515255Sstephh 		    &ba, &size);
9525255Sstephh 		for (i = 0; i < size; i++) {
9535255Sstephh 			extract_record_info(nva[i], &class, &fru, &serial,
9545255Sstephh 			    &resource, &asru, ba[i]);
9555255Sstephh 			if (!(ba[i] & FM_SUSPECT_NOT_PRESENT) &&
9565255Sstephh 			    (ba[i] & FM_SUSPECT_FAULTY))
9575255Sstephh 				any_present = 1;
9585255Sstephh 		}
9595255Sstephh 		/*
9605255Sstephh 		 * also suppress if no resources present
9615255Sstephh 		 */
9625255Sstephh 		if (any_present == 0)
9635255Sstephh 			not_suppressed = 0;
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate 
9665255Sstephh 	uurec_p = (uurec_t *)malloc(sizeof (uurec_t));
9675255Sstephh 	uurec_p->uuid = strdup(uuid);
9685255Sstephh 	uurec_p->sec = sec;
9695255Sstephh 	uurec_p->ari_uuid_list = NULL;
97010234SRobert.Johnston@Sun.COM 	uurec_p->event = NULL;
97110234SRobert.Johnston@Sun.COM 	(void) nvlist_dup(nvl, &uurec_p->event, 0);
9725255Sstephh 	host = find_hostid(nvl);
97310656SStephen.Hanson@Sun.COM 	catalog_new_record(uurec_p, msgid, class, fru, asru,
974*10928SStephen.Hanson@Sun.COM 	    resource, serial, not_suppressed, host, injected);
9755255Sstephh }
9765255Sstephh 
9775255Sstephh static void
9785255Sstephh update_asru_state_in_catalog(const char *uuid, const char *ari_uuid)
9795255Sstephh {
9805255Sstephh 	sr_list_t *srp;
9815255Sstephh 	uurec_t *uurp;
9825255Sstephh 	ari_list_t *ari_list;
9835255Sstephh 
9845255Sstephh 	srp = status_rec_list;
9855255Sstephh 	if (srp) {
9865255Sstephh 		for (;;) {
9875255Sstephh 			uurp = srp->status_record->uurec;
9885255Sstephh 			while (uurp) {
9895255Sstephh 				if (strcmp(uuid, uurp->uuid) == 0) {
9905255Sstephh 					ari_list = (ari_list_t *)
9915255Sstephh 					    malloc(sizeof (ari_list_t));
9925255Sstephh 					ari_list->ari_uuid = strdup(ari_uuid);
9935255Sstephh 					ari_list->next = uurp->ari_uuid_list;
9945255Sstephh 					uurp->ari_uuid_list = ari_list;
9955255Sstephh 					return;
9965255Sstephh 				}
9975255Sstephh 				uurp = uurp->next;
9985255Sstephh 			}
9995255Sstephh 			if (srp->next == status_rec_list)
10005255Sstephh 				break;
10015255Sstephh 			srp = srp->next;
10025255Sstephh 		}
10035255Sstephh 	}
10045255Sstephh }
10055255Sstephh 
10065255Sstephh static void
10075255Sstephh print_line(char *label, char *buf)
10085255Sstephh {
10095255Sstephh 	char *cp, *ep, *wp;
10105255Sstephh 	char c;
10115255Sstephh 	int i;
10125255Sstephh 	int lsz;
10135255Sstephh 	char *padding;
10145255Sstephh 
10155255Sstephh 	lsz = strlen(label);
10165255Sstephh 	padding = malloc(lsz + 1);
10175255Sstephh 	for (i = 0; i < lsz; i++)
10185255Sstephh 		padding[i] = ' ';
10195255Sstephh 	padding[i] = 0;
10205255Sstephh 	cp = buf;
10215255Sstephh 	ep = buf;
10225255Sstephh 	c = *ep;
10235255Sstephh 	(void) printf("\n");
10245255Sstephh 	while (c) {
10255255Sstephh 		i = lsz;
10265255Sstephh 		wp = NULL;
10275255Sstephh 		while ((c = *ep) != NULL && (wp == NULL || i < 80)) {
10285255Sstephh 			if (c == ' ')
10295255Sstephh 				wp = ep;
10305255Sstephh 			else if (c == '\n') {
10315255Sstephh 				i = 0;
10325255Sstephh 				*ep = 0;
10335255Sstephh 				do {
10345255Sstephh 					ep++;
10355255Sstephh 				} while ((c = *ep) != NULL && c == ' ');
10365255Sstephh 				break;
10375255Sstephh 			}
10385255Sstephh 			ep++;
10395255Sstephh 			i++;
10405255Sstephh 		}
10415255Sstephh 		if (i >= 80 && wp) {
10425255Sstephh 			*wp = 0;
10435255Sstephh 			ep = wp + 1;
10445255Sstephh 			c = *ep;
10455255Sstephh 		}
10465255Sstephh 		(void) printf("%s%s\n", label, cp);
10475255Sstephh 		cp = ep;
10485255Sstephh 		label = padding;
10495255Sstephh 	}
10505255Sstephh 	free(padding);
10515255Sstephh }
10525255Sstephh 
10535255Sstephh static void
105410234SRobert.Johnston@Sun.COM print_dict_info_line(nvlist_t *e, fmd_msg_item_t what, const char *linehdr)
10555255Sstephh {
105610234SRobert.Johnston@Sun.COM 	char *cp = fmd_msg_getitem_nv(fmadm_msghdl, NULL, e, what);
10575255Sstephh 
10585255Sstephh 	if (cp) {
10599501SRobert.Johnston@Sun.COM 		print_line(dgettext("FMD", linehdr), cp);
10609501SRobert.Johnston@Sun.COM 		free(cp);
10615255Sstephh 	}
10629501SRobert.Johnston@Sun.COM }
10639501SRobert.Johnston@Sun.COM 
10649501SRobert.Johnston@Sun.COM static void
106510234SRobert.Johnston@Sun.COM print_dict_info(nvlist_t *nvl)
10669501SRobert.Johnston@Sun.COM {
106710234SRobert.Johnston@Sun.COM 	print_dict_info_line(nvl, FMD_MSG_ITEM_DESC, "Description : ");
106810234SRobert.Johnston@Sun.COM 	print_dict_info_line(nvl, FMD_MSG_ITEM_RESPONSE, "Response    : ");
106910234SRobert.Johnston@Sun.COM 	print_dict_info_line(nvl, FMD_MSG_ITEM_IMPACT, "Impact      : ");
107010234SRobert.Johnston@Sun.COM 	print_dict_info_line(nvl, FMD_MSG_ITEM_ACTION, "Action      : ");
10715255Sstephh }
10725255Sstephh 
10735255Sstephh static void
10745255Sstephh print_name(name_list_t *list, char *(func)(char *), char *padding, int *np,
10755255Sstephh     int pct, int full)
10765255Sstephh {
10778245SStephen.Hanson@Sun.COM 	char *name, *fru_label = NULL;
10785255Sstephh 
10795255Sstephh 	name = list->name;
10808245SStephen.Hanson@Sun.COM 	if (list->label) {
10818245SStephen.Hanson@Sun.COM 		(void) printf("%s \"%s\" (%s)", padding, list->label, name);
10825255Sstephh 		*np += 1;
10838245SStephen.Hanson@Sun.COM 	} else if (func && (fru_label = func(list->name)) != NULL) {
10848245SStephen.Hanson@Sun.COM 		(void) printf("%s \"%s\" (%s)", padding, fru_label, name);
10858245SStephen.Hanson@Sun.COM 		*np += 1;
10868245SStephen.Hanson@Sun.COM 		free(fru_label);
10875255Sstephh 	} else {
10885255Sstephh 		(void) printf("%s %s", padding, name);
10895255Sstephh 		*np += 1;
10905255Sstephh 	}
10915255Sstephh 	if (list->pct && pct > 0 && pct < 100) {
10925255Sstephh 		if (list->count > 1) {
10935255Sstephh 			if (full) {
10945255Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
10955255Sstephh 				    dgettext("FMD", "max"),
10965255Sstephh 				    list->max_pct);
10975255Sstephh 			} else {
10985255Sstephh 				(void) printf(" %s %d%%\n",
10995255Sstephh 				    dgettext("FMD", "max"),
11005255Sstephh 				    list->max_pct);
11015255Sstephh 			}
11025255Sstephh 		} else {
11035255Sstephh 			(void) printf(" %d%%\n", list->pct);
11045255Sstephh 		}
11055255Sstephh 	} else {
11065255Sstephh 		(void) printf("\n");
11075255Sstephh 	}
11085255Sstephh }
11095255Sstephh 
11105255Sstephh static void
11115255Sstephh print_asru_status(int status, char *label)
11125255Sstephh {
11135255Sstephh 	char *msg = NULL;
11145255Sstephh 
11155255Sstephh 	switch (status) {
11165255Sstephh 	case 0:
11175255Sstephh 		msg = dgettext("FMD", "ok and in service");
11185255Sstephh 		break;
11197275Sstephh 	case FM_SUSPECT_DEGRADED:
11207275Sstephh 		msg = dgettext("FMD", "service degraded, "
11217275Sstephh 		    "but associated components no longer faulty");
11227275Sstephh 		break;
11237275Sstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED:
11247275Sstephh 		msg = dgettext("FMD", "faulted but still "
11257275Sstephh 		    "providing degraded service");
11267275Sstephh 		break;
11275255Sstephh 	case FM_SUSPECT_FAULTY:
11287275Sstephh 		msg = dgettext("FMD", "faulted but still in service");
11295255Sstephh 		break;
11305255Sstephh 	case FM_SUSPECT_UNUSABLE:
11317275Sstephh 		msg = dgettext("FMD", "out of service, "
11327275Sstephh 		    "but associated components no longer faulty");
11335255Sstephh 		break;
11345255Sstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
11355255Sstephh 		msg = dgettext("FMD", "faulted and taken out of service");
11365255Sstephh 		break;
11375255Sstephh 	default:
11385255Sstephh 		break;
11395255Sstephh 	}
11405255Sstephh 	if (msg) {
11415255Sstephh 		(void) printf("%s     %s\n", label, msg);
11425255Sstephh 	}
11435255Sstephh }
11445255Sstephh 
11455255Sstephh static void
11466228Sstephh print_fru_status(int status, char *label)
11476228Sstephh {
11486228Sstephh 	char *msg = NULL;
11496228Sstephh 
11506228Sstephh 	if (status & FM_SUSPECT_NOT_PRESENT)
11516228Sstephh 		msg = dgettext("FMD", "not present");
11526228Sstephh 	else if (status & FM_SUSPECT_FAULTY)
11536228Sstephh 		msg = dgettext("FMD", "faulty");
11547275Sstephh 	else if (status & FM_SUSPECT_REPLACED)
11557275Sstephh 		msg = dgettext("FMD", "replaced");
11567275Sstephh 	else if (status & FM_SUSPECT_REPAIRED)
11577275Sstephh 		msg = dgettext("FMD", "repair attempted");
11587275Sstephh 	else if (status & FM_SUSPECT_ACQUITTED)
11597275Sstephh 		msg = dgettext("FMD", "acquitted");
11606228Sstephh 	else
11617275Sstephh 		msg = dgettext("FMD", "removed");
11626228Sstephh 	(void) printf("%s     %s\n", label, msg);
11636228Sstephh }
11646228Sstephh 
11656228Sstephh static void
11669120SStephen.Hanson@Sun.COM print_rsrc_status(int status, char *label)
11679120SStephen.Hanson@Sun.COM {
11689120SStephen.Hanson@Sun.COM 	char *msg = "";
11699120SStephen.Hanson@Sun.COM 
11709120SStephen.Hanson@Sun.COM 	if (status & FM_SUSPECT_NOT_PRESENT)
11719120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "not present");
11729120SStephen.Hanson@Sun.COM 	else if (status & FM_SUSPECT_FAULTY) {
11739120SStephen.Hanson@Sun.COM 		if (status & FM_SUSPECT_DEGRADED)
11749120SStephen.Hanson@Sun.COM 			msg = dgettext("FMD",
11759120SStephen.Hanson@Sun.COM 			    "faulted but still providing degraded service");
11769120SStephen.Hanson@Sun.COM 		else if (status & FM_SUSPECT_UNUSABLE)
11779120SStephen.Hanson@Sun.COM 			msg = dgettext("FMD",
11789120SStephen.Hanson@Sun.COM 			    "faulted and taken out of service");
11799120SStephen.Hanson@Sun.COM 		else
11809120SStephen.Hanson@Sun.COM 			msg = dgettext("FMD", "faulted but still in service");
11819120SStephen.Hanson@Sun.COM 	} else if (status & FM_SUSPECT_REPLACED)
11829120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "replaced");
11839120SStephen.Hanson@Sun.COM 	else if (status & FM_SUSPECT_REPAIRED)
11849120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "repair attempted");
11859120SStephen.Hanson@Sun.COM 	else if (status & FM_SUSPECT_ACQUITTED)
11869120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "acquitted");
11879120SStephen.Hanson@Sun.COM 	else
11889120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "removed");
11899120SStephen.Hanson@Sun.COM 	(void) printf("%s     %s\n", label, msg);
11909120SStephen.Hanson@Sun.COM }
11919120SStephen.Hanson@Sun.COM 
11929120SStephen.Hanson@Sun.COM static void
11935255Sstephh print_name_list(name_list_t *list, char *label, char *(func)(char *),
11945255Sstephh     int limit, int pct, void (func1)(int, char *), int full)
11955255Sstephh {
11968245SStephen.Hanson@Sun.COM 	char *name, *fru_label = NULL;
11975255Sstephh 	char *padding;
11985255Sstephh 	int i, j, l, n;
11995255Sstephh 	name_list_t *end = list;
12005255Sstephh 
12015255Sstephh 	l = strlen(label);
12025255Sstephh 	padding = malloc(l + 1);
12035255Sstephh 	for (i = 0; i < l; i++)
12045255Sstephh 		padding[i] = ' ';
12055255Sstephh 	padding[l] = 0;
12065255Sstephh 	(void) printf("%s", label);
12075255Sstephh 	name = list->name;
12088245SStephen.Hanson@Sun.COM 	if (list->label)
12096002Sstephh 		(void) printf(" \"%s\" (%s)", list->label, name);
12108245SStephen.Hanson@Sun.COM 	else if (func && (fru_label = func(list->name)) != NULL) {
12118245SStephen.Hanson@Sun.COM 		(void) printf(" \"%s\" (%s)", fru_label, name);
12128245SStephen.Hanson@Sun.COM 		free(fru_label);
12138245SStephen.Hanson@Sun.COM 	} else
12148245SStephen.Hanson@Sun.COM 		(void) printf(" %s", name);
12155255Sstephh 	if (list->pct && pct > 0 && pct < 100) {
12165255Sstephh 		if (list->count > 1) {
12175255Sstephh 			if (full) {
12185255Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
12195255Sstephh 				    dgettext("FMD", "max"), list->max_pct);
12205255Sstephh 			} else {
12215255Sstephh 				(void) printf(" %s %d%%\n",
12225255Sstephh 				    dgettext("FMD", "max"), list->max_pct);
12235255Sstephh 			}
12245255Sstephh 		} else {
12255255Sstephh 			(void) printf(" %d%%\n", list->pct);
12265255Sstephh 		}
12275255Sstephh 	} else {
12285255Sstephh 		(void) printf("\n");
12295255Sstephh 	}
12305255Sstephh 	if (func1)
12315255Sstephh 		func1(list->status, padding);
12325255Sstephh 	n = 1;
12335255Sstephh 	j = 0;
12345255Sstephh 	while ((list = list->next) != end) {
12355255Sstephh 		if (limit == 0 || n < limit) {
12365255Sstephh 			print_name(list, func, padding, &n, pct, full);
12375255Sstephh 			if (func1)
12385255Sstephh 				func1(list->status, padding);
12395255Sstephh 		} else
12405255Sstephh 			j++;
12415255Sstephh 	}
12425255Sstephh 	if (j == 1) {
12435255Sstephh 		print_name(list->prev, func, padding, &n, pct, full);
12445255Sstephh 	} else if (j > 1) {
12455255Sstephh 		(void) printf("%s... %d %s\n", padding, j,
12465255Sstephh 		    dgettext("FMD", "more entries suppressed,"
12475255Sstephh 		    " use -v option for full list"));
12485255Sstephh 	}
12495255Sstephh 	free(padding);
12505255Sstephh }
12515255Sstephh 
12525255Sstephh static int
12535255Sstephh asru_same_status(name_list_t *list)
12545255Sstephh {
12555255Sstephh 	name_list_t *end = list;
12565255Sstephh 	int status = list->status;
12575255Sstephh 
12585255Sstephh 	while ((list = list->next) != end) {
12595255Sstephh 		if (status == -1) {
12605255Sstephh 			status = list->status;
12615255Sstephh 			continue;
12625255Sstephh 		}
12635255Sstephh 		if (list->status != -1 && status != list->status) {
12645255Sstephh 			status = -1;
12655255Sstephh 			break;
12665255Sstephh 		}
12675255Sstephh 	}
12685255Sstephh 	return (status);
12695255Sstephh }
12705255Sstephh 
12715255Sstephh static int
12725255Sstephh serial_in_fru(name_list_t *fru, name_list_t *serial)
12735255Sstephh {
12745255Sstephh 	name_list_t *sp = serial;
12755255Sstephh 	name_list_t *fp;
12765255Sstephh 	int nserial = 0;
12775255Sstephh 	int found = 0;
12785255Sstephh 	char buf[128];
12795255Sstephh 
12805255Sstephh 	while (sp) {
12815255Sstephh 		fp = fru;
12825255Sstephh 		nserial++;
12835255Sstephh 		(void) snprintf(buf, sizeof (buf), "serial=%s", sp->name);
12845255Sstephh 		buf[sizeof (buf) - 1] = 0;
12855255Sstephh 		while (fp) {
12865255Sstephh 			if (strstr(fp->name, buf) != NULL) {
12875255Sstephh 				found++;
12885255Sstephh 				break;
12895255Sstephh 			}
12905255Sstephh 			fp = fp->next;
12915255Sstephh 			if (fp == fru)
12925255Sstephh 				break;
12935255Sstephh 		}
12945255Sstephh 		sp = sp->next;
12955255Sstephh 		if (sp == serial)
12965255Sstephh 			break;
12975255Sstephh 	}
12985255Sstephh 	return (found == nserial ? 1 : 0);
12995255Sstephh }
13005255Sstephh 
13015255Sstephh static void
13025255Sstephh print_sup_record(status_record_t *srp, int opt_i, int full)
13035255Sstephh {
13045255Sstephh 	char buf[32];
13055255Sstephh 	uurec_t *uurp = srp->uurec;
13065255Sstephh 	int n, j, k, max;
13075255Sstephh 	int status;
13085255Sstephh 	ari_list_t *ari_list;
13095255Sstephh 
13105255Sstephh 	n = 0;
13115255Sstephh 	max = max_fault;
13125255Sstephh 	if (max < 0) {
13135255Sstephh 		max = 0;
13145255Sstephh 	}
13155255Sstephh 	j = max / 2;
13165255Sstephh 	max -= j;
13175255Sstephh 	k = srp->nrecs - max;
13185255Sstephh 	while ((uurp = uurp->next) != NULL) {
13195255Sstephh 		if (full || n < j || n >= k || max_fault == 0 ||
13205255Sstephh 		    srp->nrecs == max_fault+1) {
13215255Sstephh 			if (opt_i) {
13225255Sstephh 				ari_list = uurp->ari_uuid_list;
13235255Sstephh 				while (ari_list) {
13245255Sstephh 					(void) printf("%-15s %s\n",
13255255Sstephh 					    format_date(buf, sizeof (buf),
13265255Sstephh 					    uurp->sec), ari_list->ari_uuid);
13275255Sstephh 					ari_list = ari_list->next;
13285255Sstephh 				}
13295255Sstephh 			} else {
13305255Sstephh 				(void) printf("%-15s %s\n",
13315255Sstephh 				    format_date(buf, sizeof (buf), uurp->sec),
13325255Sstephh 				    uurp->uuid);
13335255Sstephh 			}
13345255Sstephh 		} else if (n == j)
13355255Sstephh 			(void) printf("... %d %s\n", srp->nrecs - max_fault,
13365255Sstephh 			    dgettext("FMD", "more entries suppressed"));
13375255Sstephh 		n++;
13385255Sstephh 	}
13395255Sstephh 	(void) printf("\n");
13409120SStephen.Hanson@Sun.COM 	(void) printf("%s %s", dgettext("FMD", "Host        :"),
13419120SStephen.Hanson@Sun.COM 	    srp->host->server);
13429120SStephen.Hanson@Sun.COM 	if (srp->host->domain)
13439120SStephen.Hanson@Sun.COM 		(void) printf("\t%s %s", dgettext("FMD", "Domain      :"),
13449120SStephen.Hanson@Sun.COM 		    srp->host->domain);
13459120SStephen.Hanson@Sun.COM 	(void) printf("\n%s %s", dgettext("FMD", "Platform    :"),
13469120SStephen.Hanson@Sun.COM 	    srp->host->platform);
134710462SSean.Ye@Sun.COM 	(void) printf("\t%s %s", dgettext("FMD", "Chassis_id  :"),
13489120SStephen.Hanson@Sun.COM 	    srp->host->chassis ? srp->host->chassis : "");
134910462SSean.Ye@Sun.COM 	(void) printf("\n%s %s\n\n", dgettext("FMD", "Product_sn  :"),
135010462SSean.Ye@Sun.COM 	    srp->host->product_sn? srp->host->product_sn : "");
13515255Sstephh 	if (srp->class)
13525255Sstephh 		print_name_list(srp->class,
13535255Sstephh 		    dgettext("FMD", "Fault class :"), NULL, 0, srp->class->pct,
13545255Sstephh 		    NULL, full);
13555255Sstephh 	if (srp->asru) {
13565255Sstephh 		status = asru_same_status(srp->asru);
13575255Sstephh 		if (status != -1) {
13585255Sstephh 			print_name_list(srp->asru,
13595255Sstephh 			    dgettext("FMD", "Affects     :"), NULL,
13605255Sstephh 			    full ? 0 : max_display, 0, NULL, full);
13615255Sstephh 			print_asru_status(status, "             ");
13625255Sstephh 		} else
13635255Sstephh 			print_name_list(srp->asru,
13645255Sstephh 			    dgettext("FMD", "Affects     :"), NULL,
13655255Sstephh 			    full ? 0 : max_display, 0, print_asru_status, full);
13665255Sstephh 	}
13679120SStephen.Hanson@Sun.COM 	if (full || srp->fru == NULL || srp->asru == NULL) {
13685255Sstephh 		if (srp->resource) {
136910656SStephen.Hanson@Sun.COM 			status = asru_same_status(srp->resource);
137010656SStephen.Hanson@Sun.COM 			if (status != -1) {
137110656SStephen.Hanson@Sun.COM 				print_name_list(srp->resource,
137210656SStephen.Hanson@Sun.COM 				    dgettext("FMD", "Problem in  :"), NULL,
137310656SStephen.Hanson@Sun.COM 				    full ? 0 : max_display, 0, NULL, full);
137410656SStephen.Hanson@Sun.COM 				print_rsrc_status(status, "             ");
137510656SStephen.Hanson@Sun.COM 			} else
137610656SStephen.Hanson@Sun.COM 				print_name_list(srp->resource,
137710656SStephen.Hanson@Sun.COM 				    dgettext("FMD", "Problem in  :"),
137810656SStephen.Hanson@Sun.COM 				    NULL, full ? 0 : max_display, 0,
137910656SStephen.Hanson@Sun.COM 				    print_rsrc_status, full);
13805255Sstephh 		}
13815255Sstephh 	}
13825255Sstephh 	if (srp->fru) {
13836228Sstephh 		status = asru_same_status(srp->fru);
13846228Sstephh 		if (status != -1) {
13856228Sstephh 			print_name_list(srp->fru, dgettext("FMD",
13866228Sstephh 			    "FRU         :"), get_fmri_label, 0,
13876228Sstephh 			    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
13886228Sstephh 			    NULL, full);
13896228Sstephh 			print_fru_status(status, "             ");
13906228Sstephh 		} else
13916228Sstephh 			print_name_list(srp->fru, dgettext("FMD",
13926228Sstephh 			    "FRU         :"), get_fmri_label, 0,
13936228Sstephh 			    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
13946228Sstephh 			    print_fru_status, full);
13955255Sstephh 	}
13965255Sstephh 	if (srp->serial && !serial_in_fru(srp->fru, srp->serial) &&
13975255Sstephh 	    !serial_in_fru(srp->asru, srp->serial)) {
13985255Sstephh 		print_name_list(srp->serial, dgettext("FMD", "Serial ID.  :"),
13995255Sstephh 		    NULL, 0, 0, NULL, full);
14005255Sstephh 	}
140110234SRobert.Johnston@Sun.COM 	print_dict_info(srp->uurec->event);
14025255Sstephh 	(void) printf("\n");
14035255Sstephh }
14045255Sstephh 
14055255Sstephh static void
14065255Sstephh print_status_record(status_record_t *srp, int summary, int opt_i, int full)
14075255Sstephh {
14085255Sstephh 	char buf[32];
14095255Sstephh 	uurec_t *uurp = srp->uurec;
14105255Sstephh 	static int header = 0;
14115255Sstephh 	char *head;
14125255Sstephh 	ari_list_t *ari_list;
14135255Sstephh 
14145255Sstephh 	if (!summary || !header) {
14155255Sstephh 		if (opt_i) {
14165255Sstephh 			head = "--------------- "
14175255Sstephh 			    "------------------------------------  "
14185255Sstephh 			    "-------------- ---------\n"
14195255Sstephh 			    "TIME            CACHE-ID"
14205255Sstephh 			    "                              MSG-ID"
14215255Sstephh 			    "         SEVERITY\n--------------- "
14225255Sstephh 			    "------------------------------------ "
14235255Sstephh 			    " -------------- ---------";
14245255Sstephh 		} else {
14255255Sstephh 			head = "--------------- "
14265255Sstephh 			    "------------------------------------  "
14275255Sstephh 			    "-------------- ---------\n"
14285255Sstephh 			    "TIME            EVENT-ID"
14295255Sstephh 			    "                              MSG-ID"
14305255Sstephh 			    "         SEVERITY\n--------------- "
14315255Sstephh 			    "------------------------------------ "
14325255Sstephh 			    " -------------- ---------";
14335255Sstephh 		}
14345255Sstephh 		(void) printf("%s\n", dgettext("FMD", head));
14355255Sstephh 		header = 1;
14365255Sstephh 	}
14375255Sstephh 	if (opt_i) {
14385255Sstephh 		ari_list = uurp->ari_uuid_list;
14395255Sstephh 		while (ari_list) {
1440*10928SStephen.Hanson@Sun.COM 			(void) printf("%-15s %-37s %-14s %-9s %s\n",
14415255Sstephh 			    format_date(buf, sizeof (buf), uurp->sec),
1442*10928SStephen.Hanson@Sun.COM 			    ari_list->ari_uuid, srp->msgid, srp->severity,
1443*10928SStephen.Hanson@Sun.COM 			    srp->injected ? dgettext("FMD", "injected") : "");
14445255Sstephh 			ari_list = ari_list->next;
14455255Sstephh 		}
14465255Sstephh 	} else {
1447*10928SStephen.Hanson@Sun.COM 		(void) printf("%-15s %-37s %-14s %-9s %s\n",
14485255Sstephh 		    format_date(buf, sizeof (buf), uurp->sec),
1449*10928SStephen.Hanson@Sun.COM 		    uurp->uuid, srp->msgid, srp->severity,
1450*10928SStephen.Hanson@Sun.COM 		    srp->injected ? dgettext("FMD", "injected") : "");
14515255Sstephh 	}
14525255Sstephh 
14535255Sstephh 	if (!summary)
14545255Sstephh 		print_sup_record(srp, opt_i, full);
14555255Sstephh }
14565255Sstephh 
14575255Sstephh static void
14585255Sstephh print_catalog(int summary, int opt_a, int full, int opt_i, int page_feed)
14595255Sstephh {
14605255Sstephh 	status_record_t *srp;
14615255Sstephh 	sr_list_t *slp;
14625255Sstephh 
14635255Sstephh 	slp = status_rec_list;
14645255Sstephh 	if (slp) {
14655255Sstephh 		for (;;) {
14665255Sstephh 			srp = slp->status_record;
14675255Sstephh 			if (opt_a || srp->not_suppressed) {
14685255Sstephh 				if (page_feed)
14695255Sstephh 					(void) printf("\f\n");
14705255Sstephh 				print_status_record(srp, summary, opt_i, full);
14715255Sstephh 			}
14725255Sstephh 			if (slp->next == status_rec_list)
14735255Sstephh 				break;
14745255Sstephh 			slp = slp->next;
14755255Sstephh 		}
14765255Sstephh 	}
14775255Sstephh }
14785255Sstephh 
14795255Sstephh static name_list_t *
14805255Sstephh find_fru(status_record_t *srp, char *resource)
14815255Sstephh {
14825255Sstephh 	name_list_t *rt = NULL;
14835255Sstephh 	name_list_t *fru = srp->fru;
14845255Sstephh 
14855255Sstephh 	while (fru) {
14865255Sstephh 		if (strcmp(resource, fru->name) == 0) {
14875255Sstephh 			rt = fru;
14885255Sstephh 			break;
14895255Sstephh 		}
14905255Sstephh 		fru = fru->next;
14915255Sstephh 		if (fru == srp->fru)
14925255Sstephh 			break;
14935255Sstephh 	}
14945255Sstephh 	return (rt);
14955255Sstephh }
14965255Sstephh 
14975255Sstephh static void
14985255Sstephh print_fru_line(name_list_t *fru, char *uuid)
14995255Sstephh {
15005255Sstephh 	if (fru->pct == 100) {
15015255Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
15025255Sstephh 		    dgettext("FMD", "suspects in this FRU total certainty"),
15035255Sstephh 		    100);
15045255Sstephh 	} else {
15055255Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
15065255Sstephh 		    dgettext("FMD", "suspects in this FRU max certainty"),
15075255Sstephh 		    fru->max_pct);
15085255Sstephh 	}
15095255Sstephh }
15105255Sstephh 
15115255Sstephh static void
15125255Sstephh print_fru(int summary, int opt_a, int opt_i, int page_feed)
15135255Sstephh {
15145255Sstephh 	resource_list_t *tp = status_fru_list;
15155255Sstephh 	status_record_t *srp;
15165255Sstephh 	sr_list_t *slp, *end;
15175255Sstephh 	char *msgid, *fru_label;
15185255Sstephh 	uurec_t *uurp;
15195255Sstephh 	name_list_t *fru;
15206228Sstephh 	int status;
15215255Sstephh 	ari_list_t *ari_list;
15225255Sstephh 
15235255Sstephh 	while (tp) {
15245255Sstephh 		if (opt_a || tp->not_suppressed) {
15255255Sstephh 			if (page_feed)
15265255Sstephh 				(void) printf("\f\n");
15275255Sstephh 			if (!summary)
15285255Sstephh 				(void) printf("-----------------------------"
15295255Sstephh 				    "---------------------------------------"
15305255Sstephh 				    "----------\n");
15316002Sstephh 			slp = tp->status_rec_list;
15326002Sstephh 			end = slp;
15336002Sstephh 			do {
15346002Sstephh 				srp = slp->status_record;
15356002Sstephh 				fru = find_fru(srp, tp->resource);
15366002Sstephh 				if (fru) {
15376002Sstephh 					if (fru->label)
15386228Sstephh 						(void) printf("\"%s\" (%s) ",
15396002Sstephh 						    fru->label, fru->name);
15406228Sstephh 					else if ((fru_label = get_fmri_label(
15416228Sstephh 					    fru->name)) != NULL) {
15426228Sstephh 						(void) printf("\"%s\" (%s) ",
15436002Sstephh 						    fru_label, fru->name);
15446002Sstephh 						free(fru_label);
15456002Sstephh 					} else
15466228Sstephh 						(void) printf("%s ",
15476002Sstephh 						    fru->name);
15486002Sstephh 					break;
15496002Sstephh 				}
15506002Sstephh 				slp = slp->next;
15516002Sstephh 			} while (slp != end);
15526002Sstephh 
15535255Sstephh 			slp = tp->status_rec_list;
15545255Sstephh 			end = slp;
15556228Sstephh 			status = 0;
15566228Sstephh 			do {
15576228Sstephh 				srp = slp->status_record;
15586228Sstephh 				fru = srp->fru;
15596228Sstephh 				while (fru) {
15606228Sstephh 					if (strcmp(tp->resource,
15616228Sstephh 					    fru->name) == 0)
15626228Sstephh 						status |= fru->status;
15636228Sstephh 					fru = fru->next;
15646228Sstephh 					if (fru == srp->fru)
15656228Sstephh 						break;
15666228Sstephh 				}
15676228Sstephh 				slp = slp->next;
15686228Sstephh 			} while (slp != end);
15696228Sstephh 			if (status & FM_SUSPECT_NOT_PRESENT)
1570*10928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "not present"));
15716228Sstephh 			else if (status & FM_SUSPECT_FAULTY)
1572*10928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "faulty"));
15737275Sstephh 			else if (status & FM_SUSPECT_REPLACED)
1574*10928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "replaced"));
15757275Sstephh 			else if (status & FM_SUSPECT_REPAIRED)
15767275Sstephh 				(void) printf(dgettext("FMD",
1577*10928SStephen.Hanson@Sun.COM 				    "repair attempted"));
15787275Sstephh 			else if (status & FM_SUSPECT_ACQUITTED)
1579*10928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "acquitted"));
15806228Sstephh 			else
1581*10928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "removed"));
1582*10928SStephen.Hanson@Sun.COM 
1583*10928SStephen.Hanson@Sun.COM 			if (tp->injected)
1584*10928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", " injected\n"));
1585*10928SStephen.Hanson@Sun.COM 			else
1586*10928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "\n"));
15876228Sstephh 
15886228Sstephh 			slp = tp->status_rec_list;
15896228Sstephh 			end = slp;
15905255Sstephh 			do {
15915255Sstephh 				srp = slp->status_record;
15925255Sstephh 				uurp = srp->uurec;
15935255Sstephh 				fru = find_fru(srp, tp->resource);
15945255Sstephh 				if (fru) {
15955255Sstephh 					if (opt_i) {
15965255Sstephh 						ari_list = uurp->ari_uuid_list;
15975255Sstephh 						while (ari_list) {
15985255Sstephh 							print_fru_line(fru,
15995255Sstephh 							    ari_list->ari_uuid);
16005255Sstephh 							ari_list =
16015255Sstephh 							    ari_list->next;
16025255Sstephh 						}
16035255Sstephh 					} else {
16045255Sstephh 						print_fru_line(fru, uurp->uuid);
16055255Sstephh 					}
16065255Sstephh 				}
16075255Sstephh 				slp = slp->next;
16085255Sstephh 			} while (slp != end);
16095255Sstephh 			if (!summary) {
16105255Sstephh 				slp = tp->status_rec_list;
16115255Sstephh 				end = slp;
16125255Sstephh 				srp = slp->status_record;
16135255Sstephh 				if (srp->serial &&
16145255Sstephh 				    !serial_in_fru(srp->fru, srp->serial)) {
16155255Sstephh 					print_name_list(srp->serial,
16165255Sstephh 					    dgettext("FMD", "Serial ID.  :"),
16175255Sstephh 					    NULL, 0, 0, NULL, 1);
16185255Sstephh 				}
16195255Sstephh 				msgid = NULL;
16205255Sstephh 				do {
16215255Sstephh 					if (msgid == NULL ||
16225255Sstephh 					    strcmp(msgid, srp->msgid) != 0) {
16235255Sstephh 						msgid = srp->msgid;
162410234SRobert.Johnston@Sun.COM 						print_dict_info(uurp->event);
16255255Sstephh 					}
16265255Sstephh 					slp = slp->next;
16275255Sstephh 				} while (slp != end);
16285255Sstephh 			}
16295255Sstephh 		}
16305255Sstephh 		tp = tp->next;
16315255Sstephh 		if (tp == status_fru_list)
16325255Sstephh 			break;
16335255Sstephh 	}
16345255Sstephh }
16355255Sstephh 
16365255Sstephh static void
16375255Sstephh print_asru(int opt_a)
16385255Sstephh {
16395255Sstephh 	resource_list_t *tp = status_asru_list;
16405255Sstephh 	status_record_t *srp;
16415255Sstephh 	sr_list_t *slp, *end;
16425255Sstephh 	char *msg;
16435255Sstephh 	int status;
16445255Sstephh 	name_list_t *asru;
16455255Sstephh 
16465255Sstephh 	while (tp) {
16475255Sstephh 		if (opt_a || tp->not_suppressed) {
16485255Sstephh 			status = 0;
16495255Sstephh 			slp = tp->status_rec_list;
16505255Sstephh 			end = slp;
16515255Sstephh 			do {
16525255Sstephh 				srp = slp->status_record;
16535255Sstephh 				asru = srp->asru;
16545255Sstephh 				while (asru) {
16555255Sstephh 					if (strcmp(tp->resource,
16565255Sstephh 					    asru->name) == 0)
16575255Sstephh 						status |= asru->status;
16585255Sstephh 					asru = asru->next;
16595255Sstephh 					if (asru == srp->asru)
16605255Sstephh 						break;
16615255Sstephh 				}
16625255Sstephh 				slp = slp->next;
16635255Sstephh 			} while (slp != end);
16645255Sstephh 			switch (status) {
16655255Sstephh 			case 0:
16665255Sstephh 				msg = dgettext("FMD", "ok");
16675255Sstephh 				break;
16687275Sstephh 			case FM_SUSPECT_DEGRADED:
16697275Sstephh 				msg = dgettext("FMD", "degraded");
16707275Sstephh 				break;
16717275Sstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED:
16727275Sstephh 				msg = dgettext("FMD", "degraded");
16737275Sstephh 				break;
16745255Sstephh 			case FM_SUSPECT_FAULTY:
16755255Sstephh 				msg = dgettext("FMD", "degraded");
16765255Sstephh 				break;
16775255Sstephh 			case FM_SUSPECT_UNUSABLE:
16785255Sstephh 				msg = dgettext("FMD", "unknown");
16795255Sstephh 				break;
16805255Sstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
16815255Sstephh 				msg = dgettext("FMD", "faulted");
16825255Sstephh 				break;
16835255Sstephh 			default:
16845255Sstephh 				msg = "";
16855255Sstephh 				break;
16865255Sstephh 			}
1687*10928SStephen.Hanson@Sun.COM 			(void) printf("%-69s %s", tp->resource, msg);
1688*10928SStephen.Hanson@Sun.COM 			if (tp->injected)
1689*10928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", " injected\n"));
1690*10928SStephen.Hanson@Sun.COM 			else
1691*10928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "\n"));
16925255Sstephh 		}
16935255Sstephh 		tp = tp->next;
16945255Sstephh 		if (tp == status_asru_list)
16955255Sstephh 			break;
16965255Sstephh 	}
16975255Sstephh }
16985255Sstephh 
16995255Sstephh static int
17005255Sstephh uuid_in_list(char *uuid, uurec_select_t *uurecp)
17015255Sstephh {
17025255Sstephh 	while (uurecp) {
17035255Sstephh 		if (strcmp(uuid, uurecp->uuid) == 0)
17045255Sstephh 			return (1);
17055255Sstephh 		uurecp = uurecp->next;
17065255Sstephh 	}
17070Sstevel@tonic-gate 	return (0);
17080Sstevel@tonic-gate }
17090Sstevel@tonic-gate 
17105255Sstephh static int
17115255Sstephh dfault_rec(const fmd_adm_caseinfo_t *acp, void *arg)
17125255Sstephh {
17135255Sstephh 	int64_t *diag_time;
17145255Sstephh 	uint_t nelem;
17155255Sstephh 	int rt = 0;
17165255Sstephh 	char *uuid = "-";
17175255Sstephh 	uurec_select_t *uurecp = (uurec_select_t *)arg;
17185255Sstephh 
17195255Sstephh 	if (nvlist_lookup_int64_array(acp->aci_event, FM_SUSPECT_DIAG_TIME,
17205255Sstephh 	    &diag_time, &nelem) == 0 && nelem >= 2) {
17215255Sstephh 		(void) nvlist_lookup_string(acp->aci_event, FM_SUSPECT_UUID,
17225255Sstephh 		    &uuid);
17235255Sstephh 		if (uurecp == NULL || uuid_in_list(uuid, uurecp))
17245255Sstephh 			add_fault_record_to_catalog(acp->aci_event, *diag_time,
17259501SRobert.Johnston@Sun.COM 			    uuid);
17265255Sstephh 	} else {
17275255Sstephh 		rt = -1;
17285255Sstephh 	}
17295255Sstephh 	return (rt);
17305255Sstephh }
17315255Sstephh 
17320Sstevel@tonic-gate /*ARGSUSED*/
17330Sstevel@tonic-gate static int
17345255Sstephh dstatus_rec(const fmd_adm_rsrcinfo_t *ari, void *unused)
17350Sstevel@tonic-gate {
17365255Sstephh 	update_asru_state_in_catalog(ari->ari_case, ari->ari_uuid);
17370Sstevel@tonic-gate 	return (0);
17380Sstevel@tonic-gate }
17390Sstevel@tonic-gate 
17405255Sstephh static int
17415255Sstephh get_cases_from_fmd(fmd_adm_t *adm, uurec_select_t *uurecp, int opt_i)
17425255Sstephh {
17435255Sstephh 	int rt = FMADM_EXIT_SUCCESS;
17445255Sstephh 
17455255Sstephh 	/*
174610234SRobert.Johnston@Sun.COM 	 * These calls may fail with Protocol error if message payload is
174710234SRobert.Johnston@Sun.COM 	 * too big
17485255Sstephh 	 */
17495255Sstephh 	if (fmd_adm_case_iter(adm, NULL, dfault_rec, uurecp) != 0)
17505255Sstephh 		die("failed to get case list from fmd");
17515255Sstephh 	if (opt_i && fmd_adm_rsrc_iter(adm, 1, dstatus_rec, NULL) != 0)
17525255Sstephh 		die("failed to get case status from fmd");
17535255Sstephh 	return (rt);
17545255Sstephh }
17555255Sstephh 
17565255Sstephh /*
17575255Sstephh  * fmadm faulty command
17585255Sstephh  *
17595255Sstephh  *	-a		show hidden fault records
17605255Sstephh  *	-f		show faulty fru's
17615255Sstephh  *	-g		force grouping of similar faults on the same fru
17625255Sstephh  *	-n		number of fault records to display
17635255Sstephh  *	-p		pipe output through pager
17645255Sstephh  *	-r		show faulty asru's
17655255Sstephh  *	-s		print summary of first fault
17665255Sstephh  *	-u		print listed uuid's only
17675255Sstephh  *	-v		full output
17685255Sstephh  */
17695255Sstephh 
17700Sstevel@tonic-gate int
17710Sstevel@tonic-gate cmd_faulty(fmd_adm_t *adm, int argc, char *argv[])
17720Sstevel@tonic-gate {
17735255Sstephh 	int opt_a = 0, opt_v = 0, opt_p = 0, opt_s = 0, opt_r = 0, opt_f = 0;
17745255Sstephh 	int opt_i = 0;
17755255Sstephh 	char *pager;
17765255Sstephh 	FILE *fp;
17775255Sstephh 	int rt, c, stat;
17785255Sstephh 	uurec_select_t *tp;
17795255Sstephh 	uurec_select_t *uurecp = NULL;
17800Sstevel@tonic-gate 
17815255Sstephh 	while ((c = getopt(argc, argv, "afgin:prsu:v")) != EOF) {
17820Sstevel@tonic-gate 		switch (c) {
17830Sstevel@tonic-gate 		case 'a':
17840Sstevel@tonic-gate 			opt_a++;
17850Sstevel@tonic-gate 			break;
17865255Sstephh 		case 'f':
17875255Sstephh 			opt_f++;
17885255Sstephh 			break;
17895255Sstephh 		case 'g':
17905255Sstephh 			opt_g++;
17915255Sstephh 			break;
17920Sstevel@tonic-gate 		case 'i':
17935255Sstephh 			opt_i++;
17945255Sstephh 			break;
17955255Sstephh 		case 'n':
17965255Sstephh 			max_fault = atoi(optarg);
17975255Sstephh 			break;
17985255Sstephh 		case 'p':
17995255Sstephh 			opt_p++;
18005255Sstephh 			break;
18015255Sstephh 		case 'r':
18025255Sstephh 			opt_r++;
18035255Sstephh 			break;
18045255Sstephh 		case 's':
18055255Sstephh 			opt_s++;
18065255Sstephh 			break;
18075255Sstephh 		case 'u':
18085255Sstephh 			tp = (uurec_select_t *)malloc(sizeof (uurec_select_t));
18095255Sstephh 			tp->uuid = optarg;
18105255Sstephh 			tp->next = uurecp;
18115255Sstephh 			uurecp = tp;
18125255Sstephh 			opt_a = 1;
18135255Sstephh 			break;
18145255Sstephh 		case 'v':
18155255Sstephh 			opt_v++;
18160Sstevel@tonic-gate 			break;
18170Sstevel@tonic-gate 		default:
18180Sstevel@tonic-gate 			return (FMADM_EXIT_USAGE);
18190Sstevel@tonic-gate 		}
18200Sstevel@tonic-gate 	}
18210Sstevel@tonic-gate 	if (optind < argc)
18220Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
18230Sstevel@tonic-gate 
18249501SRobert.Johnston@Sun.COM 	if ((fmadm_msghdl = fmd_msg_init(NULL, FMD_MSG_VERSION)) == NULL)
18259501SRobert.Johnston@Sun.COM 		return (FMADM_EXIT_ERROR);
18265255Sstephh 	rt = get_cases_from_fmd(adm, uurecp, opt_i);
18275255Sstephh 	if (opt_p) {
18285255Sstephh 		if ((pager = getenv("PAGER")) == NULL)
18295255Sstephh 			pager = "/usr/bin/more";
18305255Sstephh 		fp = popen(pager, "w");
18315255Sstephh 		if (fp == NULL) {
18325255Sstephh 			rt = FMADM_EXIT_ERROR;
18335255Sstephh 			opt_p = 0;
18345255Sstephh 		} else {
18355255Sstephh 			dup2(fileno(fp), 1);
18365255Sstephh 			setbuf(stdout, NULL);
18375255Sstephh 			(void) fclose(fp);
18385255Sstephh 		}
18395255Sstephh 	}
18405255Sstephh 	max_display = max_fault;
18415255Sstephh 	if (opt_f)
18425255Sstephh 		print_fru(opt_s, opt_a, opt_i, opt_p && !opt_s);
18435255Sstephh 	if (opt_r)
18445255Sstephh 		print_asru(opt_a);
18455255Sstephh 	if (opt_f == 0 && opt_r == 0)
18465255Sstephh 		print_catalog(opt_s, opt_a, opt_v, opt_i, opt_p && !opt_s);
18479501SRobert.Johnston@Sun.COM 	fmd_msg_fini(fmadm_msghdl);
18485255Sstephh 	label_release_topo();
18495255Sstephh 	if (opt_p) {
18505255Sstephh 		(void) fclose(stdout);
18515255Sstephh 		(void) wait(&stat);
18525255Sstephh 	}
18535255Sstephh 	return (rt);
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate int
18570Sstevel@tonic-gate cmd_flush(fmd_adm_t *adm, int argc, char *argv[])
18580Sstevel@tonic-gate {
18590Sstevel@tonic-gate 	int i, status = FMADM_EXIT_SUCCESS;
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	if (argc < 2 || (i = getopt(argc, argv, "")) != EOF)
18620Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
18630Sstevel@tonic-gate 
18640Sstevel@tonic-gate 	for (i = 1; i < argc; i++) {
18650Sstevel@tonic-gate 		if (fmd_adm_rsrc_flush(adm, argv[i]) != 0) {
18660Sstevel@tonic-gate 			warn("failed to flush %s", argv[i]);
18670Sstevel@tonic-gate 			status = FMADM_EXIT_ERROR;
18680Sstevel@tonic-gate 		} else
18690Sstevel@tonic-gate 			note("flushed resource history for %s\n", argv[i]);
18700Sstevel@tonic-gate 	}
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate 	return (status);
18730Sstevel@tonic-gate }
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate int
18760Sstevel@tonic-gate cmd_repair(fmd_adm_t *adm, int argc, char *argv[])
18770Sstevel@tonic-gate {
18780Sstevel@tonic-gate 	int err;
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 	if (getopt(argc, argv, "") != EOF)
18810Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 	if (argc - optind != 1)
18840Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 	/*
18877275Sstephh 	 * argument could be a uuid, an fmri (asru, fru or resource)
18886228Sstephh 	 * or a label. Try uuid first, If that fails try the others.
18890Sstevel@tonic-gate 	 */
18906228Sstephh 	err = fmd_adm_case_repair(adm, argv[optind]);
18916228Sstephh 	if (err != 0)
18927275Sstephh 		err = fmd_adm_rsrc_repaired(adm, argv[optind]);
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate 	if (err != 0)
18950Sstevel@tonic-gate 		die("failed to record repair to %s", argv[optind]);
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate 	note("recorded repair to %s\n", argv[optind]);
18980Sstevel@tonic-gate 	return (FMADM_EXIT_SUCCESS);
18990Sstevel@tonic-gate }
19007275Sstephh 
19017275Sstephh int
19027275Sstephh cmd_repaired(fmd_adm_t *adm, int argc, char *argv[])
19037275Sstephh {
19047275Sstephh 	int err;
19057275Sstephh 
19067275Sstephh 	if (getopt(argc, argv, "") != EOF)
19077275Sstephh 		return (FMADM_EXIT_USAGE);
19087275Sstephh 
19097275Sstephh 	if (argc - optind != 1)
19107275Sstephh 		return (FMADM_EXIT_USAGE);
19117275Sstephh 
19127275Sstephh 	/*
19137275Sstephh 	 * argument could be an fmri (asru, fru or resource) or a label.
19147275Sstephh 	 */
19157275Sstephh 	err = fmd_adm_rsrc_repaired(adm, argv[optind]);
19167275Sstephh 	if (err != 0)
19177275Sstephh 		die("failed to record repair to %s", argv[optind]);
19187275Sstephh 
19197275Sstephh 	note("recorded repair to of %s\n", argv[optind]);
19207275Sstephh 	return (FMADM_EXIT_SUCCESS);
19217275Sstephh }
19227275Sstephh 
19237275Sstephh int
19247275Sstephh cmd_replaced(fmd_adm_t *adm, int argc, char *argv[])
19257275Sstephh {
19267275Sstephh 	int err;
19277275Sstephh 
19287275Sstephh 	if (getopt(argc, argv, "") != EOF)
19297275Sstephh 		return (FMADM_EXIT_USAGE);
19307275Sstephh 
19317275Sstephh 	if (argc - optind != 1)
19327275Sstephh 		return (FMADM_EXIT_USAGE);
19337275Sstephh 
19347275Sstephh 	/*
19357275Sstephh 	 * argument could be an fmri (asru, fru or resource) or a label.
19367275Sstephh 	 */
19377275Sstephh 	err = fmd_adm_rsrc_replaced(adm, argv[optind]);
19387275Sstephh 	if (err != 0)
19397275Sstephh 		die("failed to record replacement of %s", argv[optind]);
19407275Sstephh 
19417275Sstephh 	note("recorded replacement of %s\n", argv[optind]);
19427275Sstephh 	return (FMADM_EXIT_SUCCESS);
19437275Sstephh }
19447275Sstephh 
19457275Sstephh int
19467275Sstephh cmd_acquit(fmd_adm_t *adm, int argc, char *argv[])
19477275Sstephh {
19487275Sstephh 	int err;
19497275Sstephh 
19507275Sstephh 	if (getopt(argc, argv, "") != EOF)
19517275Sstephh 		return (FMADM_EXIT_USAGE);
19527275Sstephh 
19537275Sstephh 	if (argc - optind != 1 && argc - optind != 2)
19547275Sstephh 		return (FMADM_EXIT_USAGE);
19557275Sstephh 
19567275Sstephh 	/*
19577275Sstephh 	 * argument could be a uuid, an fmri (asru, fru or resource)
19587275Sstephh 	 * or a label. Or it could be a uuid and an fmri or label.
19597275Sstephh 	 */
19607275Sstephh 	if (argc - optind == 2) {
19617275Sstephh 		err = fmd_adm_rsrc_acquit(adm, argv[optind], argv[optind + 1]);
19627275Sstephh 		if (err != 0)
19637275Sstephh 			err = fmd_adm_rsrc_acquit(adm, argv[optind + 1],
19647275Sstephh 			    argv[optind]);
19657275Sstephh 	} else {
19667275Sstephh 		err = fmd_adm_case_acquit(adm, argv[optind]);
19677275Sstephh 		if (err != 0)
19687275Sstephh 			err = fmd_adm_rsrc_acquit(adm, argv[optind], "");
19697275Sstephh 	}
19707275Sstephh 
19717275Sstephh 	if (err != 0)
19727275Sstephh 		die("failed to record acquital of %s", argv[optind]);
19737275Sstephh 
19747275Sstephh 	note("recorded acquital of %s\n", argv[optind]);
19757275Sstephh 	return (FMADM_EXIT_SUCCESS);
19767275Sstephh }
1977