xref: /onnv-gate/usr/src/cmd/fm/fmadm/common/faulty.c (revision 12618:0e5eaf4bf546)
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 /*
22*12618SStephen.Hanson@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
255255Sstephh #include <sys/types.h>
265255Sstephh #include <fmadm.h>
275255Sstephh #include <errno.h>
285255Sstephh #include <limits.h>
290Sstevel@tonic-gate #include <strings.h>
305255Sstephh #include <stdio.h>
315255Sstephh #include <unistd.h>
325255Sstephh #include <sys/wait.h>
335255Sstephh #include <sys/stat.h>
345255Sstephh #include <fcntl.h>
355255Sstephh #include <fm/fmd_log.h>
365255Sstephh #include <sys/fm/protocol.h>
375255Sstephh #include <fm/libtopo.h>
385255Sstephh #include <fm/fmd_adm.h>
399501SRobert.Johnston@Sun.COM #include <fm/fmd_msg.h>
405255Sstephh #include <dlfcn.h>
415255Sstephh #include <sys/systeminfo.h>
425255Sstephh #include <sys/utsname.h>
435255Sstephh #include <libintl.h>
445255Sstephh #include <locale.h>
455255Sstephh #include <sys/smbios.h>
465255Sstephh #include <libdevinfo.h>
475255Sstephh #include <stdlib.h>
485255Sstephh 
495255Sstephh #define	offsetof(s, m)	((size_t)(&(((s*)0)->m)))
505255Sstephh 
515255Sstephh /*
525255Sstephh  * Fault records are added to catalog by calling add_fault_record_to_catalog()
535255Sstephh  * records are stored in order of importance to the system.
545255Sstephh  * If -g flag is set or not_suppressed is not set and the class fru, fault,
555255Sstephh  * type are the same then details are merged into an existing record, with uuid
565255Sstephh  * records are stored in time order.
575255Sstephh  * For each record information is extracted from nvlist and merged into linked
585255Sstephh  * list each is checked for identical records for which percentage certainty are
595255Sstephh  * added together.
605255Sstephh  * print_catalog() is called to print out catalog and release external resources
615255Sstephh  *
625255Sstephh  *                         /---------------\
635255Sstephh  *	status_rec_list -> |               | -|
645255Sstephh  *                         \---------------/
655255Sstephh  *                                \/
665255Sstephh  *                         /---------------\    /-------\    /-------\
675255Sstephh  *      status_fru_list    | status_record | -> | uurec | -> | uurec | -|
685255Sstephh  *            \/           |               | |- |       | <- |       |
695255Sstephh  *      /-------------\    |               |    \-------/    \-------/
705255Sstephh  *      |             | -> |               |       \/           \/
715255Sstephh  *      \-------------/    |               |    /-------\    /-------\
725255Sstephh  *            \/           |               | -> | asru  | -> | asru  |
735255Sstephh  *            ---          |               |    |       | <- |       |
745255Sstephh  *                         |               |    \-------/    \-------/
755255Sstephh  *      status_asru_list   |  class        |
765255Sstephh  *            \/           |  resource     |    /-------\    /-------\
775255Sstephh  *      /-------------\    |  fru          | -> | list  | -> | list  |
785255Sstephh  *      |             | -> |  serial       |    |       | <- |       |
795255Sstephh  *      \-------------/    |               |    \-------/    \-------/
805255Sstephh  *            \/           \---------------/
815255Sstephh  *            ---               \/    /\
825255Sstephh  *                         /---------------\
835255Sstephh  *                         | status_record |
845255Sstephh  *                         \---------------/
855255Sstephh  *
865255Sstephh  * Fmadm faulty takes a number of options which affect the format of the
875255Sstephh  * output displayed. By default, the display reports the FRU and ASRU along
885255Sstephh  * with other information on per-case basis as in the example below.
895255Sstephh  *
905255Sstephh  * --------------- ------------------------------------  -------------- -------
915255Sstephh  * TIME            EVENT-ID                              MSG-ID         SEVERITY
925255Sstephh  * --------------- ------------------------------------  -------------- -------
935255Sstephh  * Sep 21 10:01:36 d482f935-5c8f-e9ab-9f25-d0aaafec1e6c  AMD-8000-2F    Major
945255Sstephh  *
955255Sstephh  * Fault class	: fault.memory.dimm_sb
965255Sstephh  * Affects	: mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0
977275Sstephh  *		    faulted but still in service
985255Sstephh  * FRU		: "CPU 0 DIMM 0" (hc://.../memory-controller=0/dimm=0)
995255Sstephh  *		    faulty
1005255Sstephh  *
1015255Sstephh  * Description	: The number of errors associated with this memory module has
1025255Sstephh  *		exceeded acceptable levels.  Refer to
1035255Sstephh  *		http://sun.com/msg/AMD-8000-2F for more information.
1045255Sstephh  *
1055255Sstephh  * Response	: Pages of memory associated with this memory module are being
1065255Sstephh  *		removed from service as errors are reported.
1075255Sstephh  *
1085255Sstephh  * Impact	: Total system memory capacity will be reduced as pages are
1095255Sstephh  *		retired.
1105255Sstephh  *
1115255Sstephh  * Action	: Schedule a repair procedure to replace the affected memory
1125255Sstephh  *		module.  Use fmdump -v -u <EVENT_ID> to identify the module.
1135255Sstephh  *
1145255Sstephh  * The -v flag is similar, but adds some additonal information such as the
1155255Sstephh  * resource. The -s flag is also similar but just gives the top line summary.
1165255Sstephh  * All these options (ie without the -f or -r flags) use the print_catalog()
1175255Sstephh  * function to do the display.
1185255Sstephh  *
1195255Sstephh  * The -f flag changes the output so that it appears sorted on a per-fru basis.
1205255Sstephh  * The output is somewhat cut down compared to the default output. If -f is
1215255Sstephh  * used, then print_fru() is used to print the output.
1225255Sstephh  *
1235255Sstephh  * -----------------------------------------------------------------------------
1245255Sstephh  * "SLOT 2" (hc://.../hostbridge=3/pciexrc=3/pciexbus=4/pciexdev=0) faulty
1255255Sstephh  * 5ca4aeb3-36...f6be-c2e8166dc484 2 suspects in this FRU total certainty 100%
1265255Sstephh  *
1275255Sstephh  * Description	: A problem was detected for a PCI device.
1285255Sstephh  *		Refer to http://sun.com/msg/PCI-8000-7J for more information.
1295255Sstephh  *
1305255Sstephh  * Response	: One or more device instances may be disabled
1315255Sstephh  *
1325255Sstephh  * Impact	: Possible loss of services provided by the device instances
1335255Sstephh  *		associated with this fault
1345255Sstephh  *
1355255Sstephh  * Action	: Schedule a repair procedure to replace the affected device.
1365255Sstephh  * 		Use fmdump -v -u <EVENT_ID> to identify the device or contact
1375255Sstephh  *		Sun for support.
1385255Sstephh  *
1395255Sstephh  * The -r flag changes the output so that it appears sorted on a per-asru basis.
1405255Sstephh  * The output is very much cut down compared to the default output, just giving
1415255Sstephh  * the asru fmri and state. Here print_asru() is used to print the output.
1425255Sstephh  *
1435255Sstephh  * mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0	degraded
1445255Sstephh  *
1455255Sstephh  * For all fmadm faulty options, the sequence of events is
1465255Sstephh  *
1475255Sstephh  * 1) Walk through all the cases in the system using fmd_adm_case_iter() and
1485255Sstephh  * for each case call dfault_rec(). This will call add_fault_record_to_catalog()
1495255Sstephh  * This will extract the data from the nvlist and call catalog_new_record() to
1505255Sstephh  * save the data away in various linked lists in the catalogue.
1515255Sstephh  *
1525255Sstephh  * 2) Once this is done, the data can be supplemented by using
1535255Sstephh  * fmd_adm_rsrc_iter(). However this is now only necessary for the -i option.
1545255Sstephh  *
1555255Sstephh  * 3) Finally print_catalog(), print_fru() or print_asru() are called as
1565255Sstephh  * appropriate to display the information from the catalogue sorted in the
1575255Sstephh  * requested way.
1585255Sstephh  *
1595255Sstephh  */
1605255Sstephh 
1615255Sstephh typedef struct name_list {
1625255Sstephh 	struct name_list *next;
1635255Sstephh 	struct name_list *prev;
1645255Sstephh 	char *name;
1655255Sstephh 	uint8_t pct;
1665255Sstephh 	uint8_t max_pct;
1675255Sstephh 	ushort_t count;
1685255Sstephh 	int status;
1696002Sstephh 	char *label;
1705255Sstephh } name_list_t;
1715255Sstephh 
1725255Sstephh typedef struct ari_list {
1735255Sstephh 	char *ari_uuid;
1745255Sstephh 	struct ari_list *next;
1755255Sstephh } ari_list_t;
1765255Sstephh 
1775255Sstephh typedef struct uurec {
1785255Sstephh 	struct uurec *next;
1795255Sstephh 	struct uurec *prev;
1805255Sstephh 	char *uuid;
1815255Sstephh 	ari_list_t *ari_uuid_list;
1825255Sstephh 	name_list_t *asru;
1835255Sstephh 	uint64_t sec;
18410234SRobert.Johnston@Sun.COM 	nvlist_t *event;
1855255Sstephh } uurec_t;
1865255Sstephh 
1875255Sstephh typedef struct uurec_select {
1885255Sstephh 	struct uurec_select *next;
1895255Sstephh 	char *uuid;
1905255Sstephh } uurec_select_t;
1915255Sstephh 
1925255Sstephh typedef struct host_id {
1935255Sstephh 	char *chassis;
1945255Sstephh 	char *server;
1955255Sstephh 	char *platform;
1969120SStephen.Hanson@Sun.COM 	char *domain;
19710462SSean.Ye@Sun.COM 	char *product_sn;
1985255Sstephh } hostid_t;
1995255Sstephh 
2005255Sstephh typedef struct host_id_list {
2015255Sstephh 	hostid_t hostid;
2025255Sstephh 	struct host_id_list *next;
2035255Sstephh } host_id_list_t;
2045255Sstephh 
2055255Sstephh typedef struct status_record {
2065255Sstephh 	hostid_t *host;
2075255Sstephh 	int nrecs;
2085255Sstephh 	uurec_t *uurec;
2095255Sstephh 	char *severity;			/* in C locale */
2105255Sstephh 	char *msgid;
2115255Sstephh 	name_list_t *class;
2125255Sstephh 	name_list_t *resource;
2135255Sstephh 	name_list_t *asru;
2145255Sstephh 	name_list_t *fru;
2155255Sstephh 	name_list_t *serial;
2165255Sstephh 	uint8_t not_suppressed;
21710928SStephen.Hanson@Sun.COM 	uint8_t injected;
2185255Sstephh } status_record_t;
2195255Sstephh 
2205255Sstephh typedef struct sr_list {
2215255Sstephh 	struct sr_list *next;
2225255Sstephh 	struct sr_list *prev;
2235255Sstephh 	struct status_record *status_record;
2245255Sstephh } sr_list_t;
2255255Sstephh 
2265255Sstephh typedef struct resource_list {
2275255Sstephh 	struct resource_list *next;
2285255Sstephh 	struct resource_list *prev;
2295255Sstephh 	sr_list_t *status_rec_list;
2305255Sstephh 	char *resource;
2315255Sstephh 	uint8_t not_suppressed;
23210928SStephen.Hanson@Sun.COM 	uint8_t injected;
2335255Sstephh 	uint8_t max_pct;
2345255Sstephh } resource_list_t;
2355255Sstephh 
2365255Sstephh sr_list_t *status_rec_list;
2375255Sstephh resource_list_t *status_fru_list;
2385255Sstephh resource_list_t *status_asru_list;
2395255Sstephh 
2405255Sstephh static int max_display;
2415255Sstephh static int max_fault = 0;
2425255Sstephh static topo_hdl_t *topo_handle;
2435255Sstephh static host_id_list_t *host_list;
2445255Sstephh static int n_server;
2455255Sstephh static int opt_g;
2469501SRobert.Johnston@Sun.COM static fmd_msg_hdl_t *fmadm_msghdl = NULL; /* handle for libfmd_msg calls */
2475255Sstephh 
2485255Sstephh static char *
format_date(char * buf,size_t len,uint64_t sec)2495255Sstephh format_date(char *buf, size_t len, uint64_t sec)
2505255Sstephh {
2515255Sstephh 	if (sec > LONG_MAX) {
2525255Sstephh 		(void) fprintf(stderr,
2535255Sstephh 		    "record time is too large for 32-bit utility\n");
2545255Sstephh 		(void) snprintf(buf, len, "0x%llx", sec);
2555255Sstephh 	} else {
2565255Sstephh 		time_t tod = (time_t)sec;
25710928SStephen.Hanson@Sun.COM 		time_t now = time(NULL);
25810928SStephen.Hanson@Sun.COM 		if (tod > now+60 ||
25910928SStephen.Hanson@Sun.COM 		    tod < now - 6L*30L*24L*60L*60L) { /* 6 months ago */
26010928SStephen.Hanson@Sun.COM 			(void) strftime(buf, len, "%b %d %Y    ",
26110928SStephen.Hanson@Sun.COM 			    localtime(&tod));
26210928SStephen.Hanson@Sun.COM 		} else {
26310928SStephen.Hanson@Sun.COM 			(void) strftime(buf, len, "%b %d %T", localtime(&tod));
26410928SStephen.Hanson@Sun.COM 		}
2655255Sstephh 	}
2665255Sstephh 
2675255Sstephh 	return (buf);
2685255Sstephh }
2695255Sstephh 
2705255Sstephh static hostid_t *
find_hostid_in_list(char * platform,char * chassis,char * server,char * domain,char * product_sn)27110462SSean.Ye@Sun.COM find_hostid_in_list(char *platform, char *chassis, char *server, char *domain,
27210462SSean.Ye@Sun.COM     char *product_sn)
2735255Sstephh {
2745255Sstephh 	hostid_t *rt = NULL;
2755255Sstephh 	host_id_list_t *hostp;
2765255Sstephh 
2775255Sstephh 	if (platform == NULL)
2785255Sstephh 		platform = "-";
2795255Sstephh 	if (server == NULL)
2805255Sstephh 		server = "-";
2815255Sstephh 	hostp = host_list;
2825255Sstephh 	while (hostp) {
2835255Sstephh 		if (hostp->hostid.platform &&
2845255Sstephh 		    strcmp(hostp->hostid.platform, platform) == 0 &&
2855255Sstephh 		    hostp->hostid.server &&
2865255Sstephh 		    strcmp(hostp->hostid.server, server) == 0 &&
2875255Sstephh 		    (chassis == NULL || hostp->hostid.chassis == NULL ||
2889120SStephen.Hanson@Sun.COM 		    strcmp(chassis, hostp->hostid.chassis) == 0) &&
28910462SSean.Ye@Sun.COM 		    (product_sn == NULL || hostp->hostid.product_sn == NULL ||
29010462SSean.Ye@Sun.COM 		    strcmp(product_sn, hostp->hostid.product_sn) == 0) &&
2919120SStephen.Hanson@Sun.COM 		    (domain == NULL || hostp->hostid.domain == NULL ||
2929120SStephen.Hanson@Sun.COM 		    strcmp(domain, hostp->hostid.domain) == 0)) {
2935255Sstephh 			rt = &hostp->hostid;
2945255Sstephh 			break;
2955255Sstephh 		}
2965255Sstephh 		hostp = hostp->next;
2975255Sstephh 	}
2985255Sstephh 	if (rt == NULL) {
2995255Sstephh 		hostp = malloc(sizeof (host_id_list_t));
3005255Sstephh 		hostp->hostid.platform = strdup(platform);
30110462SSean.Ye@Sun.COM 		hostp->hostid.product_sn =
30210462SSean.Ye@Sun.COM 		    product_sn ? strdup(product_sn) : NULL;
3035255Sstephh 		hostp->hostid.server = strdup(server);
3045255Sstephh 		hostp->hostid.chassis = chassis ? strdup(chassis) : NULL;
3059120SStephen.Hanson@Sun.COM 		hostp->hostid.domain = domain ? strdup(domain) : NULL;
3065255Sstephh 		hostp->next = host_list;
3075255Sstephh 		host_list = hostp;
3085255Sstephh 		rt = &hostp->hostid;
3095255Sstephh 		n_server++;
3105255Sstephh 	}
3115255Sstephh 	return (rt);
3125255Sstephh }
3135255Sstephh 
3145255Sstephh static hostid_t *
find_hostid(nvlist_t * nvl)3155255Sstephh find_hostid(nvlist_t *nvl)
3165255Sstephh {
3179120SStephen.Hanson@Sun.COM 	char *platform = NULL, *chassis = NULL, *server = NULL, *domain = NULL;
31810462SSean.Ye@Sun.COM 	char *product_sn = NULL;
3195255Sstephh 	nvlist_t *auth, *fmri;
3205255Sstephh 	hostid_t *rt = NULL;
3215255Sstephh 
3225255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &fmri) == 0 &&
3235255Sstephh 	    nvlist_lookup_nvlist(fmri, FM_FMRI_AUTHORITY, &auth) == 0) {
3245255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT,
3255255Sstephh 		    &platform);
32610462SSean.Ye@Sun.COM 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN,
32710462SSean.Ye@Sun.COM 		    &product_sn);
3285255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server);
3295255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS,
3305255Sstephh 		    &chassis);
3319120SStephen.Hanson@Sun.COM 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_DOMAIN, &domain);
33210462SSean.Ye@Sun.COM 		rt = find_hostid_in_list(platform, chassis, server,
33310462SSean.Ye@Sun.COM 		    domain, product_sn);
3345255Sstephh 	}
3355255Sstephh 	return (rt);
3365255Sstephh }
3375255Sstephh 
3385255Sstephh static char *
get_nvl2str_topo(nvlist_t * nvl)3395255Sstephh get_nvl2str_topo(nvlist_t *nvl)
3405255Sstephh {
3415255Sstephh 	char *name = NULL;
3425255Sstephh 	char *tname;
3435255Sstephh 	int err;
3445255Sstephh 	char *scheme = NULL;
3455255Sstephh 	char *mod_name = NULL;
3465255Sstephh 	char buf[128];
3475255Sstephh 
3485255Sstephh 	if (topo_handle == NULL)
349*12618SStephen.Hanson@Sun.COM 		topo_handle = topo_open(TOPO_VERSION, 0, &err);
3505255Sstephh 	if (topo_fmri_nvl2str(topo_handle, nvl, &tname, &err) == 0) {
3515255Sstephh 		name = strdup(tname);
3525255Sstephh 		topo_hdl_strfree(topo_handle, tname);
3535255Sstephh 	} else {
3545255Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme);
3555255Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_MOD_NAME, &mod_name);
3565255Sstephh 		if (scheme && strcmp(scheme, FM_FMRI_SCHEME_FMD) == 0 &&
3575255Sstephh 		    mod_name) {
3585255Sstephh 			(void) snprintf(buf, sizeof (buf), "%s:///module/%s",
3595255Sstephh 			    scheme, mod_name);
3605255Sstephh 			name = strdup(buf);
3615255Sstephh 		}
3625255Sstephh 	}
3635255Sstephh 	return (name);
3645255Sstephh }
3655255Sstephh 
3665255Sstephh static int
set_priority(char * s)3675255Sstephh set_priority(char *s)
3685255Sstephh {
3695255Sstephh 	int rt = 0;
3705255Sstephh 
3715255Sstephh 	if (s) {
3725255Sstephh 		if (strcmp(s, "Minor") == 0)
3735255Sstephh 			rt = 1;
3745255Sstephh 		else if (strcmp(s, "Major") == 0)
3755255Sstephh 			rt = 10;
3765255Sstephh 		else if (strcmp(s, "Critical") == 0)
3775255Sstephh 			rt = 100;
3785255Sstephh 	}
3795255Sstephh 	return (rt);
3805255Sstephh }
3815255Sstephh 
3825255Sstephh static int
cmp_priority(char * s1,char * s2,uint64_t t1,uint64_t t2,uint8_t p1,uint8_t p2)3835255Sstephh cmp_priority(char *s1, char *s2, uint64_t t1, uint64_t t2, uint8_t p1,
3845255Sstephh     uint8_t p2)
3855255Sstephh {
3865255Sstephh 	int r1, r2;
3875255Sstephh 	int rt;
3885255Sstephh 
3895255Sstephh 	r1 = set_priority(s1);
3905255Sstephh 	r2 = set_priority(s2);
3915255Sstephh 	rt = r1 - r2;
3925255Sstephh 	if (rt == 0) {
3935255Sstephh 		if (t1 > t2)
3945255Sstephh 			rt = 1;
3955255Sstephh 		else if (t1 < t2)
3965255Sstephh 			rt = -1;
3975255Sstephh 		else
3985255Sstephh 			rt = p1 - p2;
3995255Sstephh 	}
4005255Sstephh 	return (rt);
4015255Sstephh }
4025255Sstephh 
4035255Sstephh /*
4045255Sstephh  * merge two lists into one, by comparing enties in new and moving into list if
4055255Sstephh  * name is not there or free off memory for names which are already there
4065255Sstephh  * add_pct indicates if pct is the sum or highest pct
4075255Sstephh  */
4085255Sstephh static name_list_t *
merge_name_list(name_list_t ** list,name_list_t * new,int add_pct)4095255Sstephh merge_name_list(name_list_t **list, name_list_t *new, int add_pct)
4105255Sstephh {
4115255Sstephh 	name_list_t *lp, *np, *sp, *rt = NULL;
4125255Sstephh 	int max_pct;
4135255Sstephh 
4145255Sstephh 	rt = *list;
4155255Sstephh 	np = new;
4165255Sstephh 	while (np) {
4175255Sstephh 		lp = *list;
4185255Sstephh 		while (lp) {
4195255Sstephh 			if (strcmp(lp->name, np->name) == 0)
4205255Sstephh 				break;
4215255Sstephh 			lp = lp->next;
4225255Sstephh 			if (lp == *list)
4235255Sstephh 				lp = NULL;
4245255Sstephh 		}
4255255Sstephh 		if (np->next == new)
4265255Sstephh 			sp = NULL;
4275255Sstephh 		else
4285255Sstephh 			sp = np->next;
4295255Sstephh 		if (lp) {
4305255Sstephh 			lp->status |= (np->status & FM_SUSPECT_FAULTY);
4315255Sstephh 			if (add_pct) {
4325255Sstephh 				lp->pct += np->pct;
4335255Sstephh 				lp->count += np->count;
4345255Sstephh 			} else if (np->pct > lp->pct) {
4355255Sstephh 				lp->pct = np->pct;
4365255Sstephh 			}
4375255Sstephh 			max_pct = np->max_pct;
4386002Sstephh 			if (np->label)
4396002Sstephh 				free(np->label);
4405255Sstephh 			free(np->name);
4415255Sstephh 			free(np);
4425255Sstephh 			np = NULL;
4435255Sstephh 			if (max_pct > lp->max_pct) {
4445255Sstephh 				lp->max_pct = max_pct;
4455255Sstephh 				if (lp->max_pct > lp->prev->max_pct &&
4465255Sstephh 				    lp != *list) {
4475255Sstephh 					lp->prev->next = lp->next;
4485255Sstephh 					lp->next->prev = lp->prev;
4495255Sstephh 					np = lp;
4505255Sstephh 				}
4515255Sstephh 			}
4525255Sstephh 		}
4535255Sstephh 		if (np) {
4545255Sstephh 			lp = *list;
4555255Sstephh 			if (lp) {
4565255Sstephh 				if (np->max_pct > lp->max_pct) {
4575255Sstephh 					np->next = lp;
4585255Sstephh 					np->prev = lp->prev;
4595255Sstephh 					lp->prev->next = np;
4605255Sstephh 					lp->prev = np;
4615255Sstephh 					*list = np;
4625255Sstephh 					rt = np;
4635255Sstephh 				} else {
4645255Sstephh 					lp = lp->next;
4655255Sstephh 					while (lp != *list &&
4665255Sstephh 					    np->max_pct < lp->max_pct) {
4675255Sstephh 						lp = lp->next;
4685255Sstephh 					}
4695255Sstephh 					np->next = lp;
4705255Sstephh 					np->prev = lp->prev;
4715255Sstephh 					lp->prev->next = np;
4725255Sstephh 					lp->prev = np;
4735255Sstephh 				}
4745255Sstephh 			} else {
4755255Sstephh 				*list = np;
4765255Sstephh 				np->next = np;
4775255Sstephh 				np->prev = np;
4785255Sstephh 				rt = np;
4795255Sstephh 			}
4805255Sstephh 		}
4815255Sstephh 		np = sp;
4825255Sstephh 	}
4835255Sstephh 	return (rt);
4845255Sstephh }
4855255Sstephh 
4865255Sstephh static name_list_t *
alloc_name_list(char * name,uint8_t pct)4875255Sstephh alloc_name_list(char *name, uint8_t pct)
4885255Sstephh {
4895255Sstephh 	name_list_t *nlp;
4905255Sstephh 
4915255Sstephh 	nlp = malloc(sizeof (*nlp));
4925255Sstephh 	nlp->name = strdup(name);
4935255Sstephh 	nlp->pct = pct;
4945255Sstephh 	nlp->max_pct = pct;
4955255Sstephh 	nlp->count = 1;
4965255Sstephh 	nlp->next = nlp;
4975255Sstephh 	nlp->prev = nlp;
4985255Sstephh 	nlp->status = 0;
4996002Sstephh 	nlp->label = NULL;
5005255Sstephh 	return (nlp);
5015255Sstephh }
5025255Sstephh 
5035255Sstephh static status_record_t *
new_record_init(uurec_t * uurec_p,char * msgid,name_list_t * class,name_list_t * fru,name_list_t * asru,name_list_t * resource,name_list_t * serial,boolean_t not_suppressed,hostid_t * hostid,boolean_t injected)5045255Sstephh new_record_init(uurec_t *uurec_p, char *msgid, name_list_t *class,
5055255Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
5069501SRobert.Johnston@Sun.COM     name_list_t *serial, boolean_t not_suppressed,
50710928SStephen.Hanson@Sun.COM     hostid_t *hostid, boolean_t injected)
5085255Sstephh {
5095255Sstephh 	status_record_t *status_rec_p;
5105255Sstephh 
5115255Sstephh 	status_rec_p = (status_record_t *)malloc(sizeof (status_record_t));
5125255Sstephh 	status_rec_p->nrecs = 1;
5135255Sstephh 	status_rec_p->host = hostid;
5145255Sstephh 	status_rec_p->uurec = uurec_p;
5155255Sstephh 	uurec_p->next = NULL;
5165255Sstephh 	uurec_p->prev = NULL;
5175255Sstephh 	uurec_p->asru = asru;
5189501SRobert.Johnston@Sun.COM 	if ((status_rec_p->severity = fmd_msg_getitem_id(fmadm_msghdl, NULL,
5199501SRobert.Johnston@Sun.COM 	    msgid, FMD_MSG_ITEM_SEVERITY)) == NULL)
5209501SRobert.Johnston@Sun.COM 		status_rec_p->severity = strdup("unknown");
5215255Sstephh 	status_rec_p->class = class;
5225255Sstephh 	status_rec_p->fru = fru;
5235255Sstephh 	status_rec_p->asru = asru;
5245255Sstephh 	status_rec_p->resource = resource;
5255255Sstephh 	status_rec_p->serial = serial;
5265255Sstephh 	status_rec_p->msgid = strdup(msgid);
5275255Sstephh 	status_rec_p->not_suppressed = not_suppressed;
52810928SStephen.Hanson@Sun.COM 	status_rec_p->injected = injected;
5295255Sstephh 	return (status_rec_p);
5305255Sstephh }
5315255Sstephh 
5325255Sstephh /*
5335255Sstephh  * add record to given list maintaining order higher priority first.
5345255Sstephh  */
5355255Sstephh static void
add_rec_list(status_record_t * status_rec_p,sr_list_t ** list_pp)5365255Sstephh add_rec_list(status_record_t *status_rec_p, sr_list_t **list_pp)
5375255Sstephh {
5385255Sstephh 	sr_list_t *tp, *np, *sp;
5395255Sstephh 	int order;
5405255Sstephh 	uint64_t sec;
5415255Sstephh 
5425255Sstephh 	np = malloc(sizeof (sr_list_t));
5435255Sstephh 	np->status_record = status_rec_p;
5445255Sstephh 	sec = status_rec_p->uurec->sec;
5455255Sstephh 	if ((sp = *list_pp) == NULL) {
5465255Sstephh 		*list_pp = np;
5475255Sstephh 		np->next = np;
5485255Sstephh 		np->prev = np;
5495255Sstephh 	} else {
5505255Sstephh 		/* insert new record in front of lower priority */
5515255Sstephh 		tp = sp;
5525255Sstephh 		order = cmp_priority(status_rec_p->severity,
5535255Sstephh 		    sp->status_record->severity, sec,
5545255Sstephh 		    tp->status_record->uurec->sec, 0, 0);
5555255Sstephh 		if (order > 0) {
5565255Sstephh 			*list_pp = np;
5575255Sstephh 		} else {
5585255Sstephh 			tp = sp->next;
5595255Sstephh 			while (tp != sp &&
5605255Sstephh 			    cmp_priority(status_rec_p->severity,
5615255Sstephh 			    tp->status_record->severity, sec,
5625255Sstephh 			    tp->status_record->uurec->sec, 0, 0)) {
5635255Sstephh 				tp = tp->next;
5645255Sstephh 			}
5655255Sstephh 		}
5665255Sstephh 		np->next = tp;
5675255Sstephh 		np->prev = tp->prev;
5685255Sstephh 		tp->prev->next = np;
5695255Sstephh 		tp->prev = np;
5705255Sstephh 	}
5715255Sstephh }
5725255Sstephh 
5735255Sstephh static void
add_resource(status_record_t * status_rec_p,resource_list_t ** rp,resource_list_t * np)5745255Sstephh add_resource(status_record_t *status_rec_p, resource_list_t **rp,
5755255Sstephh     resource_list_t *np)
5765255Sstephh {
5775255Sstephh 	int order;
5785255Sstephh 	uint64_t sec;
5795255Sstephh 	resource_list_t *sp, *tp;
5805255Sstephh 	status_record_t *srp;
5815255Sstephh 	char *severity = status_rec_p->severity;
5825255Sstephh 
5835255Sstephh 	add_rec_list(status_rec_p, &np->status_rec_list);
5845255Sstephh 	if ((sp = *rp) == NULL) {
5855255Sstephh 		np->next = np;
5865255Sstephh 		np->prev = np;
5875255Sstephh 		*rp = np;
5885255Sstephh 	} else {
5895255Sstephh 		/*
5905255Sstephh 		 * insert new record in front of lower priority
5915255Sstephh 		 */
5925255Sstephh 		tp = sp->next;
5935255Sstephh 		srp = sp->status_rec_list->status_record;
5945255Sstephh 		sec = status_rec_p->uurec->sec;
5955255Sstephh 		order = cmp_priority(severity, srp->severity, sec,
5965255Sstephh 		    srp->uurec->sec, np->max_pct, sp->max_pct);
5975255Sstephh 		if (order > 0) {
5985255Sstephh 			*rp = np;
5995255Sstephh 		} else {
6005255Sstephh 			srp = tp->status_rec_list->status_record;
6015255Sstephh 			while (tp != sp &&
6025255Sstephh 			    cmp_priority(severity, srp->severity, sec,
6035255Sstephh 			    srp->uurec->sec, np->max_pct, sp->max_pct) < 0) {
6045255Sstephh 				tp = tp->next;
6055255Sstephh 				srp = tp->status_rec_list->status_record;
6065255Sstephh 			}
6075255Sstephh 		}
6085255Sstephh 		np->next = tp;
6095255Sstephh 		np->prev = tp->prev;
6105255Sstephh 		tp->prev->next = np;
6115255Sstephh 		tp->prev = np;
6125255Sstephh 	}
6135255Sstephh }
6145255Sstephh 
6155255Sstephh static void
add_resource_list(status_record_t * status_rec_p,name_list_t * fp,resource_list_t ** rpp)6165255Sstephh add_resource_list(status_record_t *status_rec_p, name_list_t *fp,
6175255Sstephh     resource_list_t **rpp)
6185255Sstephh {
6195255Sstephh 	int order;
6205255Sstephh 	resource_list_t *np, *end;
6215255Sstephh 	status_record_t *srp;
6225255Sstephh 
6235255Sstephh 	np = *rpp;
6245255Sstephh 	end = np;
6255255Sstephh 	while (np) {
6265255Sstephh 		if (strcmp(fp->name, np->resource) == 0) {
6275255Sstephh 			np->not_suppressed |= status_rec_p->not_suppressed;
62810928SStephen.Hanson@Sun.COM 			np->injected |= status_rec_p->injected;
6295255Sstephh 			srp = np->status_rec_list->status_record;
6305255Sstephh 			order = cmp_priority(status_rec_p->severity,
6315255Sstephh 			    srp->severity, status_rec_p->uurec->sec,
6325255Sstephh 			    srp->uurec->sec, fp->max_pct, np->max_pct);
6335255Sstephh 			if (order > 0 && np != end) {
6345255Sstephh 				/*
6355255Sstephh 				 * remove from list and add again using
6365255Sstephh 				 * new priority
6375255Sstephh 				 */
6385255Sstephh 				np->prev->next = np->next;
6395255Sstephh 				np->next->prev = np->prev;
6405255Sstephh 				add_resource(status_rec_p,
6415255Sstephh 				    rpp, np);
6425255Sstephh 			} else {
6435255Sstephh 				add_rec_list(status_rec_p,
6445255Sstephh 				    &np->status_rec_list);
6455255Sstephh 			}
6465255Sstephh 			break;
6475255Sstephh 		}
6485255Sstephh 		np = np->next;
6495255Sstephh 		if (np == end) {
6505255Sstephh 			np = NULL;
6515255Sstephh 			break;
6525255Sstephh 		}
6535255Sstephh 	}
6545255Sstephh 	if (np == NULL) {
6555255Sstephh 		np = malloc(sizeof (resource_list_t));
6565255Sstephh 		np->resource = fp->name;
6575255Sstephh 		np->not_suppressed = status_rec_p->not_suppressed;
65810928SStephen.Hanson@Sun.COM 		np->injected = status_rec_p->injected;
6595255Sstephh 		np->status_rec_list = NULL;
6605255Sstephh 		np->max_pct = fp->max_pct;
6615255Sstephh 		add_resource(status_rec_p, rpp, np);
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6655255Sstephh static void
add_list(status_record_t * status_rec_p,name_list_t * listp,resource_list_t ** glistp)6665255Sstephh add_list(status_record_t *status_rec_p, name_list_t *listp,
6675255Sstephh     resource_list_t **glistp)
6685255Sstephh {
6695255Sstephh 	name_list_t *fp, *end;
6705255Sstephh 
6715255Sstephh 	fp = listp;
6725255Sstephh 	end = fp;
6735255Sstephh 	while (fp) {
6745255Sstephh 		add_resource_list(status_rec_p, fp, glistp);
6755255Sstephh 		fp = fp->next;
6765255Sstephh 		if (fp == end)
6775255Sstephh 			break;
6785255Sstephh 	}
6795255Sstephh }
6805255Sstephh 
6815255Sstephh /*
6825255Sstephh  * add record to rec, fru and asru lists.
6835255Sstephh  */
6845255Sstephh static void
catalog_new_record(uurec_t * uurec_p,char * msgid,name_list_t * class,name_list_t * fru,name_list_t * asru,name_list_t * resource,name_list_t * serial,boolean_t not_suppressed,hostid_t * hostid,boolean_t injected,boolean_t dummy_fru)6855255Sstephh catalog_new_record(uurec_t *uurec_p, char *msgid, name_list_t *class,
6865255Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
6879501SRobert.Johnston@Sun.COM     name_list_t *serial, boolean_t not_suppressed,
68811416SStephen.Hanson@Sun.COM     hostid_t *hostid, boolean_t injected, boolean_t dummy_fru)
6895255Sstephh {
6905255Sstephh 	status_record_t *status_rec_p;
6915255Sstephh 
6925255Sstephh 	status_rec_p = new_record_init(uurec_p, msgid, class, fru, asru,
69310928SStephen.Hanson@Sun.COM 	    resource, serial, not_suppressed, hostid, injected);
6945255Sstephh 	add_rec_list(status_rec_p, &status_rec_list);
69511416SStephen.Hanson@Sun.COM 	if (status_rec_p->fru && !dummy_fru)
6965255Sstephh 		add_list(status_rec_p, status_rec_p->fru, &status_fru_list);
6975255Sstephh 	if (status_rec_p->asru)
6985255Sstephh 		add_list(status_rec_p, status_rec_p->asru, &status_asru_list);
6995255Sstephh }
7005255Sstephh 
7015255Sstephh static void
get_serial_no(nvlist_t * nvl,name_list_t ** serial_p,uint8_t pct)7025255Sstephh get_serial_no(nvlist_t *nvl, name_list_t **serial_p, uint8_t pct)
7035255Sstephh {
7045255Sstephh 	char *name;
7055255Sstephh 	char *serial = NULL;
7065255Sstephh 	char **lserial = NULL;
7075255Sstephh 	uint64_t serint;
7085255Sstephh 	name_list_t *nlp;
7095255Sstephh 	int j;
7105255Sstephh 	uint_t nelem;
7115255Sstephh 	char buf[64];
7120Sstevel@tonic-gate 
7135255Sstephh 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) == 0) {
7145255Sstephh 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
7155255Sstephh 			if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
7165255Sstephh 			    &serint) == 0) {
7175255Sstephh 				(void) snprintf(buf, sizeof (buf), "%llX",
7185255Sstephh 				    serint);
7195255Sstephh 				nlp = alloc_name_list(buf, pct);
7205255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
7215255Sstephh 			}
7225255Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
7235255Sstephh 			if (nvlist_lookup_string_array(nvl,
7245255Sstephh 			    FM_FMRI_MEM_SERIAL_ID, &lserial, &nelem) == 0) {
7255255Sstephh 				nlp = alloc_name_list(lserial[0], pct);
7265255Sstephh 				for (j = 1; j < nelem; j++) {
7275255Sstephh 					name_list_t *n1lp;
7285255Sstephh 					n1lp = alloc_name_list(lserial[j], pct);
7295255Sstephh 					(void) merge_name_list(&nlp, n1lp, 1);
7305255Sstephh 				}
7315255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
7325255Sstephh 			}
7335255Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_HC) == 0) {
7345255Sstephh 			if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID,
7355255Sstephh 			    &serial) == 0) {
7365255Sstephh 				nlp = alloc_name_list(serial, pct);
7375255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
7385255Sstephh 			}
7395255Sstephh 		}
7405255Sstephh 	}
7415255Sstephh }
7425255Sstephh 
7435255Sstephh static void
extract_record_info(nvlist_t * nvl,name_list_t ** class_p,name_list_t ** fru_p,name_list_t ** serial_p,name_list_t ** resource_p,name_list_t ** asru_p,boolean_t * dummy_fru,uint8_t status)7445255Sstephh extract_record_info(nvlist_t *nvl, name_list_t **class_p,
74511416SStephen.Hanson@Sun.COM     name_list_t **fru_p, name_list_t **serial_p, name_list_t **resource_p,
74611416SStephen.Hanson@Sun.COM     name_list_t **asru_p, boolean_t *dummy_fru, uint8_t status)
7470Sstevel@tonic-gate {
7485255Sstephh 	nvlist_t *lfru, *lasru, *rsrc;
7495255Sstephh 	name_list_t *nlp;
7505255Sstephh 	char *name;
7515255Sstephh 	uint8_t lpct = 0;
7525255Sstephh 	char *lclass = NULL;
7536002Sstephh 	char *label;
7545255Sstephh 
7555255Sstephh 	(void) nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &lpct);
7565255Sstephh 	if (nvlist_lookup_string(nvl, FM_CLASS, &lclass) == 0) {
7575255Sstephh 		nlp = alloc_name_list(lclass, lpct);
7585255Sstephh 		(void) merge_name_list(class_p, nlp, 1);
7595255Sstephh 	}
7605255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &lfru) == 0) {
7615255Sstephh 		name = get_nvl2str_topo(lfru);
7625255Sstephh 		if (name != NULL) {
7635255Sstephh 			nlp = alloc_name_list(name, lpct);
7647275Sstephh 			nlp->status = status & ~(FM_SUSPECT_UNUSABLE |
7657275Sstephh 			    FM_SUSPECT_DEGRADED);
7665255Sstephh 			free(name);
7676002Sstephh 			if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION,
7686002Sstephh 			    &label) == 0)
7696002Sstephh 				nlp->label = strdup(label);
7705255Sstephh 			(void) merge_name_list(fru_p, nlp, 1);
7715255Sstephh 		}
7725255Sstephh 		get_serial_no(lfru, serial_p, lpct);
77310656SStephen.Hanson@Sun.COM 	} else if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) != 0) {
77410656SStephen.Hanson@Sun.COM 		/*
77510656SStephen.Hanson@Sun.COM 		 * No FRU or resource. But we want to display the repair status
77610656SStephen.Hanson@Sun.COM 		 * somehow, so create a dummy FRU field.
77710656SStephen.Hanson@Sun.COM 		 */
77811416SStephen.Hanson@Sun.COM 		*dummy_fru = 1;
77910656SStephen.Hanson@Sun.COM 		nlp = alloc_name_list(dgettext("FMD", "None"), lpct);
78010656SStephen.Hanson@Sun.COM 		nlp->status = status & ~(FM_SUSPECT_UNUSABLE |
78110656SStephen.Hanson@Sun.COM 		    FM_SUSPECT_DEGRADED);
78210656SStephen.Hanson@Sun.COM 		(void) merge_name_list(fru_p, nlp, 1);
7835255Sstephh 	}
7845255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &lasru) == 0) {
7855255Sstephh 		name = get_nvl2str_topo(lasru);
7865255Sstephh 		if (name != NULL) {
7875255Sstephh 			nlp = alloc_name_list(name, lpct);
7887275Sstephh 			nlp->status = status & ~(FM_SUSPECT_NOT_PRESENT |
7897275Sstephh 			    FM_SUSPECT_REPAIRED | FM_SUSPECT_REPLACED |
7907275Sstephh 			    FM_SUSPECT_ACQUITTED);
7915255Sstephh 			free(name);
7925255Sstephh 			(void) merge_name_list(asru_p, nlp, 1);
7935255Sstephh 		}
7945255Sstephh 		get_serial_no(lasru, serial_p, lpct);
7955255Sstephh 	}
7965255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
7975255Sstephh 		name = get_nvl2str_topo(rsrc);
7985255Sstephh 		if (name != NULL) {
7995255Sstephh 			nlp = alloc_name_list(name, lpct);
8006228Sstephh 			nlp->status = status;
8015255Sstephh 			free(name);
8028245SStephen.Hanson@Sun.COM 			if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION,
8038245SStephen.Hanson@Sun.COM 			    &label) == 0)
8048245SStephen.Hanson@Sun.COM 				nlp->label = strdup(label);
8055255Sstephh 			(void) merge_name_list(resource_p, nlp, 1);
8065255Sstephh 		}
8075255Sstephh 	}
8085255Sstephh }
8095255Sstephh 
8105255Sstephh static void
add_fault_record_to_catalog(nvlist_t * nvl,uint64_t sec,char * uuid)8119501SRobert.Johnston@Sun.COM add_fault_record_to_catalog(nvlist_t *nvl, uint64_t sec, char *uuid)
8125255Sstephh {
8135255Sstephh 	char *msgid = "-";
8145255Sstephh 	uint_t i, size = 0;
8155255Sstephh 	name_list_t *class = NULL, *resource = NULL;
8165255Sstephh 	name_list_t *asru = NULL, *fru = NULL, *serial = NULL;
8175255Sstephh 	nvlist_t **nva;
8185255Sstephh 	uint8_t *ba;
8195255Sstephh 	uurec_t *uurec_p;
8205255Sstephh 	hostid_t *host;
8215255Sstephh 	boolean_t not_suppressed = 1;
8225255Sstephh 	boolean_t any_present = 0;
82310928SStephen.Hanson@Sun.COM 	boolean_t injected = 0;
82411416SStephen.Hanson@Sun.COM 	boolean_t dummy_fru = 0;
8255255Sstephh 
8265255Sstephh 	(void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &msgid);
8275255Sstephh 	(void) nvlist_lookup_uint32(nvl, FM_SUSPECT_FAULT_SZ, &size);
8285255Sstephh 	(void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_MESSAGE,
8295255Sstephh 	    &not_suppressed);
83010928SStephen.Hanson@Sun.COM 	(void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED, &injected);
8315255Sstephh 
8325255Sstephh 	if (size != 0) {
8335255Sstephh 		(void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
8345255Sstephh 		    &nva, &size);
8355255Sstephh 		(void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS,
8365255Sstephh 		    &ba, &size);
8375255Sstephh 		for (i = 0; i < size; i++) {
8385255Sstephh 			extract_record_info(nva[i], &class, &fru, &serial,
83911416SStephen.Hanson@Sun.COM 			    &resource, &asru, &dummy_fru, ba[i]);
8405255Sstephh 			if (!(ba[i] & FM_SUSPECT_NOT_PRESENT) &&
8415255Sstephh 			    (ba[i] & FM_SUSPECT_FAULTY))
8425255Sstephh 				any_present = 1;
8435255Sstephh 		}
8445255Sstephh 		/*
8455255Sstephh 		 * also suppress if no resources present
8465255Sstephh 		 */
8475255Sstephh 		if (any_present == 0)
8485255Sstephh 			not_suppressed = 0;
8490Sstevel@tonic-gate 	}
8500Sstevel@tonic-gate 
8515255Sstephh 	uurec_p = (uurec_t *)malloc(sizeof (uurec_t));
8525255Sstephh 	uurec_p->uuid = strdup(uuid);
8535255Sstephh 	uurec_p->sec = sec;
8545255Sstephh 	uurec_p->ari_uuid_list = NULL;
85510234SRobert.Johnston@Sun.COM 	uurec_p->event = NULL;
85610234SRobert.Johnston@Sun.COM 	(void) nvlist_dup(nvl, &uurec_p->event, 0);
8575255Sstephh 	host = find_hostid(nvl);
85810656SStephen.Hanson@Sun.COM 	catalog_new_record(uurec_p, msgid, class, fru, asru,
85911416SStephen.Hanson@Sun.COM 	    resource, serial, not_suppressed, host, injected, dummy_fru);
8605255Sstephh }
8615255Sstephh 
8625255Sstephh static void
update_asru_state_in_catalog(const char * uuid,const char * ari_uuid)8635255Sstephh update_asru_state_in_catalog(const char *uuid, const char *ari_uuid)
8645255Sstephh {
8655255Sstephh 	sr_list_t *srp;
8665255Sstephh 	uurec_t *uurp;
8675255Sstephh 	ari_list_t *ari_list;
8685255Sstephh 
8695255Sstephh 	srp = status_rec_list;
8705255Sstephh 	if (srp) {
8715255Sstephh 		for (;;) {
8725255Sstephh 			uurp = srp->status_record->uurec;
8735255Sstephh 			while (uurp) {
8745255Sstephh 				if (strcmp(uuid, uurp->uuid) == 0) {
8755255Sstephh 					ari_list = (ari_list_t *)
8765255Sstephh 					    malloc(sizeof (ari_list_t));
8775255Sstephh 					ari_list->ari_uuid = strdup(ari_uuid);
8785255Sstephh 					ari_list->next = uurp->ari_uuid_list;
8795255Sstephh 					uurp->ari_uuid_list = ari_list;
8805255Sstephh 					return;
8815255Sstephh 				}
8825255Sstephh 				uurp = uurp->next;
8835255Sstephh 			}
8845255Sstephh 			if (srp->next == status_rec_list)
8855255Sstephh 				break;
8865255Sstephh 			srp = srp->next;
8875255Sstephh 		}
8885255Sstephh 	}
8895255Sstephh }
8905255Sstephh 
8915255Sstephh static void
print_line(char * label,char * buf)8925255Sstephh print_line(char *label, char *buf)
8935255Sstephh {
8945255Sstephh 	char *cp, *ep, *wp;
8955255Sstephh 	char c;
8965255Sstephh 	int i;
8975255Sstephh 	int lsz;
8985255Sstephh 	char *padding;
8995255Sstephh 
9005255Sstephh 	lsz = strlen(label);
9015255Sstephh 	padding = malloc(lsz + 1);
9025255Sstephh 	for (i = 0; i < lsz; i++)
9035255Sstephh 		padding[i] = ' ';
9045255Sstephh 	padding[i] = 0;
9055255Sstephh 	cp = buf;
9065255Sstephh 	ep = buf;
9075255Sstephh 	c = *ep;
9085255Sstephh 	(void) printf("\n");
9095255Sstephh 	while (c) {
9105255Sstephh 		i = lsz;
9115255Sstephh 		wp = NULL;
9125255Sstephh 		while ((c = *ep) != NULL && (wp == NULL || i < 80)) {
9135255Sstephh 			if (c == ' ')
9145255Sstephh 				wp = ep;
9155255Sstephh 			else if (c == '\n') {
9165255Sstephh 				i = 0;
9175255Sstephh 				*ep = 0;
9185255Sstephh 				do {
9195255Sstephh 					ep++;
9205255Sstephh 				} while ((c = *ep) != NULL && c == ' ');
9215255Sstephh 				break;
9225255Sstephh 			}
9235255Sstephh 			ep++;
9245255Sstephh 			i++;
9255255Sstephh 		}
9265255Sstephh 		if (i >= 80 && wp) {
9275255Sstephh 			*wp = 0;
9285255Sstephh 			ep = wp + 1;
9295255Sstephh 			c = *ep;
9305255Sstephh 		}
9315255Sstephh 		(void) printf("%s%s\n", label, cp);
9325255Sstephh 		cp = ep;
9335255Sstephh 		label = padding;
9345255Sstephh 	}
9355255Sstephh 	free(padding);
9365255Sstephh }
9375255Sstephh 
9385255Sstephh static void
print_dict_info_line(nvlist_t * e,fmd_msg_item_t what,const char * linehdr)93910234SRobert.Johnston@Sun.COM print_dict_info_line(nvlist_t *e, fmd_msg_item_t what, const char *linehdr)
9405255Sstephh {
94110234SRobert.Johnston@Sun.COM 	char *cp = fmd_msg_getitem_nv(fmadm_msghdl, NULL, e, what);
9425255Sstephh 
9435255Sstephh 	if (cp) {
9449501SRobert.Johnston@Sun.COM 		print_line(dgettext("FMD", linehdr), cp);
9459501SRobert.Johnston@Sun.COM 		free(cp);
9465255Sstephh 	}
9479501SRobert.Johnston@Sun.COM }
9489501SRobert.Johnston@Sun.COM 
9499501SRobert.Johnston@Sun.COM static void
print_dict_info(nvlist_t * nvl)95010234SRobert.Johnston@Sun.COM print_dict_info(nvlist_t *nvl)
9519501SRobert.Johnston@Sun.COM {
95210234SRobert.Johnston@Sun.COM 	print_dict_info_line(nvl, FMD_MSG_ITEM_DESC, "Description : ");
95310234SRobert.Johnston@Sun.COM 	print_dict_info_line(nvl, FMD_MSG_ITEM_RESPONSE, "Response    : ");
95410234SRobert.Johnston@Sun.COM 	print_dict_info_line(nvl, FMD_MSG_ITEM_IMPACT, "Impact      : ");
95510234SRobert.Johnston@Sun.COM 	print_dict_info_line(nvl, FMD_MSG_ITEM_ACTION, "Action      : ");
9565255Sstephh }
9575255Sstephh 
9585255Sstephh static void
print_name(name_list_t * list,char * padding,int * np,int pct,int full)959*12618SStephen.Hanson@Sun.COM print_name(name_list_t *list, char *padding, int *np, int pct, int full)
9605255Sstephh {
961*12618SStephen.Hanson@Sun.COM 	char *name;
9625255Sstephh 
9635255Sstephh 	name = list->name;
9648245SStephen.Hanson@Sun.COM 	if (list->label) {
9658245SStephen.Hanson@Sun.COM 		(void) printf("%s \"%s\" (%s)", padding, list->label, name);
9665255Sstephh 		*np += 1;
9675255Sstephh 	} else {
9685255Sstephh 		(void) printf("%s %s", padding, name);
9695255Sstephh 		*np += 1;
9705255Sstephh 	}
9715255Sstephh 	if (list->pct && pct > 0 && pct < 100) {
9725255Sstephh 		if (list->count > 1) {
9735255Sstephh 			if (full) {
9745255Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
9755255Sstephh 				    dgettext("FMD", "max"),
9765255Sstephh 				    list->max_pct);
9775255Sstephh 			} else {
9785255Sstephh 				(void) printf(" %s %d%%\n",
9795255Sstephh 				    dgettext("FMD", "max"),
9805255Sstephh 				    list->max_pct);
9815255Sstephh 			}
9825255Sstephh 		} else {
9835255Sstephh 			(void) printf(" %d%%\n", list->pct);
9845255Sstephh 		}
9855255Sstephh 	} else {
9865255Sstephh 		(void) printf("\n");
9875255Sstephh 	}
9885255Sstephh }
9895255Sstephh 
9905255Sstephh static void
print_asru_status(int status,char * label)9915255Sstephh print_asru_status(int status, char *label)
9925255Sstephh {
9935255Sstephh 	char *msg = NULL;
9945255Sstephh 
9955255Sstephh 	switch (status) {
9965255Sstephh 	case 0:
9975255Sstephh 		msg = dgettext("FMD", "ok and in service");
9985255Sstephh 		break;
9997275Sstephh 	case FM_SUSPECT_DEGRADED:
10007275Sstephh 		msg = dgettext("FMD", "service degraded, "
10017275Sstephh 		    "but associated components no longer faulty");
10027275Sstephh 		break;
10037275Sstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED:
10047275Sstephh 		msg = dgettext("FMD", "faulted but still "
10057275Sstephh 		    "providing degraded service");
10067275Sstephh 		break;
10075255Sstephh 	case FM_SUSPECT_FAULTY:
10087275Sstephh 		msg = dgettext("FMD", "faulted but still in service");
10095255Sstephh 		break;
10105255Sstephh 	case FM_SUSPECT_UNUSABLE:
10117275Sstephh 		msg = dgettext("FMD", "out of service, "
10127275Sstephh 		    "but associated components no longer faulty");
10135255Sstephh 		break;
10145255Sstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
10155255Sstephh 		msg = dgettext("FMD", "faulted and taken out of service");
10165255Sstephh 		break;
10175255Sstephh 	default:
10185255Sstephh 		break;
10195255Sstephh 	}
10205255Sstephh 	if (msg) {
10215255Sstephh 		(void) printf("%s     %s\n", label, msg);
10225255Sstephh 	}
10235255Sstephh }
10245255Sstephh 
10255255Sstephh static void
print_fru_status(int status,char * label)10266228Sstephh print_fru_status(int status, char *label)
10276228Sstephh {
10286228Sstephh 	char *msg = NULL;
10296228Sstephh 
10306228Sstephh 	if (status & FM_SUSPECT_NOT_PRESENT)
10316228Sstephh 		msg = dgettext("FMD", "not present");
10326228Sstephh 	else if (status & FM_SUSPECT_FAULTY)
10336228Sstephh 		msg = dgettext("FMD", "faulty");
10347275Sstephh 	else if (status & FM_SUSPECT_REPLACED)
10357275Sstephh 		msg = dgettext("FMD", "replaced");
10367275Sstephh 	else if (status & FM_SUSPECT_REPAIRED)
10377275Sstephh 		msg = dgettext("FMD", "repair attempted");
10387275Sstephh 	else if (status & FM_SUSPECT_ACQUITTED)
10397275Sstephh 		msg = dgettext("FMD", "acquitted");
10406228Sstephh 	else
10417275Sstephh 		msg = dgettext("FMD", "removed");
10426228Sstephh 	(void) printf("%s     %s\n", label, msg);
10436228Sstephh }
10446228Sstephh 
10456228Sstephh static void
print_rsrc_status(int status,char * label)10469120SStephen.Hanson@Sun.COM print_rsrc_status(int status, char *label)
10479120SStephen.Hanson@Sun.COM {
10489120SStephen.Hanson@Sun.COM 	char *msg = "";
10499120SStephen.Hanson@Sun.COM 
10509120SStephen.Hanson@Sun.COM 	if (status & FM_SUSPECT_NOT_PRESENT)
10519120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "not present");
10529120SStephen.Hanson@Sun.COM 	else if (status & FM_SUSPECT_FAULTY) {
10539120SStephen.Hanson@Sun.COM 		if (status & FM_SUSPECT_DEGRADED)
10549120SStephen.Hanson@Sun.COM 			msg = dgettext("FMD",
10559120SStephen.Hanson@Sun.COM 			    "faulted but still providing degraded service");
10569120SStephen.Hanson@Sun.COM 		else if (status & FM_SUSPECT_UNUSABLE)
10579120SStephen.Hanson@Sun.COM 			msg = dgettext("FMD",
10589120SStephen.Hanson@Sun.COM 			    "faulted and taken out of service");
10599120SStephen.Hanson@Sun.COM 		else
10609120SStephen.Hanson@Sun.COM 			msg = dgettext("FMD", "faulted but still in service");
10619120SStephen.Hanson@Sun.COM 	} else if (status & FM_SUSPECT_REPLACED)
10629120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "replaced");
10639120SStephen.Hanson@Sun.COM 	else if (status & FM_SUSPECT_REPAIRED)
10649120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "repair attempted");
10659120SStephen.Hanson@Sun.COM 	else if (status & FM_SUSPECT_ACQUITTED)
10669120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "acquitted");
10679120SStephen.Hanson@Sun.COM 	else
10689120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "removed");
10699120SStephen.Hanson@Sun.COM 	(void) printf("%s     %s\n", label, msg);
10709120SStephen.Hanson@Sun.COM }
10719120SStephen.Hanson@Sun.COM 
10729120SStephen.Hanson@Sun.COM static void
print_name_list(name_list_t * list,char * label,int limit,int pct,void (func1)(int,char *),int full)1073*12618SStephen.Hanson@Sun.COM print_name_list(name_list_t *list, char *label,
10745255Sstephh     int limit, int pct, void (func1)(int, char *), int full)
10755255Sstephh {
1076*12618SStephen.Hanson@Sun.COM 	char *name;
10775255Sstephh 	char *padding;
10785255Sstephh 	int i, j, l, n;
10795255Sstephh 	name_list_t *end = list;
10805255Sstephh 
10815255Sstephh 	l = strlen(label);
10825255Sstephh 	padding = malloc(l + 1);
10835255Sstephh 	for (i = 0; i < l; i++)
10845255Sstephh 		padding[i] = ' ';
10855255Sstephh 	padding[l] = 0;
10865255Sstephh 	(void) printf("%s", label);
10875255Sstephh 	name = list->name;
10888245SStephen.Hanson@Sun.COM 	if (list->label)
10896002Sstephh 		(void) printf(" \"%s\" (%s)", list->label, name);
1090*12618SStephen.Hanson@Sun.COM 	else
10918245SStephen.Hanson@Sun.COM 		(void) printf(" %s", name);
10925255Sstephh 	if (list->pct && pct > 0 && pct < 100) {
10935255Sstephh 		if (list->count > 1) {
10945255Sstephh 			if (full) {
10955255Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
10965255Sstephh 				    dgettext("FMD", "max"), list->max_pct);
10975255Sstephh 			} else {
10985255Sstephh 				(void) printf(" %s %d%%\n",
10995255Sstephh 				    dgettext("FMD", "max"), list->max_pct);
11005255Sstephh 			}
11015255Sstephh 		} else {
11025255Sstephh 			(void) printf(" %d%%\n", list->pct);
11035255Sstephh 		}
11045255Sstephh 	} else {
11055255Sstephh 		(void) printf("\n");
11065255Sstephh 	}
11075255Sstephh 	if (func1)
11085255Sstephh 		func1(list->status, padding);
11095255Sstephh 	n = 1;
11105255Sstephh 	j = 0;
11115255Sstephh 	while ((list = list->next) != end) {
11125255Sstephh 		if (limit == 0 || n < limit) {
1113*12618SStephen.Hanson@Sun.COM 			print_name(list, padding, &n, pct, full);
11145255Sstephh 			if (func1)
11155255Sstephh 				func1(list->status, padding);
11165255Sstephh 		} else
11175255Sstephh 			j++;
11185255Sstephh 	}
11195255Sstephh 	if (j == 1) {
1120*12618SStephen.Hanson@Sun.COM 		print_name(list->prev, padding, &n, pct, full);
11215255Sstephh 	} else if (j > 1) {
11225255Sstephh 		(void) printf("%s... %d %s\n", padding, j,
11235255Sstephh 		    dgettext("FMD", "more entries suppressed,"
11245255Sstephh 		    " use -v option for full list"));
11255255Sstephh 	}
11265255Sstephh 	free(padding);
11275255Sstephh }
11285255Sstephh 
11295255Sstephh static int
asru_same_status(name_list_t * list)11305255Sstephh asru_same_status(name_list_t *list)
11315255Sstephh {
11325255Sstephh 	name_list_t *end = list;
11335255Sstephh 	int status = list->status;
11345255Sstephh 
11355255Sstephh 	while ((list = list->next) != end) {
11365255Sstephh 		if (status == -1) {
11375255Sstephh 			status = list->status;
11385255Sstephh 			continue;
11395255Sstephh 		}
11405255Sstephh 		if (list->status != -1 && status != list->status) {
11415255Sstephh 			status = -1;
11425255Sstephh 			break;
11435255Sstephh 		}
11445255Sstephh 	}
11455255Sstephh 	return (status);
11465255Sstephh }
11475255Sstephh 
11485255Sstephh static int
serial_in_fru(name_list_t * fru,name_list_t * serial)11495255Sstephh serial_in_fru(name_list_t *fru, name_list_t *serial)
11505255Sstephh {
11515255Sstephh 	name_list_t *sp = serial;
11525255Sstephh 	name_list_t *fp;
11535255Sstephh 	int nserial = 0;
11545255Sstephh 	int found = 0;
11555255Sstephh 	char buf[128];
11565255Sstephh 
11575255Sstephh 	while (sp) {
11585255Sstephh 		fp = fru;
11595255Sstephh 		nserial++;
11605255Sstephh 		(void) snprintf(buf, sizeof (buf), "serial=%s", sp->name);
11615255Sstephh 		buf[sizeof (buf) - 1] = 0;
11625255Sstephh 		while (fp) {
11635255Sstephh 			if (strstr(fp->name, buf) != NULL) {
11645255Sstephh 				found++;
11655255Sstephh 				break;
11665255Sstephh 			}
11675255Sstephh 			fp = fp->next;
11685255Sstephh 			if (fp == fru)
11695255Sstephh 				break;
11705255Sstephh 		}
11715255Sstephh 		sp = sp->next;
11725255Sstephh 		if (sp == serial)
11735255Sstephh 			break;
11745255Sstephh 	}
11755255Sstephh 	return (found == nserial ? 1 : 0);
11765255Sstephh }
11775255Sstephh 
11785255Sstephh static void
print_sup_record(status_record_t * srp,int opt_i,int full)11795255Sstephh print_sup_record(status_record_t *srp, int opt_i, int full)
11805255Sstephh {
11815255Sstephh 	char buf[32];
11825255Sstephh 	uurec_t *uurp = srp->uurec;
11835255Sstephh 	int n, j, k, max;
11845255Sstephh 	int status;
11855255Sstephh 	ari_list_t *ari_list;
11865255Sstephh 
11875255Sstephh 	n = 0;
11885255Sstephh 	max = max_fault;
11895255Sstephh 	if (max < 0) {
11905255Sstephh 		max = 0;
11915255Sstephh 	}
11925255Sstephh 	j = max / 2;
11935255Sstephh 	max -= j;
11945255Sstephh 	k = srp->nrecs - max;
11955255Sstephh 	while ((uurp = uurp->next) != NULL) {
11965255Sstephh 		if (full || n < j || n >= k || max_fault == 0 ||
11975255Sstephh 		    srp->nrecs == max_fault+1) {
11985255Sstephh 			if (opt_i) {
11995255Sstephh 				ari_list = uurp->ari_uuid_list;
12005255Sstephh 				while (ari_list) {
12015255Sstephh 					(void) printf("%-15s %s\n",
12025255Sstephh 					    format_date(buf, sizeof (buf),
12035255Sstephh 					    uurp->sec), ari_list->ari_uuid);
12045255Sstephh 					ari_list = ari_list->next;
12055255Sstephh 				}
12065255Sstephh 			} else {
12075255Sstephh 				(void) printf("%-15s %s\n",
12085255Sstephh 				    format_date(buf, sizeof (buf), uurp->sec),
12095255Sstephh 				    uurp->uuid);
12105255Sstephh 			}
12115255Sstephh 		} else if (n == j)
12125255Sstephh 			(void) printf("... %d %s\n", srp->nrecs - max_fault,
12135255Sstephh 			    dgettext("FMD", "more entries suppressed"));
12145255Sstephh 		n++;
12155255Sstephh 	}
12165255Sstephh 	(void) printf("\n");
12179120SStephen.Hanson@Sun.COM 	(void) printf("%s %s", dgettext("FMD", "Host        :"),
12189120SStephen.Hanson@Sun.COM 	    srp->host->server);
12199120SStephen.Hanson@Sun.COM 	if (srp->host->domain)
12209120SStephen.Hanson@Sun.COM 		(void) printf("\t%s %s", dgettext("FMD", "Domain      :"),
12219120SStephen.Hanson@Sun.COM 		    srp->host->domain);
12229120SStephen.Hanson@Sun.COM 	(void) printf("\n%s %s", dgettext("FMD", "Platform    :"),
12239120SStephen.Hanson@Sun.COM 	    srp->host->platform);
122410462SSean.Ye@Sun.COM 	(void) printf("\t%s %s", dgettext("FMD", "Chassis_id  :"),
12259120SStephen.Hanson@Sun.COM 	    srp->host->chassis ? srp->host->chassis : "");
122610462SSean.Ye@Sun.COM 	(void) printf("\n%s %s\n\n", dgettext("FMD", "Product_sn  :"),
122710462SSean.Ye@Sun.COM 	    srp->host->product_sn? srp->host->product_sn : "");
12285255Sstephh 	if (srp->class)
12295255Sstephh 		print_name_list(srp->class,
1230*12618SStephen.Hanson@Sun.COM 		    dgettext("FMD", "Fault class :"), 0, srp->class->pct,
12315255Sstephh 		    NULL, full);
12325255Sstephh 	if (srp->asru) {
12335255Sstephh 		status = asru_same_status(srp->asru);
12345255Sstephh 		if (status != -1) {
12355255Sstephh 			print_name_list(srp->asru,
1236*12618SStephen.Hanson@Sun.COM 			    dgettext("FMD", "Affects     :"),
12375255Sstephh 			    full ? 0 : max_display, 0, NULL, full);
12385255Sstephh 			print_asru_status(status, "             ");
12395255Sstephh 		} else
12405255Sstephh 			print_name_list(srp->asru,
1241*12618SStephen.Hanson@Sun.COM 			    dgettext("FMD", "Affects     :"),
12425255Sstephh 			    full ? 0 : max_display, 0, print_asru_status, full);
12435255Sstephh 	}
12449120SStephen.Hanson@Sun.COM 	if (full || srp->fru == NULL || srp->asru == NULL) {
12455255Sstephh 		if (srp->resource) {
124610656SStephen.Hanson@Sun.COM 			status = asru_same_status(srp->resource);
124710656SStephen.Hanson@Sun.COM 			if (status != -1) {
124810656SStephen.Hanson@Sun.COM 				print_name_list(srp->resource,
1249*12618SStephen.Hanson@Sun.COM 				    dgettext("FMD", "Problem in  :"),
125010656SStephen.Hanson@Sun.COM 				    full ? 0 : max_display, 0, NULL, full);
125110656SStephen.Hanson@Sun.COM 				print_rsrc_status(status, "             ");
125210656SStephen.Hanson@Sun.COM 			} else
125310656SStephen.Hanson@Sun.COM 				print_name_list(srp->resource,
125410656SStephen.Hanson@Sun.COM 				    dgettext("FMD", "Problem in  :"),
1255*12618SStephen.Hanson@Sun.COM 				    full ? 0 : max_display, 0,
125610656SStephen.Hanson@Sun.COM 				    print_rsrc_status, full);
12575255Sstephh 		}
12585255Sstephh 	}
12595255Sstephh 	if (srp->fru) {
12606228Sstephh 		status = asru_same_status(srp->fru);
12616228Sstephh 		if (status != -1) {
12626228Sstephh 			print_name_list(srp->fru, dgettext("FMD",
1263*12618SStephen.Hanson@Sun.COM 			    "FRU         :"), 0,
12646228Sstephh 			    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
12656228Sstephh 			    NULL, full);
12666228Sstephh 			print_fru_status(status, "             ");
12676228Sstephh 		} else
12686228Sstephh 			print_name_list(srp->fru, dgettext("FMD",
1269*12618SStephen.Hanson@Sun.COM 			    "FRU         :"), 0,
12706228Sstephh 			    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
12716228Sstephh 			    print_fru_status, full);
12725255Sstephh 	}
12735255Sstephh 	if (srp->serial && !serial_in_fru(srp->fru, srp->serial) &&
12745255Sstephh 	    !serial_in_fru(srp->asru, srp->serial)) {
12755255Sstephh 		print_name_list(srp->serial, dgettext("FMD", "Serial ID.  :"),
1276*12618SStephen.Hanson@Sun.COM 		    0, 0, NULL, full);
12775255Sstephh 	}
127810234SRobert.Johnston@Sun.COM 	print_dict_info(srp->uurec->event);
12795255Sstephh 	(void) printf("\n");
12805255Sstephh }
12815255Sstephh 
12825255Sstephh static void
print_status_record(status_record_t * srp,int summary,int opt_i,int full)12835255Sstephh print_status_record(status_record_t *srp, int summary, int opt_i, int full)
12845255Sstephh {
12855255Sstephh 	char buf[32];
12865255Sstephh 	uurec_t *uurp = srp->uurec;
12875255Sstephh 	static int header = 0;
12885255Sstephh 	char *head;
12895255Sstephh 	ari_list_t *ari_list;
12905255Sstephh 
12915255Sstephh 	if (!summary || !header) {
12925255Sstephh 		if (opt_i) {
12935255Sstephh 			head = "--------------- "
12945255Sstephh 			    "------------------------------------  "
12955255Sstephh 			    "-------------- ---------\n"
12965255Sstephh 			    "TIME            CACHE-ID"
12975255Sstephh 			    "                              MSG-ID"
12985255Sstephh 			    "         SEVERITY\n--------------- "
12995255Sstephh 			    "------------------------------------ "
13005255Sstephh 			    " -------------- ---------";
13015255Sstephh 		} else {
13025255Sstephh 			head = "--------------- "
13035255Sstephh 			    "------------------------------------  "
13045255Sstephh 			    "-------------- ---------\n"
13055255Sstephh 			    "TIME            EVENT-ID"
13065255Sstephh 			    "                              MSG-ID"
13075255Sstephh 			    "         SEVERITY\n--------------- "
13085255Sstephh 			    "------------------------------------ "
13095255Sstephh 			    " -------------- ---------";
13105255Sstephh 		}
13115255Sstephh 		(void) printf("%s\n", dgettext("FMD", head));
13125255Sstephh 		header = 1;
13135255Sstephh 	}
13145255Sstephh 	if (opt_i) {
13155255Sstephh 		ari_list = uurp->ari_uuid_list;
13165255Sstephh 		while (ari_list) {
131710928SStephen.Hanson@Sun.COM 			(void) printf("%-15s %-37s %-14s %-9s %s\n",
13185255Sstephh 			    format_date(buf, sizeof (buf), uurp->sec),
131910928SStephen.Hanson@Sun.COM 			    ari_list->ari_uuid, srp->msgid, srp->severity,
132010928SStephen.Hanson@Sun.COM 			    srp->injected ? dgettext("FMD", "injected") : "");
13215255Sstephh 			ari_list = ari_list->next;
13225255Sstephh 		}
13235255Sstephh 	} else {
132410928SStephen.Hanson@Sun.COM 		(void) printf("%-15s %-37s %-14s %-9s %s\n",
13255255Sstephh 		    format_date(buf, sizeof (buf), uurp->sec),
132610928SStephen.Hanson@Sun.COM 		    uurp->uuid, srp->msgid, srp->severity,
132710928SStephen.Hanson@Sun.COM 		    srp->injected ? dgettext("FMD", "injected") : "");
13285255Sstephh 	}
13295255Sstephh 
13305255Sstephh 	if (!summary)
13315255Sstephh 		print_sup_record(srp, opt_i, full);
13325255Sstephh }
13335255Sstephh 
13345255Sstephh static void
print_catalog(int summary,int opt_a,int full,int opt_i,int page_feed)13355255Sstephh print_catalog(int summary, int opt_a, int full, int opt_i, int page_feed)
13365255Sstephh {
13375255Sstephh 	status_record_t *srp;
13385255Sstephh 	sr_list_t *slp;
13395255Sstephh 
13405255Sstephh 	slp = status_rec_list;
13415255Sstephh 	if (slp) {
13425255Sstephh 		for (;;) {
13435255Sstephh 			srp = slp->status_record;
13445255Sstephh 			if (opt_a || srp->not_suppressed) {
13455255Sstephh 				if (page_feed)
13465255Sstephh 					(void) printf("\f\n");
13475255Sstephh 				print_status_record(srp, summary, opt_i, full);
13485255Sstephh 			}
13495255Sstephh 			if (slp->next == status_rec_list)
13505255Sstephh 				break;
13515255Sstephh 			slp = slp->next;
13525255Sstephh 		}
13535255Sstephh 	}
13545255Sstephh }
13555255Sstephh 
13565255Sstephh static name_list_t *
find_fru(status_record_t * srp,char * resource)13575255Sstephh find_fru(status_record_t *srp, char *resource)
13585255Sstephh {
13595255Sstephh 	name_list_t *rt = NULL;
13605255Sstephh 	name_list_t *fru = srp->fru;
13615255Sstephh 
13625255Sstephh 	while (fru) {
13635255Sstephh 		if (strcmp(resource, fru->name) == 0) {
13645255Sstephh 			rt = fru;
13655255Sstephh 			break;
13665255Sstephh 		}
13675255Sstephh 		fru = fru->next;
13685255Sstephh 		if (fru == srp->fru)
13695255Sstephh 			break;
13705255Sstephh 	}
13715255Sstephh 	return (rt);
13725255Sstephh }
13735255Sstephh 
13745255Sstephh static void
print_fru_line(name_list_t * fru,char * uuid)13755255Sstephh print_fru_line(name_list_t *fru, char *uuid)
13765255Sstephh {
13775255Sstephh 	if (fru->pct == 100) {
13785255Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
13795255Sstephh 		    dgettext("FMD", "suspects in this FRU total certainty"),
13805255Sstephh 		    100);
13815255Sstephh 	} else {
13825255Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
13835255Sstephh 		    dgettext("FMD", "suspects in this FRU max certainty"),
13845255Sstephh 		    fru->max_pct);
13855255Sstephh 	}
13865255Sstephh }
13875255Sstephh 
13885255Sstephh static void
print_fru(int summary,int opt_a,int opt_i,int page_feed)13895255Sstephh print_fru(int summary, int opt_a, int opt_i, int page_feed)
13905255Sstephh {
13915255Sstephh 	resource_list_t *tp = status_fru_list;
13925255Sstephh 	status_record_t *srp;
13935255Sstephh 	sr_list_t *slp, *end;
13945255Sstephh 	uurec_t *uurp;
13955255Sstephh 	name_list_t *fru;
13966228Sstephh 	int status;
13975255Sstephh 	ari_list_t *ari_list;
13985255Sstephh 
13995255Sstephh 	while (tp) {
14005255Sstephh 		if (opt_a || tp->not_suppressed) {
14015255Sstephh 			if (page_feed)
14025255Sstephh 				(void) printf("\f\n");
14035255Sstephh 			if (!summary)
14045255Sstephh 				(void) printf("-----------------------------"
14055255Sstephh 				    "---------------------------------------"
14065255Sstephh 				    "----------\n");
14076002Sstephh 			slp = tp->status_rec_list;
14086002Sstephh 			end = slp;
14096002Sstephh 			do {
14106002Sstephh 				srp = slp->status_record;
141111416SStephen.Hanson@Sun.COM 				if (!srp->not_suppressed) {
141211416SStephen.Hanson@Sun.COM 					slp = slp->next;
141311416SStephen.Hanson@Sun.COM 					continue;
141411416SStephen.Hanson@Sun.COM 				}
14156002Sstephh 				fru = find_fru(srp, tp->resource);
14166002Sstephh 				if (fru) {
14176002Sstephh 					if (fru->label)
14186228Sstephh 						(void) printf("\"%s\" (%s) ",
14196002Sstephh 						    fru->label, fru->name);
1420*12618SStephen.Hanson@Sun.COM 					else
14216228Sstephh 						(void) printf("%s ",
14226002Sstephh 						    fru->name);
14236002Sstephh 					break;
14246002Sstephh 				}
14256002Sstephh 				slp = slp->next;
14266002Sstephh 			} while (slp != end);
14276002Sstephh 
14285255Sstephh 			slp = tp->status_rec_list;
14295255Sstephh 			end = slp;
14306228Sstephh 			status = 0;
14316228Sstephh 			do {
14326228Sstephh 				srp = slp->status_record;
143311416SStephen.Hanson@Sun.COM 				if (!srp->not_suppressed) {
143411416SStephen.Hanson@Sun.COM 					slp = slp->next;
143511416SStephen.Hanson@Sun.COM 					continue;
143611416SStephen.Hanson@Sun.COM 				}
14376228Sstephh 				fru = srp->fru;
14386228Sstephh 				while (fru) {
14396228Sstephh 					if (strcmp(tp->resource,
14406228Sstephh 					    fru->name) == 0)
14416228Sstephh 						status |= fru->status;
14426228Sstephh 					fru = fru->next;
14436228Sstephh 					if (fru == srp->fru)
14446228Sstephh 						break;
14456228Sstephh 				}
14466228Sstephh 				slp = slp->next;
14476228Sstephh 			} while (slp != end);
14486228Sstephh 			if (status & FM_SUSPECT_NOT_PRESENT)
144910928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "not present"));
14506228Sstephh 			else if (status & FM_SUSPECT_FAULTY)
145110928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "faulty"));
14527275Sstephh 			else if (status & FM_SUSPECT_REPLACED)
145310928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "replaced"));
14547275Sstephh 			else if (status & FM_SUSPECT_REPAIRED)
14557275Sstephh 				(void) printf(dgettext("FMD",
145610928SStephen.Hanson@Sun.COM 				    "repair attempted"));
14577275Sstephh 			else if (status & FM_SUSPECT_ACQUITTED)
145810928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "acquitted"));
14596228Sstephh 			else
146010928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "removed"));
146110928SStephen.Hanson@Sun.COM 
146210928SStephen.Hanson@Sun.COM 			if (tp->injected)
146310928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", " injected\n"));
146410928SStephen.Hanson@Sun.COM 			else
146510928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "\n"));
14666228Sstephh 
14676228Sstephh 			slp = tp->status_rec_list;
14686228Sstephh 			end = slp;
14695255Sstephh 			do {
14705255Sstephh 				srp = slp->status_record;
147111416SStephen.Hanson@Sun.COM 				if (!srp->not_suppressed) {
147211416SStephen.Hanson@Sun.COM 					slp = slp->next;
147311416SStephen.Hanson@Sun.COM 					continue;
147411416SStephen.Hanson@Sun.COM 				}
14755255Sstephh 				uurp = srp->uurec;
14765255Sstephh 				fru = find_fru(srp, tp->resource);
14775255Sstephh 				if (fru) {
14785255Sstephh 					if (opt_i) {
14795255Sstephh 						ari_list = uurp->ari_uuid_list;
14805255Sstephh 						while (ari_list) {
14815255Sstephh 							print_fru_line(fru,
14825255Sstephh 							    ari_list->ari_uuid);
14835255Sstephh 							ari_list =
14845255Sstephh 							    ari_list->next;
14855255Sstephh 						}
14865255Sstephh 					} else {
14875255Sstephh 						print_fru_line(fru, uurp->uuid);
14885255Sstephh 					}
14895255Sstephh 				}
14905255Sstephh 				slp = slp->next;
14915255Sstephh 			} while (slp != end);
14925255Sstephh 			if (!summary) {
14935255Sstephh 				slp = tp->status_rec_list;
14945255Sstephh 				end = slp;
14955255Sstephh 				do {
149611416SStephen.Hanson@Sun.COM 					srp = slp->status_record;
149711416SStephen.Hanson@Sun.COM 					if (!srp->not_suppressed) {
149811416SStephen.Hanson@Sun.COM 						slp = slp->next;
149911416SStephen.Hanson@Sun.COM 						continue;
150011416SStephen.Hanson@Sun.COM 					}
150111416SStephen.Hanson@Sun.COM 					if (srp->serial &&
150211416SStephen.Hanson@Sun.COM 					    !serial_in_fru(srp->fru,
150311416SStephen.Hanson@Sun.COM 					    srp->serial)) {
150411416SStephen.Hanson@Sun.COM 						print_name_list(srp->serial,
150511416SStephen.Hanson@Sun.COM 						    dgettext("FMD",
150611416SStephen.Hanson@Sun.COM 						    "Serial ID.  :"),
1507*12618SStephen.Hanson@Sun.COM 						    0, 0, NULL, 1);
150811416SStephen.Hanson@Sun.COM 						break;
15095255Sstephh 					}
15105255Sstephh 					slp = slp->next;
15115255Sstephh 				} while (slp != end);
15125255Sstephh 			}
15135255Sstephh 		}
15145255Sstephh 		tp = tp->next;
15155255Sstephh 		if (tp == status_fru_list)
15165255Sstephh 			break;
15175255Sstephh 	}
15185255Sstephh }
15195255Sstephh 
15205255Sstephh static void
print_asru(int opt_a)15215255Sstephh print_asru(int opt_a)
15225255Sstephh {
15235255Sstephh 	resource_list_t *tp = status_asru_list;
15245255Sstephh 	status_record_t *srp;
15255255Sstephh 	sr_list_t *slp, *end;
15265255Sstephh 	char *msg;
15275255Sstephh 	int status;
15285255Sstephh 	name_list_t *asru;
15295255Sstephh 
15305255Sstephh 	while (tp) {
15315255Sstephh 		if (opt_a || tp->not_suppressed) {
15325255Sstephh 			status = 0;
15335255Sstephh 			slp = tp->status_rec_list;
15345255Sstephh 			end = slp;
15355255Sstephh 			do {
15365255Sstephh 				srp = slp->status_record;
153711416SStephen.Hanson@Sun.COM 				if (!srp->not_suppressed) {
153811416SStephen.Hanson@Sun.COM 					slp = slp->next;
153911416SStephen.Hanson@Sun.COM 					continue;
154011416SStephen.Hanson@Sun.COM 				}
15415255Sstephh 				asru = srp->asru;
15425255Sstephh 				while (asru) {
15435255Sstephh 					if (strcmp(tp->resource,
15445255Sstephh 					    asru->name) == 0)
15455255Sstephh 						status |= asru->status;
15465255Sstephh 					asru = asru->next;
15475255Sstephh 					if (asru == srp->asru)
15485255Sstephh 						break;
15495255Sstephh 				}
15505255Sstephh 				slp = slp->next;
15515255Sstephh 			} while (slp != end);
15525255Sstephh 			switch (status) {
15535255Sstephh 			case 0:
15545255Sstephh 				msg = dgettext("FMD", "ok");
15555255Sstephh 				break;
15567275Sstephh 			case FM_SUSPECT_DEGRADED:
15577275Sstephh 				msg = dgettext("FMD", "degraded");
15587275Sstephh 				break;
15597275Sstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED:
15607275Sstephh 				msg = dgettext("FMD", "degraded");
15617275Sstephh 				break;
15625255Sstephh 			case FM_SUSPECT_FAULTY:
15635255Sstephh 				msg = dgettext("FMD", "degraded");
15645255Sstephh 				break;
15655255Sstephh 			case FM_SUSPECT_UNUSABLE:
15665255Sstephh 				msg = dgettext("FMD", "unknown");
15675255Sstephh 				break;
15685255Sstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
15695255Sstephh 				msg = dgettext("FMD", "faulted");
15705255Sstephh 				break;
15715255Sstephh 			default:
15725255Sstephh 				msg = "";
15735255Sstephh 				break;
15745255Sstephh 			}
157510928SStephen.Hanson@Sun.COM 			(void) printf("%-69s %s", tp->resource, msg);
157610928SStephen.Hanson@Sun.COM 			if (tp->injected)
157710928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", " injected\n"));
157810928SStephen.Hanson@Sun.COM 			else
157910928SStephen.Hanson@Sun.COM 				(void) printf(dgettext("FMD", "\n"));
15805255Sstephh 		}
15815255Sstephh 		tp = tp->next;
15825255Sstephh 		if (tp == status_asru_list)
15835255Sstephh 			break;
15845255Sstephh 	}
15855255Sstephh }
15865255Sstephh 
15875255Sstephh static int
uuid_in_list(char * uuid,uurec_select_t * uurecp)15885255Sstephh uuid_in_list(char *uuid, uurec_select_t *uurecp)
15895255Sstephh {
15905255Sstephh 	while (uurecp) {
15915255Sstephh 		if (strcmp(uuid, uurecp->uuid) == 0)
15925255Sstephh 			return (1);
15935255Sstephh 		uurecp = uurecp->next;
15945255Sstephh 	}
15950Sstevel@tonic-gate 	return (0);
15960Sstevel@tonic-gate }
15970Sstevel@tonic-gate 
15985255Sstephh static int
dfault_rec(const fmd_adm_caseinfo_t * acp,void * arg)15995255Sstephh dfault_rec(const fmd_adm_caseinfo_t *acp, void *arg)
16005255Sstephh {
16015255Sstephh 	int64_t *diag_time;
16025255Sstephh 	uint_t nelem;
16035255Sstephh 	int rt = 0;
16045255Sstephh 	char *uuid = "-";
16055255Sstephh 	uurec_select_t *uurecp = (uurec_select_t *)arg;
16065255Sstephh 
16075255Sstephh 	if (nvlist_lookup_int64_array(acp->aci_event, FM_SUSPECT_DIAG_TIME,
16085255Sstephh 	    &diag_time, &nelem) == 0 && nelem >= 2) {
16095255Sstephh 		(void) nvlist_lookup_string(acp->aci_event, FM_SUSPECT_UUID,
16105255Sstephh 		    &uuid);
16115255Sstephh 		if (uurecp == NULL || uuid_in_list(uuid, uurecp))
16125255Sstephh 			add_fault_record_to_catalog(acp->aci_event, *diag_time,
16139501SRobert.Johnston@Sun.COM 			    uuid);
16145255Sstephh 	} else {
16155255Sstephh 		rt = -1;
16165255Sstephh 	}
16175255Sstephh 	return (rt);
16185255Sstephh }
16195255Sstephh 
16200Sstevel@tonic-gate /*ARGSUSED*/
16210Sstevel@tonic-gate static int
dstatus_rec(const fmd_adm_rsrcinfo_t * ari,void * unused)16225255Sstephh dstatus_rec(const fmd_adm_rsrcinfo_t *ari, void *unused)
16230Sstevel@tonic-gate {
16245255Sstephh 	update_asru_state_in_catalog(ari->ari_case, ari->ari_uuid);
16250Sstevel@tonic-gate 	return (0);
16260Sstevel@tonic-gate }
16270Sstevel@tonic-gate 
16285255Sstephh static int
get_cases_from_fmd(fmd_adm_t * adm,uurec_select_t * uurecp,int opt_i)16295255Sstephh get_cases_from_fmd(fmd_adm_t *adm, uurec_select_t *uurecp, int opt_i)
16305255Sstephh {
16315255Sstephh 	int rt = FMADM_EXIT_SUCCESS;
16325255Sstephh 
16335255Sstephh 	/*
163410234SRobert.Johnston@Sun.COM 	 * These calls may fail with Protocol error if message payload is
163510234SRobert.Johnston@Sun.COM 	 * too big
16365255Sstephh 	 */
16375255Sstephh 	if (fmd_adm_case_iter(adm, NULL, dfault_rec, uurecp) != 0)
16385255Sstephh 		die("failed to get case list from fmd");
16395255Sstephh 	if (opt_i && fmd_adm_rsrc_iter(adm, 1, dstatus_rec, NULL) != 0)
16405255Sstephh 		die("failed to get case status from fmd");
16415255Sstephh 	return (rt);
16425255Sstephh }
16435255Sstephh 
16445255Sstephh /*
16455255Sstephh  * fmadm faulty command
16465255Sstephh  *
16475255Sstephh  *	-a		show hidden fault records
16485255Sstephh  *	-f		show faulty fru's
16495255Sstephh  *	-g		force grouping of similar faults on the same fru
16505255Sstephh  *	-n		number of fault records to display
16515255Sstephh  *	-p		pipe output through pager
16525255Sstephh  *	-r		show faulty asru's
16535255Sstephh  *	-s		print summary of first fault
16545255Sstephh  *	-u		print listed uuid's only
16555255Sstephh  *	-v		full output
16565255Sstephh  */
16575255Sstephh 
16580Sstevel@tonic-gate int
cmd_faulty(fmd_adm_t * adm,int argc,char * argv[])16590Sstevel@tonic-gate cmd_faulty(fmd_adm_t *adm, int argc, char *argv[])
16600Sstevel@tonic-gate {
16615255Sstephh 	int opt_a = 0, opt_v = 0, opt_p = 0, opt_s = 0, opt_r = 0, opt_f = 0;
16625255Sstephh 	int opt_i = 0;
16635255Sstephh 	char *pager;
16645255Sstephh 	FILE *fp;
16655255Sstephh 	int rt, c, stat;
16665255Sstephh 	uurec_select_t *tp;
16675255Sstephh 	uurec_select_t *uurecp = NULL;
16680Sstevel@tonic-gate 
16695255Sstephh 	while ((c = getopt(argc, argv, "afgin:prsu:v")) != EOF) {
16700Sstevel@tonic-gate 		switch (c) {
16710Sstevel@tonic-gate 		case 'a':
16720Sstevel@tonic-gate 			opt_a++;
16730Sstevel@tonic-gate 			break;
16745255Sstephh 		case 'f':
16755255Sstephh 			opt_f++;
16765255Sstephh 			break;
16775255Sstephh 		case 'g':
16785255Sstephh 			opt_g++;
16795255Sstephh 			break;
16800Sstevel@tonic-gate 		case 'i':
16815255Sstephh 			opt_i++;
16825255Sstephh 			break;
16835255Sstephh 		case 'n':
16845255Sstephh 			max_fault = atoi(optarg);
16855255Sstephh 			break;
16865255Sstephh 		case 'p':
16875255Sstephh 			opt_p++;
16885255Sstephh 			break;
16895255Sstephh 		case 'r':
16905255Sstephh 			opt_r++;
16915255Sstephh 			break;
16925255Sstephh 		case 's':
16935255Sstephh 			opt_s++;
16945255Sstephh 			break;
16955255Sstephh 		case 'u':
16965255Sstephh 			tp = (uurec_select_t *)malloc(sizeof (uurec_select_t));
16975255Sstephh 			tp->uuid = optarg;
16985255Sstephh 			tp->next = uurecp;
16995255Sstephh 			uurecp = tp;
17005255Sstephh 			opt_a = 1;
17015255Sstephh 			break;
17025255Sstephh 		case 'v':
17035255Sstephh 			opt_v++;
17040Sstevel@tonic-gate 			break;
17050Sstevel@tonic-gate 		default:
17060Sstevel@tonic-gate 			return (FMADM_EXIT_USAGE);
17070Sstevel@tonic-gate 		}
17080Sstevel@tonic-gate 	}
17090Sstevel@tonic-gate 	if (optind < argc)
17100Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
17110Sstevel@tonic-gate 
17129501SRobert.Johnston@Sun.COM 	if ((fmadm_msghdl = fmd_msg_init(NULL, FMD_MSG_VERSION)) == NULL)
17139501SRobert.Johnston@Sun.COM 		return (FMADM_EXIT_ERROR);
17145255Sstephh 	rt = get_cases_from_fmd(adm, uurecp, opt_i);
17155255Sstephh 	if (opt_p) {
17165255Sstephh 		if ((pager = getenv("PAGER")) == NULL)
17175255Sstephh 			pager = "/usr/bin/more";
17185255Sstephh 		fp = popen(pager, "w");
17195255Sstephh 		if (fp == NULL) {
17205255Sstephh 			rt = FMADM_EXIT_ERROR;
17215255Sstephh 			opt_p = 0;
17225255Sstephh 		} else {
172311050SRobert.Johnston@Sun.COM 			(void) dup2(fileno(fp), 1);
17245255Sstephh 			setbuf(stdout, NULL);
17255255Sstephh 			(void) fclose(fp);
17265255Sstephh 		}
17275255Sstephh 	}
17285255Sstephh 	max_display = max_fault;
17295255Sstephh 	if (opt_f)
17305255Sstephh 		print_fru(opt_s, opt_a, opt_i, opt_p && !opt_s);
17315255Sstephh 	if (opt_r)
17325255Sstephh 		print_asru(opt_a);
17335255Sstephh 	if (opt_f == 0 && opt_r == 0)
17345255Sstephh 		print_catalog(opt_s, opt_a, opt_v, opt_i, opt_p && !opt_s);
17359501SRobert.Johnston@Sun.COM 	fmd_msg_fini(fmadm_msghdl);
1736*12618SStephen.Hanson@Sun.COM 	if (topo_handle)
1737*12618SStephen.Hanson@Sun.COM 		topo_close(topo_handle);
17385255Sstephh 	if (opt_p) {
17395255Sstephh 		(void) fclose(stdout);
17405255Sstephh 		(void) wait(&stat);
17415255Sstephh 	}
17425255Sstephh 	return (rt);
17430Sstevel@tonic-gate }
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate int
cmd_flush(fmd_adm_t * adm,int argc,char * argv[])17460Sstevel@tonic-gate cmd_flush(fmd_adm_t *adm, int argc, char *argv[])
17470Sstevel@tonic-gate {
17480Sstevel@tonic-gate 	int i, status = FMADM_EXIT_SUCCESS;
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 	if (argc < 2 || (i = getopt(argc, argv, "")) != EOF)
17510Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate 	for (i = 1; i < argc; i++) {
17540Sstevel@tonic-gate 		if (fmd_adm_rsrc_flush(adm, argv[i]) != 0) {
17550Sstevel@tonic-gate 			warn("failed to flush %s", argv[i]);
17560Sstevel@tonic-gate 			status = FMADM_EXIT_ERROR;
17570Sstevel@tonic-gate 		} else
17580Sstevel@tonic-gate 			note("flushed resource history for %s\n", argv[i]);
17590Sstevel@tonic-gate 	}
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 	return (status);
17620Sstevel@tonic-gate }
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate int
cmd_repair(fmd_adm_t * adm,int argc,char * argv[])17650Sstevel@tonic-gate cmd_repair(fmd_adm_t *adm, int argc, char *argv[])
17660Sstevel@tonic-gate {
17670Sstevel@tonic-gate 	int err;
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 	if (getopt(argc, argv, "") != EOF)
17700Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 	if (argc - optind != 1)
17730Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	/*
17767275Sstephh 	 * argument could be a uuid, an fmri (asru, fru or resource)
17776228Sstephh 	 * or a label. Try uuid first, If that fails try the others.
17780Sstevel@tonic-gate 	 */
17796228Sstephh 	err = fmd_adm_case_repair(adm, argv[optind]);
17806228Sstephh 	if (err != 0)
17817275Sstephh 		err = fmd_adm_rsrc_repaired(adm, argv[optind]);
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 	if (err != 0)
17840Sstevel@tonic-gate 		die("failed to record repair to %s", argv[optind]);
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 	note("recorded repair to %s\n", argv[optind]);
17870Sstevel@tonic-gate 	return (FMADM_EXIT_SUCCESS);
17880Sstevel@tonic-gate }
17897275Sstephh 
17907275Sstephh int
cmd_repaired(fmd_adm_t * adm,int argc,char * argv[])17917275Sstephh cmd_repaired(fmd_adm_t *adm, int argc, char *argv[])
17927275Sstephh {
17937275Sstephh 	int err;
17947275Sstephh 
17957275Sstephh 	if (getopt(argc, argv, "") != EOF)
17967275Sstephh 		return (FMADM_EXIT_USAGE);
17977275Sstephh 
17987275Sstephh 	if (argc - optind != 1)
17997275Sstephh 		return (FMADM_EXIT_USAGE);
18007275Sstephh 
18017275Sstephh 	/*
18027275Sstephh 	 * argument could be an fmri (asru, fru or resource) or a label.
18037275Sstephh 	 */
18047275Sstephh 	err = fmd_adm_rsrc_repaired(adm, argv[optind]);
18057275Sstephh 	if (err != 0)
18067275Sstephh 		die("failed to record repair to %s", argv[optind]);
18077275Sstephh 
18087275Sstephh 	note("recorded repair to of %s\n", argv[optind]);
18097275Sstephh 	return (FMADM_EXIT_SUCCESS);
18107275Sstephh }
18117275Sstephh 
18127275Sstephh int
cmd_replaced(fmd_adm_t * adm,int argc,char * argv[])18137275Sstephh cmd_replaced(fmd_adm_t *adm, int argc, char *argv[])
18147275Sstephh {
18157275Sstephh 	int err;
18167275Sstephh 
18177275Sstephh 	if (getopt(argc, argv, "") != EOF)
18187275Sstephh 		return (FMADM_EXIT_USAGE);
18197275Sstephh 
18207275Sstephh 	if (argc - optind != 1)
18217275Sstephh 		return (FMADM_EXIT_USAGE);
18227275Sstephh 
18237275Sstephh 	/*
18247275Sstephh 	 * argument could be an fmri (asru, fru or resource) or a label.
18257275Sstephh 	 */
18267275Sstephh 	err = fmd_adm_rsrc_replaced(adm, argv[optind]);
18277275Sstephh 	if (err != 0)
18287275Sstephh 		die("failed to record replacement of %s", argv[optind]);
18297275Sstephh 
18307275Sstephh 	note("recorded replacement of %s\n", argv[optind]);
18317275Sstephh 	return (FMADM_EXIT_SUCCESS);
18327275Sstephh }
18337275Sstephh 
18347275Sstephh int
cmd_acquit(fmd_adm_t * adm,int argc,char * argv[])18357275Sstephh cmd_acquit(fmd_adm_t *adm, int argc, char *argv[])
18367275Sstephh {
18377275Sstephh 	int err;
18387275Sstephh 
18397275Sstephh 	if (getopt(argc, argv, "") != EOF)
18407275Sstephh 		return (FMADM_EXIT_USAGE);
18417275Sstephh 
18427275Sstephh 	if (argc - optind != 1 && argc - optind != 2)
18437275Sstephh 		return (FMADM_EXIT_USAGE);
18447275Sstephh 
18457275Sstephh 	/*
18467275Sstephh 	 * argument could be a uuid, an fmri (asru, fru or resource)
18477275Sstephh 	 * or a label. Or it could be a uuid and an fmri or label.
18487275Sstephh 	 */
18497275Sstephh 	if (argc - optind == 2) {
18507275Sstephh 		err = fmd_adm_rsrc_acquit(adm, argv[optind], argv[optind + 1]);
18517275Sstephh 		if (err != 0)
18527275Sstephh 			err = fmd_adm_rsrc_acquit(adm, argv[optind + 1],
18537275Sstephh 			    argv[optind]);
18547275Sstephh 	} else {
18557275Sstephh 		err = fmd_adm_case_acquit(adm, argv[optind]);
18567275Sstephh 		if (err != 0)
18577275Sstephh 			err = fmd_adm_rsrc_acquit(adm, argv[optind], "");
18587275Sstephh 	}
18597275Sstephh 
18607275Sstephh 	if (err != 0)
18617275Sstephh 		die("failed to record acquital of %s", argv[optind]);
18627275Sstephh 
18637275Sstephh 	note("recorded acquital of %s\n", argv[optind]);
18647275Sstephh 	return (FMADM_EXIT_SUCCESS);
18657275Sstephh }
1866