xref: /onnv-gate/usr/src/cmd/fm/fmadm/common/faulty.c (revision 9501:f84d3cc28d24)
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>
40*9501SRobert.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;
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;
1975255Sstephh } hostid_t;
1985255Sstephh 
1995255Sstephh typedef struct host_id_list {
2005255Sstephh 	hostid_t hostid;
2015255Sstephh 	struct host_id_list *next;
2025255Sstephh } host_id_list_t;
2035255Sstephh 
2045255Sstephh typedef struct status_record {
2055255Sstephh 	hostid_t *host;
2065255Sstephh 	int nrecs;
2075255Sstephh 	uurec_t *uurec;
2085255Sstephh 	char *severity;			/* in C locale */
2095255Sstephh 	char *msgid;
2105255Sstephh 	name_list_t *class;
2115255Sstephh 	name_list_t *resource;
2125255Sstephh 	name_list_t *asru;
2135255Sstephh 	name_list_t *fru;
2145255Sstephh 	name_list_t *serial;
2155255Sstephh 	uint8_t not_suppressed;
2165255Sstephh } status_record_t;
2175255Sstephh 
2185255Sstephh typedef struct sr_list {
2195255Sstephh 	struct sr_list *next;
2205255Sstephh 	struct sr_list *prev;
2215255Sstephh 	struct status_record *status_record;
2225255Sstephh } sr_list_t;
2235255Sstephh 
2245255Sstephh typedef struct resource_list {
2255255Sstephh 	struct resource_list *next;
2265255Sstephh 	struct resource_list *prev;
2275255Sstephh 	sr_list_t *status_rec_list;
2285255Sstephh 	char *resource;
2295255Sstephh 	uint8_t not_suppressed;
2305255Sstephh 	uint8_t max_pct;
2315255Sstephh } resource_list_t;
2325255Sstephh 
2335255Sstephh typedef struct tgetlabel_data {
2345255Sstephh 	char *label;
2355255Sstephh 	char *fru;
2365255Sstephh } tgetlabel_data_t;
2370Sstevel@tonic-gate 
2385255Sstephh sr_list_t *status_rec_list;
2395255Sstephh resource_list_t *status_fru_list;
2405255Sstephh resource_list_t *status_asru_list;
2415255Sstephh 
2425255Sstephh static int max_display;
2435255Sstephh static int max_fault = 0;
2445255Sstephh static topo_hdl_t *topo_handle;
2455255Sstephh static char *topo_handle_uuid;
2465255Sstephh static host_id_list_t *host_list;
2475255Sstephh static int n_server;
2485255Sstephh static int opt_g;
249*9501SRobert.Johnston@Sun.COM static fmd_msg_hdl_t *fmadm_msghdl = NULL; /* handle for libfmd_msg calls */
2505255Sstephh 
2515255Sstephh static char *
2525255Sstephh format_date(char *buf, size_t len, uint64_t sec)
2535255Sstephh {
2545255Sstephh 	if (sec > LONG_MAX) {
2555255Sstephh 		(void) fprintf(stderr,
2565255Sstephh 		    "record time is too large for 32-bit utility\n");
2575255Sstephh 		(void) snprintf(buf, len, "0x%llx", sec);
2585255Sstephh 	} else {
2595255Sstephh 		time_t tod = (time_t)sec;
2605255Sstephh 		(void) strftime(buf, len, "%b %d %T", localtime(&tod));
2615255Sstephh 	}
2625255Sstephh 
2635255Sstephh 	return (buf);
2645255Sstephh }
2655255Sstephh 
2665255Sstephh static hostid_t *
2679120SStephen.Hanson@Sun.COM find_hostid_in_list(char *platform, char *chassis, char *server, char *domain)
2685255Sstephh {
2695255Sstephh 	hostid_t *rt = NULL;
2705255Sstephh 	host_id_list_t *hostp;
2715255Sstephh 
2725255Sstephh 	if (platform == NULL)
2735255Sstephh 		platform = "-";
2745255Sstephh 	if (server == NULL)
2755255Sstephh 		server = "-";
2765255Sstephh 	hostp = host_list;
2775255Sstephh 	while (hostp) {
2785255Sstephh 		if (hostp->hostid.platform &&
2795255Sstephh 		    strcmp(hostp->hostid.platform, platform) == 0 &&
2805255Sstephh 		    hostp->hostid.server &&
2815255Sstephh 		    strcmp(hostp->hostid.server, server) == 0 &&
2825255Sstephh 		    (chassis == NULL || hostp->hostid.chassis == NULL ||
2839120SStephen.Hanson@Sun.COM 		    strcmp(chassis, hostp->hostid.chassis) == 0) &&
2849120SStephen.Hanson@Sun.COM 		    (domain == NULL || hostp->hostid.domain == NULL ||
2859120SStephen.Hanson@Sun.COM 		    strcmp(domain, hostp->hostid.domain) == 0)) {
2865255Sstephh 			rt = &hostp->hostid;
2875255Sstephh 			break;
2885255Sstephh 		}
2895255Sstephh 		hostp = hostp->next;
2905255Sstephh 	}
2915255Sstephh 	if (rt == NULL) {
2925255Sstephh 		hostp = malloc(sizeof (host_id_list_t));
2935255Sstephh 		hostp->hostid.platform = strdup(platform);
2945255Sstephh 		hostp->hostid.server = strdup(server);
2955255Sstephh 		hostp->hostid.chassis = chassis ? strdup(chassis) : NULL;
2969120SStephen.Hanson@Sun.COM 		hostp->hostid.domain = domain ? strdup(domain) : NULL;
2975255Sstephh 		hostp->next = host_list;
2985255Sstephh 		host_list = hostp;
2995255Sstephh 		rt = &hostp->hostid;
3005255Sstephh 		n_server++;
3015255Sstephh 	}
3025255Sstephh 	return (rt);
3035255Sstephh }
3045255Sstephh 
3055255Sstephh static hostid_t *
3065255Sstephh find_hostid(nvlist_t *nvl)
3075255Sstephh {
3089120SStephen.Hanson@Sun.COM 	char *platform = NULL, *chassis = NULL, *server = NULL, *domain = NULL;
3095255Sstephh 	nvlist_t *auth, *fmri;
3105255Sstephh 	hostid_t *rt = NULL;
3115255Sstephh 
3125255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &fmri) == 0 &&
3135255Sstephh 	    nvlist_lookup_nvlist(fmri, FM_FMRI_AUTHORITY, &auth) == 0) {
3145255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT,
3155255Sstephh 		    &platform);
3165255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server);
3175255Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS,
3185255Sstephh 		    &chassis);
3199120SStephen.Hanson@Sun.COM 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_DOMAIN, &domain);
3209120SStephen.Hanson@Sun.COM 		rt = find_hostid_in_list(platform, chassis, server, domain);
3215255Sstephh 	}
3225255Sstephh 	return (rt);
3235255Sstephh }
3245255Sstephh 
3255255Sstephh /*
3265255Sstephh  * compare two fru strings which are made up of substrings seperated by '/'
3275255Sstephh  * return true if every substring is the same in the two strings, or if a
3285255Sstephh  * substring is null in one.
3295255Sstephh  */
3305255Sstephh 
3315255Sstephh static int
3325255Sstephh frucmp(char *f1, char *f2)
3335255Sstephh {
3345255Sstephh 	char c1, c2;
3355255Sstephh 	int i = 0;
3365255Sstephh 
3375255Sstephh 	for (;;) {
3385255Sstephh 		c1 = *f1;
3395255Sstephh 		c2 = *f2;
3405255Sstephh 		if (c1 == c2) {
3415255Sstephh 			i = (c1 == '/') ? 0 : i + 1;
3425255Sstephh 		} else if (i == 0) {
3435255Sstephh 			if (c1 == '/') {
3445255Sstephh 				do {
3455255Sstephh 					f2++;
3465255Sstephh 				} while ((c2 = *f2) != 0 && c2 != '/');
3475255Sstephh 				if (c2 == NULL)
3485255Sstephh 					break;
3495255Sstephh 			} else if (c2 == '/') {
3505255Sstephh 				do {
3515255Sstephh 					f1++;
3525255Sstephh 				} while ((c1 = *f1) != 0 && c1 != '/');
3535255Sstephh 				if (c1 == NULL)
3545255Sstephh 					break;
3555255Sstephh 			} else
3565255Sstephh 				break;
3575255Sstephh 		} else
3585255Sstephh 			break;
3595255Sstephh 		if (c1 == NULL)
3605255Sstephh 			return (0);
3615255Sstephh 		f1++;
3625255Sstephh 		f2++;
3635255Sstephh 	}
3645255Sstephh 	return (1);
3655255Sstephh }
3665255Sstephh 
3675255Sstephh static int
3685255Sstephh tgetlabel(topo_hdl_t *thp, tnode_t *node, void *arg)
3690Sstevel@tonic-gate {
3705255Sstephh 	int err;
3715255Sstephh 	char *fru_name, *lname;
3725255Sstephh 	nvlist_t *fru = NULL;
3735255Sstephh 	int rt = TOPO_WALK_NEXT;
3745255Sstephh 	tgetlabel_data_t *tdp = (tgetlabel_data_t *)arg;
3755255Sstephh 
3765255Sstephh 	if (topo_node_fru(node, &fru, NULL, &err) == 0) {
3775255Sstephh 		if (topo_fmri_nvl2str(thp, fru, &fru_name, &err) == 0) {
3785255Sstephh 			if (frucmp(tdp->fru, fru_name) == 0 &&
3795255Sstephh 			    topo_node_label(node, &lname, &err) == 0) {
3805255Sstephh 				tdp->label = strdup(lname);
3815255Sstephh 				topo_hdl_strfree(thp, lname);
3825255Sstephh 				rt = TOPO_WALK_TERMINATE;
3835255Sstephh 			}
3845255Sstephh 			topo_hdl_strfree(thp, fru_name);
3855255Sstephh 		}
3865255Sstephh 		nvlist_free(fru);
3875255Sstephh 	}
3885255Sstephh 	return (rt);
3895255Sstephh }
3905255Sstephh 
3915255Sstephh static void
3925255Sstephh label_get_topo(void)
3935255Sstephh {
3945255Sstephh 	int err;
3955255Sstephh 
3965255Sstephh 	topo_handle = topo_open(TOPO_VERSION, 0, &err);
3975255Sstephh 	if (topo_handle) {
3985255Sstephh 		topo_handle_uuid = topo_snap_hold(topo_handle, NULL, &err);
3995255Sstephh 	}
4005255Sstephh }
4015255Sstephh 
4025255Sstephh static void
4035255Sstephh label_release_topo(void)
4045255Sstephh {
4055255Sstephh 	if (topo_handle_uuid)
4065255Sstephh 		topo_hdl_strfree(topo_handle, topo_handle_uuid);
4075255Sstephh 	if (topo_handle) {
4085255Sstephh 		topo_snap_release(topo_handle);
4095255Sstephh 		topo_close(topo_handle);
4105255Sstephh 	}
4115255Sstephh }
4125255Sstephh 
4135255Sstephh static char *
4145255Sstephh get_fmri_label(char *fru)
4155255Sstephh {
4165255Sstephh 	topo_walk_t *twp;
4175255Sstephh 	tgetlabel_data_t td;
4185255Sstephh 	int err;
4195255Sstephh 
4205255Sstephh 	td.label = NULL;
4215255Sstephh 	td.fru = fru;
4225255Sstephh 	if (topo_handle == NULL)
4235255Sstephh 		label_get_topo();
4245255Sstephh 	if (topo_handle_uuid) {
4255255Sstephh 		twp = topo_walk_init(topo_handle, FM_FMRI_SCHEME_HC,
4265255Sstephh 		    tgetlabel, &td, &err);
4275255Sstephh 		if (twp) {
4285255Sstephh 			topo_walk_step(twp, TOPO_WALK_CHILD);
4295255Sstephh 			topo_walk_fini(twp);
4305255Sstephh 		}
4315255Sstephh 	}
4325255Sstephh 	return (td.label);
4335255Sstephh }
4345255Sstephh 
4355255Sstephh static char *
4365255Sstephh get_nvl2str_topo(nvlist_t *nvl)
4375255Sstephh {
4385255Sstephh 	char *name = NULL;
4395255Sstephh 	char *tname;
4405255Sstephh 	int err;
4415255Sstephh 	char *scheme = NULL;
4425255Sstephh 	char *mod_name = NULL;
4435255Sstephh 	char buf[128];
4445255Sstephh 
4455255Sstephh 	if (topo_handle == NULL)
4465255Sstephh 		label_get_topo();
4475255Sstephh 	if (topo_fmri_nvl2str(topo_handle, nvl, &tname, &err) == 0) {
4485255Sstephh 		name = strdup(tname);
4495255Sstephh 		topo_hdl_strfree(topo_handle, tname);
4505255Sstephh 	} else {
4515255Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme);
4525255Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_MOD_NAME, &mod_name);
4535255Sstephh 		if (scheme && strcmp(scheme, FM_FMRI_SCHEME_FMD) == 0 &&
4545255Sstephh 		    mod_name) {
4555255Sstephh 			(void) snprintf(buf, sizeof (buf), "%s:///module/%s",
4565255Sstephh 			    scheme, mod_name);
4575255Sstephh 			name = strdup(buf);
4585255Sstephh 		}
4595255Sstephh 	}
4605255Sstephh 	return (name);
4615255Sstephh }
4625255Sstephh 
4635255Sstephh static int
4645255Sstephh set_priority(char *s)
4655255Sstephh {
4665255Sstephh 	int rt = 0;
4675255Sstephh 
4685255Sstephh 	if (s) {
4695255Sstephh 		if (strcmp(s, "Minor") == 0)
4705255Sstephh 			rt = 1;
4715255Sstephh 		else if (strcmp(s, "Major") == 0)
4725255Sstephh 			rt = 10;
4735255Sstephh 		else if (strcmp(s, "Critical") == 0)
4745255Sstephh 			rt = 100;
4755255Sstephh 	}
4765255Sstephh 	return (rt);
4775255Sstephh }
4785255Sstephh 
4795255Sstephh static int
4805255Sstephh cmp_priority(char *s1, char *s2, uint64_t t1, uint64_t t2, uint8_t p1,
4815255Sstephh     uint8_t p2)
4825255Sstephh {
4835255Sstephh 	int r1, r2;
4845255Sstephh 	int rt;
4855255Sstephh 
4865255Sstephh 	r1 = set_priority(s1);
4875255Sstephh 	r2 = set_priority(s2);
4885255Sstephh 	rt = r1 - r2;
4895255Sstephh 	if (rt == 0) {
4905255Sstephh 		if (t1 > t2)
4915255Sstephh 			rt = 1;
4925255Sstephh 		else if (t1 < t2)
4935255Sstephh 			rt = -1;
4945255Sstephh 		else
4955255Sstephh 			rt = p1 - p2;
4965255Sstephh 	}
4975255Sstephh 	return (rt);
4985255Sstephh }
4995255Sstephh 
5005255Sstephh /*
5015255Sstephh  * merge two lists into one, by comparing enties in new and moving into list if
5025255Sstephh  * name is not there or free off memory for names which are already there
5035255Sstephh  * add_pct indicates if pct is the sum or highest pct
5045255Sstephh  */
5055255Sstephh static name_list_t *
5065255Sstephh merge_name_list(name_list_t **list, name_list_t *new, int add_pct)
5075255Sstephh {
5085255Sstephh 	name_list_t *lp, *np, *sp, *rt = NULL;
5095255Sstephh 	int max_pct;
5105255Sstephh 
5115255Sstephh 	rt = *list;
5125255Sstephh 	np = new;
5135255Sstephh 	while (np) {
5145255Sstephh 		lp = *list;
5155255Sstephh 		while (lp) {
5165255Sstephh 			if (strcmp(lp->name, np->name) == 0)
5175255Sstephh 				break;
5185255Sstephh 			lp = lp->next;
5195255Sstephh 			if (lp == *list)
5205255Sstephh 				lp = NULL;
5215255Sstephh 		}
5225255Sstephh 		if (np->next == new)
5235255Sstephh 			sp = NULL;
5245255Sstephh 		else
5255255Sstephh 			sp = np->next;
5265255Sstephh 		if (lp) {
5275255Sstephh 			lp->status |= (np->status & FM_SUSPECT_FAULTY);
5285255Sstephh 			if (add_pct) {
5295255Sstephh 				lp->pct += np->pct;
5305255Sstephh 				lp->count += np->count;
5315255Sstephh 			} else if (np->pct > lp->pct) {
5325255Sstephh 				lp->pct = np->pct;
5335255Sstephh 			}
5345255Sstephh 			max_pct = np->max_pct;
5356002Sstephh 			if (np->label)
5366002Sstephh 				free(np->label);
5375255Sstephh 			free(np->name);
5385255Sstephh 			free(np);
5395255Sstephh 			np = NULL;
5405255Sstephh 			if (max_pct > lp->max_pct) {
5415255Sstephh 				lp->max_pct = max_pct;
5425255Sstephh 				if (lp->max_pct > lp->prev->max_pct &&
5435255Sstephh 				    lp != *list) {
5445255Sstephh 					lp->prev->next = lp->next;
5455255Sstephh 					lp->next->prev = lp->prev;
5465255Sstephh 					np = lp;
5475255Sstephh 				}
5485255Sstephh 			}
5495255Sstephh 		}
5505255Sstephh 		if (np) {
5515255Sstephh 			lp = *list;
5525255Sstephh 			if (lp) {
5535255Sstephh 				if (np->max_pct > lp->max_pct) {
5545255Sstephh 					np->next = lp;
5555255Sstephh 					np->prev = lp->prev;
5565255Sstephh 					lp->prev->next = np;
5575255Sstephh 					lp->prev = np;
5585255Sstephh 					*list = np;
5595255Sstephh 					rt = np;
5605255Sstephh 				} else {
5615255Sstephh 					lp = lp->next;
5625255Sstephh 					while (lp != *list &&
5635255Sstephh 					    np->max_pct < lp->max_pct) {
5645255Sstephh 						lp = lp->next;
5655255Sstephh 					}
5665255Sstephh 					np->next = lp;
5675255Sstephh 					np->prev = lp->prev;
5685255Sstephh 					lp->prev->next = np;
5695255Sstephh 					lp->prev = np;
5705255Sstephh 				}
5715255Sstephh 			} else {
5725255Sstephh 				*list = np;
5735255Sstephh 				np->next = np;
5745255Sstephh 				np->prev = np;
5755255Sstephh 				rt = np;
5765255Sstephh 			}
5775255Sstephh 		}
5785255Sstephh 		np = sp;
5795255Sstephh 	}
5805255Sstephh 	return (rt);
5815255Sstephh }
5825255Sstephh 
5835255Sstephh /*
5845255Sstephh  * compare entries in two lists return true if the two lists have identical
5855255Sstephh  * content. The two lists may not have entries in the same order, so we compare
5865255Sstephh  * the size of the list as well as trying to find every entry from one list in
5875255Sstephh  * the other.
5885255Sstephh  */
5895255Sstephh static int
5905255Sstephh cmp_name_list(name_list_t *lxp1, name_list_t *lxp2)
5915255Sstephh {
5925255Sstephh 	name_list_t *lp1, *lp2;
5935255Sstephh 	int l1 = 0, l2 = 0, common = 0;
5945255Sstephh 
5955255Sstephh 	lp2 = lxp2;
5965255Sstephh 	while (lp2) {
5975255Sstephh 		l2++;
5985255Sstephh 		lp2 = lp2->next;
5995255Sstephh 		if (lp2 == lxp2)
6005255Sstephh 			break;
6015255Sstephh 	}
6025255Sstephh 	lp1 = lxp1;
6035255Sstephh 	while (lp1) {
6045255Sstephh 		l1++;
6055255Sstephh 		lp2 = lxp2;
6065255Sstephh 		while (lp2) {
6075255Sstephh 			if (strcmp(lp2->name, lp1->name) == 0) {
6085255Sstephh 				common++;
6095255Sstephh 				break;
6105255Sstephh 			}
6115255Sstephh 			lp2 = lp2->next;
6125255Sstephh 			if (lp2 == lxp2)
6135255Sstephh 				break;
6145255Sstephh 		}
6155255Sstephh 		lp1 = lp1->next;
6165255Sstephh 		if (lp1 == lxp1)
6175255Sstephh 			break;
6185255Sstephh 	}
6195255Sstephh 	if (l1 == l2 && l2 == common)
6205255Sstephh 		return (0);
6215255Sstephh 	else
6225255Sstephh 		return (1);
6235255Sstephh }
6245255Sstephh 
6255255Sstephh static name_list_t *
6265255Sstephh alloc_name_list(char *name, uint8_t pct)
6275255Sstephh {
6285255Sstephh 	name_list_t *nlp;
6295255Sstephh 
6305255Sstephh 	nlp = malloc(sizeof (*nlp));
6315255Sstephh 	nlp->name = strdup(name);
6325255Sstephh 	nlp->pct = pct;
6335255Sstephh 	nlp->max_pct = pct;
6345255Sstephh 	nlp->count = 1;
6355255Sstephh 	nlp->next = nlp;
6365255Sstephh 	nlp->prev = nlp;
6375255Sstephh 	nlp->status = 0;
6386002Sstephh 	nlp->label = NULL;
6395255Sstephh 	return (nlp);
6405255Sstephh }
6415255Sstephh 
6425255Sstephh static void
6435255Sstephh free_name_list(name_list_t *list)
6445255Sstephh {
6455255Sstephh 	name_list_t *next = list;
6465255Sstephh 	name_list_t *lp;
6475255Sstephh 
6485255Sstephh 	if (list) {
6495255Sstephh 		do {
6505255Sstephh 			lp = next;
6515255Sstephh 			next = lp->next;
6526002Sstephh 			if (lp->label)
6536002Sstephh 				free(lp->label);
6545255Sstephh 			free(lp->name);
6555255Sstephh 			free(lp);
6565255Sstephh 		} while (next != list);
6575255Sstephh 	}
6585255Sstephh }
6595255Sstephh 
6605255Sstephh static status_record_t *
6615255Sstephh new_record_init(uurec_t *uurec_p, char *msgid, name_list_t *class,
6625255Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
663*9501SRobert.Johnston@Sun.COM     name_list_t *serial, boolean_t not_suppressed,
6645255Sstephh     hostid_t *hostid)
6655255Sstephh {
6665255Sstephh 	status_record_t *status_rec_p;
6675255Sstephh 
6685255Sstephh 	status_rec_p = (status_record_t *)malloc(sizeof (status_record_t));
6695255Sstephh 	status_rec_p->nrecs = 1;
6705255Sstephh 	status_rec_p->host = hostid;
6715255Sstephh 	status_rec_p->uurec = uurec_p;
6725255Sstephh 	uurec_p->next = NULL;
6735255Sstephh 	uurec_p->prev = NULL;
6745255Sstephh 	uurec_p->asru = asru;
675*9501SRobert.Johnston@Sun.COM 	if ((status_rec_p->severity = fmd_msg_getitem_id(fmadm_msghdl, NULL,
676*9501SRobert.Johnston@Sun.COM 	    msgid, FMD_MSG_ITEM_SEVERITY)) == NULL)
677*9501SRobert.Johnston@Sun.COM 		status_rec_p->severity = strdup("unknown");
6785255Sstephh 	status_rec_p->class = class;
6795255Sstephh 	status_rec_p->fru = fru;
6805255Sstephh 	status_rec_p->asru = asru;
6815255Sstephh 	status_rec_p->resource = resource;
6825255Sstephh 	status_rec_p->serial = serial;
6835255Sstephh 	status_rec_p->msgid = strdup(msgid);
6845255Sstephh 	status_rec_p->not_suppressed = not_suppressed;
6855255Sstephh 	return (status_rec_p);
6865255Sstephh }
6875255Sstephh 
6885255Sstephh /*
6895255Sstephh  * add record to given list maintaining order higher priority first.
6905255Sstephh  */
6915255Sstephh static void
6925255Sstephh add_rec_list(status_record_t *status_rec_p, sr_list_t **list_pp)
6935255Sstephh {
6945255Sstephh 	sr_list_t *tp, *np, *sp;
6955255Sstephh 	int order;
6965255Sstephh 	uint64_t sec;
6975255Sstephh 
6985255Sstephh 	np = malloc(sizeof (sr_list_t));
6995255Sstephh 	np->status_record = status_rec_p;
7005255Sstephh 	sec = status_rec_p->uurec->sec;
7015255Sstephh 	if ((sp = *list_pp) == NULL) {
7025255Sstephh 		*list_pp = np;
7035255Sstephh 		np->next = np;
7045255Sstephh 		np->prev = np;
7055255Sstephh 	} else {
7065255Sstephh 		/* insert new record in front of lower priority */
7075255Sstephh 		tp = sp;
7085255Sstephh 		order = cmp_priority(status_rec_p->severity,
7095255Sstephh 		    sp->status_record->severity, sec,
7105255Sstephh 		    tp->status_record->uurec->sec, 0, 0);
7115255Sstephh 		if (order > 0) {
7125255Sstephh 			*list_pp = np;
7135255Sstephh 		} else {
7145255Sstephh 			tp = sp->next;
7155255Sstephh 			while (tp != sp &&
7165255Sstephh 			    cmp_priority(status_rec_p->severity,
7175255Sstephh 			    tp->status_record->severity, sec,
7185255Sstephh 			    tp->status_record->uurec->sec, 0, 0)) {
7195255Sstephh 				tp = tp->next;
7205255Sstephh 			}
7215255Sstephh 		}
7225255Sstephh 		np->next = tp;
7235255Sstephh 		np->prev = tp->prev;
7245255Sstephh 		tp->prev->next = np;
7255255Sstephh 		tp->prev = np;
7265255Sstephh 	}
7275255Sstephh }
7285255Sstephh 
7295255Sstephh static void
7305255Sstephh add_resource(status_record_t *status_rec_p, resource_list_t **rp,
7315255Sstephh     resource_list_t *np)
7325255Sstephh {
7335255Sstephh 	int order;
7345255Sstephh 	uint64_t sec;
7355255Sstephh 	resource_list_t *sp, *tp;
7365255Sstephh 	status_record_t *srp;
7375255Sstephh 	char *severity = status_rec_p->severity;
7385255Sstephh 
7395255Sstephh 	add_rec_list(status_rec_p, &np->status_rec_list);
7405255Sstephh 	if ((sp = *rp) == NULL) {
7415255Sstephh 		np->next = np;
7425255Sstephh 		np->prev = np;
7435255Sstephh 		*rp = np;
7445255Sstephh 	} else {
7455255Sstephh 		/*
7465255Sstephh 		 * insert new record in front of lower priority
7475255Sstephh 		 */
7485255Sstephh 		tp = sp->next;
7495255Sstephh 		srp = sp->status_rec_list->status_record;
7505255Sstephh 		sec = status_rec_p->uurec->sec;
7515255Sstephh 		order = cmp_priority(severity, srp->severity, sec,
7525255Sstephh 		    srp->uurec->sec, np->max_pct, sp->max_pct);
7535255Sstephh 		if (order > 0) {
7545255Sstephh 			*rp = np;
7555255Sstephh 		} else {
7565255Sstephh 			srp = tp->status_rec_list->status_record;
7575255Sstephh 			while (tp != sp &&
7585255Sstephh 			    cmp_priority(severity, srp->severity, sec,
7595255Sstephh 			    srp->uurec->sec, np->max_pct, sp->max_pct) < 0) {
7605255Sstephh 				tp = tp->next;
7615255Sstephh 				srp = tp->status_rec_list->status_record;
7625255Sstephh 			}
7635255Sstephh 		}
7645255Sstephh 		np->next = tp;
7655255Sstephh 		np->prev = tp->prev;
7665255Sstephh 		tp->prev->next = np;
7675255Sstephh 		tp->prev = np;
7685255Sstephh 	}
7695255Sstephh }
7705255Sstephh 
7715255Sstephh static void
7725255Sstephh add_resource_list(status_record_t *status_rec_p, name_list_t *fp,
7735255Sstephh     resource_list_t **rpp)
7745255Sstephh {
7755255Sstephh 	int order;
7765255Sstephh 	resource_list_t *np, *end;
7775255Sstephh 	status_record_t *srp;
7785255Sstephh 
7795255Sstephh 	np = *rpp;
7805255Sstephh 	end = np;
7815255Sstephh 	while (np) {
7825255Sstephh 		if (strcmp(fp->name, np->resource) == 0) {
7835255Sstephh 			np->not_suppressed |= status_rec_p->not_suppressed;
7845255Sstephh 			srp = np->status_rec_list->status_record;
7855255Sstephh 			order = cmp_priority(status_rec_p->severity,
7865255Sstephh 			    srp->severity, status_rec_p->uurec->sec,
7875255Sstephh 			    srp->uurec->sec, fp->max_pct, np->max_pct);
7885255Sstephh 			if (order > 0 && np != end) {
7895255Sstephh 				/*
7905255Sstephh 				 * remove from list and add again using
7915255Sstephh 				 * new priority
7925255Sstephh 				 */
7935255Sstephh 				np->prev->next = np->next;
7945255Sstephh 				np->next->prev = np->prev;
7955255Sstephh 				add_resource(status_rec_p,
7965255Sstephh 				    rpp, np);
7975255Sstephh 			} else {
7985255Sstephh 				add_rec_list(status_rec_p,
7995255Sstephh 				    &np->status_rec_list);
8005255Sstephh 			}
8015255Sstephh 			break;
8025255Sstephh 		}
8035255Sstephh 		np = np->next;
8045255Sstephh 		if (np == end) {
8055255Sstephh 			np = NULL;
8065255Sstephh 			break;
8075255Sstephh 		}
8085255Sstephh 	}
8095255Sstephh 	if (np == NULL) {
8105255Sstephh 		np = malloc(sizeof (resource_list_t));
8115255Sstephh 		np->resource = fp->name;
8125255Sstephh 		np->not_suppressed = status_rec_p->not_suppressed;
8135255Sstephh 		np->status_rec_list = NULL;
8145255Sstephh 		np->max_pct = fp->max_pct;
8155255Sstephh 		add_resource(status_rec_p, rpp, np);
8160Sstevel@tonic-gate 	}
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate 
8195255Sstephh static void
8205255Sstephh add_list(status_record_t *status_rec_p, name_list_t *listp,
8215255Sstephh     resource_list_t **glistp)
8225255Sstephh {
8235255Sstephh 	name_list_t *fp, *end;
8245255Sstephh 
8255255Sstephh 	fp = listp;
8265255Sstephh 	end = fp;
8275255Sstephh 	while (fp) {
8285255Sstephh 		add_resource_list(status_rec_p, fp, glistp);
8295255Sstephh 		fp = fp->next;
8305255Sstephh 		if (fp == end)
8315255Sstephh 			break;
8325255Sstephh 	}
8335255Sstephh }
8345255Sstephh 
8355255Sstephh /*
8365255Sstephh  * add record to rec, fru and asru lists.
8375255Sstephh  */
8385255Sstephh static void
8395255Sstephh catalog_new_record(uurec_t *uurec_p, char *msgid, name_list_t *class,
8405255Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
841*9501SRobert.Johnston@Sun.COM     name_list_t *serial, boolean_t not_suppressed,
8425255Sstephh     hostid_t *hostid)
8435255Sstephh {
8445255Sstephh 	status_record_t *status_rec_p;
8455255Sstephh 
8465255Sstephh 	status_rec_p = new_record_init(uurec_p, msgid, class, fru, asru,
847*9501SRobert.Johnston@Sun.COM 	    resource, serial, not_suppressed, hostid);
8485255Sstephh 	add_rec_list(status_rec_p, &status_rec_list);
8495255Sstephh 	if (status_rec_p->fru)
8505255Sstephh 		add_list(status_rec_p, status_rec_p->fru, &status_fru_list);
8515255Sstephh 	if (status_rec_p->asru)
8525255Sstephh 		add_list(status_rec_p, status_rec_p->asru, &status_asru_list);
8535255Sstephh }
8545255Sstephh 
8555255Sstephh /*
8565255Sstephh  * add uuid and diagnoses time to an existing record for similar fault on the
8575255Sstephh  * same fru
8585255Sstephh  */
8595255Sstephh static void
8605255Sstephh catalog_merge_record(status_record_t *status_rec_p, uurec_t *uurec_p,
8615255Sstephh     name_list_t *asru, name_list_t *resource, name_list_t *serial,
862*9501SRobert.Johnston@Sun.COM     boolean_t not_suppressed)
8635255Sstephh {
8645255Sstephh 	uurec_t *uurec1_p;
8650Sstevel@tonic-gate 
8665255Sstephh 	status_rec_p->nrecs++;
8675255Sstephh 	/* add uurec in time order */
8685255Sstephh 	if (status_rec_p->uurec->sec > uurec_p->sec) {
8695255Sstephh 		uurec_p->next = status_rec_p->uurec;
8705255Sstephh 		uurec_p->prev = NULL;
8715255Sstephh 		status_rec_p->uurec = uurec_p;
8725255Sstephh 	} else {
8735255Sstephh 		uurec1_p = status_rec_p->uurec;
8745255Sstephh 		while (uurec1_p->next && uurec1_p->next->sec <= uurec_p->sec)
8755255Sstephh 			uurec1_p = uurec1_p->next;
8765255Sstephh 		if (uurec1_p->next)
8775255Sstephh 			uurec1_p->next->prev = uurec_p;
8785255Sstephh 		uurec_p->next = uurec1_p->next;
8795255Sstephh 		uurec_p->prev = uurec1_p;
8805255Sstephh 		uurec1_p->next = uurec_p;
8815255Sstephh 	}
8825255Sstephh 	status_rec_p->not_suppressed |= not_suppressed;
8835255Sstephh 	uurec_p->asru = merge_name_list(&status_rec_p->asru, asru, 0);
8845255Sstephh 	(void) merge_name_list(&status_rec_p->resource, resource, 0);
8855255Sstephh 	(void) merge_name_list(&status_rec_p->serial, serial, 0);
8865255Sstephh }
8875255Sstephh 
8885255Sstephh static status_record_t *
8895255Sstephh record_in_catalog(name_list_t *class, name_list_t *fru,
8905255Sstephh     char *msgid, hostid_t *host)
8915255Sstephh {
8925255Sstephh 	sr_list_t *status_rec_p;
8935255Sstephh 	status_record_t *srp = NULL;
8945255Sstephh 
8955255Sstephh 	status_rec_p = status_rec_list;
8965255Sstephh 	while (status_rec_p) {
8975255Sstephh 		srp = status_rec_p->status_record;
8985255Sstephh 		if (host == srp->host &&
8995255Sstephh 		    cmp_name_list(class, srp->class) == 0 &&
9005255Sstephh 		    cmp_name_list(fru, srp->fru) == 0 &&
9015255Sstephh 		    strcmp(msgid, srp->msgid) == 0)
9025255Sstephh 			break;
9035255Sstephh 		if (status_rec_p->next == status_rec_list) {
9045255Sstephh 			srp = NULL;
9055255Sstephh 			break;
9065255Sstephh 		} else {
9075255Sstephh 			status_rec_p = status_rec_p->next;
9085255Sstephh 		}
9095255Sstephh 	}
9105255Sstephh 	return (srp);
9115255Sstephh }
9125255Sstephh 
9135255Sstephh static void
9145255Sstephh get_serial_no(nvlist_t *nvl, name_list_t **serial_p, uint8_t pct)
9155255Sstephh {
9165255Sstephh 	char *name;
9175255Sstephh 	char *serial = NULL;
9185255Sstephh 	char **lserial = NULL;
9195255Sstephh 	uint64_t serint;
9205255Sstephh 	name_list_t *nlp;
9215255Sstephh 	int j;
9225255Sstephh 	uint_t nelem;
9235255Sstephh 	char buf[64];
9240Sstevel@tonic-gate 
9255255Sstephh 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) == 0) {
9265255Sstephh 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
9275255Sstephh 			if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
9285255Sstephh 			    &serint) == 0) {
9295255Sstephh 				(void) snprintf(buf, sizeof (buf), "%llX",
9305255Sstephh 				    serint);
9315255Sstephh 				nlp = alloc_name_list(buf, pct);
9325255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
9335255Sstephh 			}
9345255Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
9355255Sstephh 			if (nvlist_lookup_string_array(nvl,
9365255Sstephh 			    FM_FMRI_MEM_SERIAL_ID, &lserial, &nelem) == 0) {
9375255Sstephh 				nlp = alloc_name_list(lserial[0], pct);
9385255Sstephh 				for (j = 1; j < nelem; j++) {
9395255Sstephh 					name_list_t *n1lp;
9405255Sstephh 					n1lp = alloc_name_list(lserial[j], pct);
9415255Sstephh 					(void) merge_name_list(&nlp, n1lp, 1);
9425255Sstephh 				}
9435255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
9445255Sstephh 			}
9455255Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_HC) == 0) {
9465255Sstephh 			if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID,
9475255Sstephh 			    &serial) == 0) {
9485255Sstephh 				nlp = alloc_name_list(serial, pct);
9495255Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
9505255Sstephh 			}
9515255Sstephh 		}
9525255Sstephh 	}
9535255Sstephh }
9545255Sstephh 
9555255Sstephh static void
9565255Sstephh extract_record_info(nvlist_t *nvl, name_list_t **class_p,
9575255Sstephh     name_list_t **fru_p, name_list_t **serial_p,
9585255Sstephh     name_list_t **resource_p, name_list_t **asru_p, uint8_t status)
9590Sstevel@tonic-gate {
9605255Sstephh 	nvlist_t *lfru, *lasru, *rsrc;
9615255Sstephh 	name_list_t *nlp;
9625255Sstephh 	char *name;
9635255Sstephh 	uint8_t lpct = 0;
9645255Sstephh 	char *lclass = NULL;
9656002Sstephh 	char *label;
9665255Sstephh 
9675255Sstephh 	(void) nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &lpct);
9685255Sstephh 	if (nvlist_lookup_string(nvl, FM_CLASS, &lclass) == 0) {
9695255Sstephh 		nlp = alloc_name_list(lclass, lpct);
9705255Sstephh 		(void) merge_name_list(class_p, nlp, 1);
9715255Sstephh 	}
9725255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &lfru) == 0) {
9735255Sstephh 		name = get_nvl2str_topo(lfru);
9745255Sstephh 		if (name != NULL) {
9755255Sstephh 			nlp = alloc_name_list(name, lpct);
9767275Sstephh 			nlp->status = status & ~(FM_SUSPECT_UNUSABLE |
9777275Sstephh 			    FM_SUSPECT_DEGRADED);
9785255Sstephh 			free(name);
9796002Sstephh 			if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION,
9806002Sstephh 			    &label) == 0)
9816002Sstephh 				nlp->label = strdup(label);
9825255Sstephh 			(void) merge_name_list(fru_p, nlp, 1);
9835255Sstephh 		}
9845255Sstephh 		get_serial_no(lfru, serial_p, lpct);
9855255Sstephh 	}
9865255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &lasru) == 0) {
9875255Sstephh 		name = get_nvl2str_topo(lasru);
9885255Sstephh 		if (name != NULL) {
9895255Sstephh 			nlp = alloc_name_list(name, lpct);
9907275Sstephh 			nlp->status = status & ~(FM_SUSPECT_NOT_PRESENT |
9917275Sstephh 			    FM_SUSPECT_REPAIRED | FM_SUSPECT_REPLACED |
9927275Sstephh 			    FM_SUSPECT_ACQUITTED);
9935255Sstephh 			free(name);
9945255Sstephh 			(void) merge_name_list(asru_p, nlp, 1);
9955255Sstephh 		}
9965255Sstephh 		get_serial_no(lasru, serial_p, lpct);
9975255Sstephh 	}
9985255Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
9995255Sstephh 		name = get_nvl2str_topo(rsrc);
10005255Sstephh 		if (name != NULL) {
10015255Sstephh 			nlp = alloc_name_list(name, lpct);
10026228Sstephh 			nlp->status = status;
10035255Sstephh 			free(name);
10048245SStephen.Hanson@Sun.COM 			if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION,
10058245SStephen.Hanson@Sun.COM 			    &label) == 0)
10068245SStephen.Hanson@Sun.COM 				nlp->label = strdup(label);
10075255Sstephh 			(void) merge_name_list(resource_p, nlp, 1);
10085255Sstephh 		}
10095255Sstephh 	}
10105255Sstephh }
10115255Sstephh 
10125255Sstephh static void
1013*9501SRobert.Johnston@Sun.COM add_fault_record_to_catalog(nvlist_t *nvl, uint64_t sec, char *uuid)
10145255Sstephh {
10155255Sstephh 	char *msgid = "-";
10165255Sstephh 	uint_t i, size = 0;
10175255Sstephh 	name_list_t *class = NULL, *resource = NULL;
10185255Sstephh 	name_list_t *asru = NULL, *fru = NULL, *serial = NULL;
10195255Sstephh 	nvlist_t **nva;
10205255Sstephh 	uint8_t *ba;
10215255Sstephh 	status_record_t *status_rec_p;
10225255Sstephh 	uurec_t *uurec_p;
10235255Sstephh 	hostid_t *host;
10245255Sstephh 	boolean_t not_suppressed = 1;
10255255Sstephh 	boolean_t any_present = 0;
10265255Sstephh 
10275255Sstephh 	(void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &msgid);
10285255Sstephh 	(void) nvlist_lookup_uint32(nvl, FM_SUSPECT_FAULT_SZ, &size);
10295255Sstephh 	(void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_MESSAGE,
10305255Sstephh 	    &not_suppressed);
10315255Sstephh 
10325255Sstephh 	if (size != 0) {
10335255Sstephh 		(void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
10345255Sstephh 		    &nva, &size);
10355255Sstephh 		(void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS,
10365255Sstephh 		    &ba, &size);
10375255Sstephh 		for (i = 0; i < size; i++) {
10385255Sstephh 			extract_record_info(nva[i], &class, &fru, &serial,
10395255Sstephh 			    &resource, &asru, ba[i]);
10405255Sstephh 			if (!(ba[i] & FM_SUSPECT_NOT_PRESENT) &&
10415255Sstephh 			    (ba[i] & FM_SUSPECT_FAULTY))
10425255Sstephh 				any_present = 1;
10435255Sstephh 		}
10445255Sstephh 		/*
10455255Sstephh 		 * also suppress if no resources present
10465255Sstephh 		 */
10475255Sstephh 		if (any_present == 0)
10485255Sstephh 			not_suppressed = 0;
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10515255Sstephh 	uurec_p = (uurec_t *)malloc(sizeof (uurec_t));
10525255Sstephh 	uurec_p->uuid = strdup(uuid);
10535255Sstephh 	uurec_p->sec = sec;
10545255Sstephh 	uurec_p->ari_uuid_list = NULL;
10555255Sstephh 	host = find_hostid(nvl);
10565255Sstephh 	if (not_suppressed && !opt_g)
10575255Sstephh 		status_rec_p = NULL;
10585255Sstephh 	else
10595255Sstephh 		status_rec_p = record_in_catalog(class, fru, msgid, host);
10605255Sstephh 	if (status_rec_p) {
10615255Sstephh 		catalog_merge_record(status_rec_p, uurec_p, asru, resource,
1062*9501SRobert.Johnston@Sun.COM 		    serial, not_suppressed);
10635255Sstephh 		free_name_list(class);
10645255Sstephh 		free_name_list(fru);
10655255Sstephh 	} else {
10665255Sstephh 		catalog_new_record(uurec_p, msgid, class, fru, asru,
1067*9501SRobert.Johnston@Sun.COM 		    resource, serial, not_suppressed, host);
10685255Sstephh 	}
10695255Sstephh }
10705255Sstephh 
10715255Sstephh static void
10725255Sstephh update_asru_state_in_catalog(const char *uuid, const char *ari_uuid)
10735255Sstephh {
10745255Sstephh 	sr_list_t *srp;
10755255Sstephh 	uurec_t *uurp;
10765255Sstephh 	ari_list_t *ari_list;
10775255Sstephh 
10785255Sstephh 	srp = status_rec_list;
10795255Sstephh 	if (srp) {
10805255Sstephh 		for (;;) {
10815255Sstephh 			uurp = srp->status_record->uurec;
10825255Sstephh 			while (uurp) {
10835255Sstephh 				if (strcmp(uuid, uurp->uuid) == 0) {
10845255Sstephh 					ari_list = (ari_list_t *)
10855255Sstephh 					    malloc(sizeof (ari_list_t));
10865255Sstephh 					ari_list->ari_uuid = strdup(ari_uuid);
10875255Sstephh 					ari_list->next = uurp->ari_uuid_list;
10885255Sstephh 					uurp->ari_uuid_list = ari_list;
10895255Sstephh 					return;
10905255Sstephh 				}
10915255Sstephh 				uurp = uurp->next;
10925255Sstephh 			}
10935255Sstephh 			if (srp->next == status_rec_list)
10945255Sstephh 				break;
10955255Sstephh 			srp = srp->next;
10965255Sstephh 		}
10975255Sstephh 	}
10985255Sstephh }
10995255Sstephh 
11005255Sstephh static void
11015255Sstephh print_line(char *label, char *buf)
11025255Sstephh {
11035255Sstephh 	char *cp, *ep, *wp;
11045255Sstephh 	char c;
11055255Sstephh 	int i;
11065255Sstephh 	int lsz;
11075255Sstephh 	char *padding;
11085255Sstephh 
11095255Sstephh 	lsz = strlen(label);
11105255Sstephh 	padding = malloc(lsz + 1);
11115255Sstephh 	for (i = 0; i < lsz; i++)
11125255Sstephh 		padding[i] = ' ';
11135255Sstephh 	padding[i] = 0;
11145255Sstephh 	cp = buf;
11155255Sstephh 	ep = buf;
11165255Sstephh 	c = *ep;
11175255Sstephh 	(void) printf("\n");
11185255Sstephh 	while (c) {
11195255Sstephh 		i = lsz;
11205255Sstephh 		wp = NULL;
11215255Sstephh 		while ((c = *ep) != NULL && (wp == NULL || i < 80)) {
11225255Sstephh 			if (c == ' ')
11235255Sstephh 				wp = ep;
11245255Sstephh 			else if (c == '\n') {
11255255Sstephh 				i = 0;
11265255Sstephh 				*ep = 0;
11275255Sstephh 				do {
11285255Sstephh 					ep++;
11295255Sstephh 				} while ((c = *ep) != NULL && c == ' ');
11305255Sstephh 				break;
11315255Sstephh 			}
11325255Sstephh 			ep++;
11335255Sstephh 			i++;
11345255Sstephh 		}
11355255Sstephh 		if (i >= 80 && wp) {
11365255Sstephh 			*wp = 0;
11375255Sstephh 			ep = wp + 1;
11385255Sstephh 			c = *ep;
11395255Sstephh 		}
11405255Sstephh 		(void) printf("%s%s\n", label, cp);
11415255Sstephh 		cp = ep;
11425255Sstephh 		label = padding;
11435255Sstephh 	}
11445255Sstephh 	free(padding);
11455255Sstephh }
11465255Sstephh 
11475255Sstephh static void
1148*9501SRobert.Johnston@Sun.COM print_dict_info_line(char *msgid, fmd_msg_item_t what, const char *linehdr)
11495255Sstephh {
1150*9501SRobert.Johnston@Sun.COM 	char *cp = fmd_msg_getitem_id(fmadm_msghdl, NULL, msgid, what);
11515255Sstephh 
11525255Sstephh 	if (cp) {
1153*9501SRobert.Johnston@Sun.COM 		print_line(dgettext("FMD", linehdr), cp);
1154*9501SRobert.Johnston@Sun.COM 		free(cp);
11555255Sstephh 	}
1156*9501SRobert.Johnston@Sun.COM }
1157*9501SRobert.Johnston@Sun.COM 
1158*9501SRobert.Johnston@Sun.COM static void
1159*9501SRobert.Johnston@Sun.COM print_dict_info(char *msgid)
1160*9501SRobert.Johnston@Sun.COM {
1161*9501SRobert.Johnston@Sun.COM 	print_dict_info_line(msgid, FMD_MSG_ITEM_DESC, "Description : ");
1162*9501SRobert.Johnston@Sun.COM 	print_dict_info_line(msgid, FMD_MSG_ITEM_RESPONSE, "Response    : ");
1163*9501SRobert.Johnston@Sun.COM 	print_dict_info_line(msgid, FMD_MSG_ITEM_IMPACT, "Impact      : ");
1164*9501SRobert.Johnston@Sun.COM 	print_dict_info_line(msgid, FMD_MSG_ITEM_ACTION, "Action      : ");
11655255Sstephh }
11665255Sstephh 
11675255Sstephh static void
11685255Sstephh print_name(name_list_t *list, char *(func)(char *), char *padding, int *np,
11695255Sstephh     int pct, int full)
11705255Sstephh {
11718245SStephen.Hanson@Sun.COM 	char *name, *fru_label = NULL;
11725255Sstephh 
11735255Sstephh 	name = list->name;
11748245SStephen.Hanson@Sun.COM 	if (list->label) {
11758245SStephen.Hanson@Sun.COM 		(void) printf("%s \"%s\" (%s)", padding, list->label, name);
11765255Sstephh 		*np += 1;
11778245SStephen.Hanson@Sun.COM 	} else if (func && (fru_label = func(list->name)) != NULL) {
11788245SStephen.Hanson@Sun.COM 		(void) printf("%s \"%s\" (%s)", padding, fru_label, name);
11798245SStephen.Hanson@Sun.COM 		*np += 1;
11808245SStephen.Hanson@Sun.COM 		free(fru_label);
11815255Sstephh 	} else {
11825255Sstephh 		(void) printf("%s %s", padding, name);
11835255Sstephh 		*np += 1;
11845255Sstephh 	}
11855255Sstephh 	if (list->pct && pct > 0 && pct < 100) {
11865255Sstephh 		if (list->count > 1) {
11875255Sstephh 			if (full) {
11885255Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
11895255Sstephh 				    dgettext("FMD", "max"),
11905255Sstephh 				    list->max_pct);
11915255Sstephh 			} else {
11925255Sstephh 				(void) printf(" %s %d%%\n",
11935255Sstephh 				    dgettext("FMD", "max"),
11945255Sstephh 				    list->max_pct);
11955255Sstephh 			}
11965255Sstephh 		} else {
11975255Sstephh 			(void) printf(" %d%%\n", list->pct);
11985255Sstephh 		}
11995255Sstephh 	} else {
12005255Sstephh 		(void) printf("\n");
12015255Sstephh 	}
12025255Sstephh }
12035255Sstephh 
12045255Sstephh static void
12055255Sstephh print_asru_status(int status, char *label)
12065255Sstephh {
12075255Sstephh 	char *msg = NULL;
12085255Sstephh 
12095255Sstephh 	switch (status) {
12105255Sstephh 	case 0:
12115255Sstephh 		msg = dgettext("FMD", "ok and in service");
12125255Sstephh 		break;
12137275Sstephh 	case FM_SUSPECT_DEGRADED:
12147275Sstephh 		msg = dgettext("FMD", "service degraded, "
12157275Sstephh 		    "but associated components no longer faulty");
12167275Sstephh 		break;
12177275Sstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED:
12187275Sstephh 		msg = dgettext("FMD", "faulted but still "
12197275Sstephh 		    "providing degraded service");
12207275Sstephh 		break;
12215255Sstephh 	case FM_SUSPECT_FAULTY:
12227275Sstephh 		msg = dgettext("FMD", "faulted but still in service");
12235255Sstephh 		break;
12245255Sstephh 	case FM_SUSPECT_UNUSABLE:
12257275Sstephh 		msg = dgettext("FMD", "out of service, "
12267275Sstephh 		    "but associated components no longer faulty");
12275255Sstephh 		break;
12285255Sstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
12295255Sstephh 		msg = dgettext("FMD", "faulted and taken out of service");
12305255Sstephh 		break;
12315255Sstephh 	default:
12325255Sstephh 		break;
12335255Sstephh 	}
12345255Sstephh 	if (msg) {
12355255Sstephh 		(void) printf("%s     %s\n", label, msg);
12365255Sstephh 	}
12375255Sstephh }
12385255Sstephh 
12395255Sstephh static void
12406228Sstephh print_fru_status(int status, char *label)
12416228Sstephh {
12426228Sstephh 	char *msg = NULL;
12436228Sstephh 
12446228Sstephh 	if (status & FM_SUSPECT_NOT_PRESENT)
12456228Sstephh 		msg = dgettext("FMD", "not present");
12466228Sstephh 	else if (status & FM_SUSPECT_FAULTY)
12476228Sstephh 		msg = dgettext("FMD", "faulty");
12487275Sstephh 	else if (status & FM_SUSPECT_REPLACED)
12497275Sstephh 		msg = dgettext("FMD", "replaced");
12507275Sstephh 	else if (status & FM_SUSPECT_REPAIRED)
12517275Sstephh 		msg = dgettext("FMD", "repair attempted");
12527275Sstephh 	else if (status & FM_SUSPECT_ACQUITTED)
12537275Sstephh 		msg = dgettext("FMD", "acquitted");
12546228Sstephh 	else
12557275Sstephh 		msg = dgettext("FMD", "removed");
12566228Sstephh 	(void) printf("%s     %s\n", label, msg);
12576228Sstephh }
12586228Sstephh 
12596228Sstephh static void
12609120SStephen.Hanson@Sun.COM print_rsrc_status(int status, char *label)
12619120SStephen.Hanson@Sun.COM {
12629120SStephen.Hanson@Sun.COM 	char *msg = "";
12639120SStephen.Hanson@Sun.COM 
12649120SStephen.Hanson@Sun.COM 	if (status & FM_SUSPECT_NOT_PRESENT)
12659120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "not present");
12669120SStephen.Hanson@Sun.COM 	else if (status & FM_SUSPECT_FAULTY) {
12679120SStephen.Hanson@Sun.COM 		if (status & FM_SUSPECT_DEGRADED)
12689120SStephen.Hanson@Sun.COM 			msg = dgettext("FMD",
12699120SStephen.Hanson@Sun.COM 			    "faulted but still providing degraded service");
12709120SStephen.Hanson@Sun.COM 		else if (status & FM_SUSPECT_UNUSABLE)
12719120SStephen.Hanson@Sun.COM 			msg = dgettext("FMD",
12729120SStephen.Hanson@Sun.COM 			    "faulted and taken out of service");
12739120SStephen.Hanson@Sun.COM 		else
12749120SStephen.Hanson@Sun.COM 			msg = dgettext("FMD", "faulted but still in service");
12759120SStephen.Hanson@Sun.COM 	} else if (status & FM_SUSPECT_REPLACED)
12769120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "replaced");
12779120SStephen.Hanson@Sun.COM 	else if (status & FM_SUSPECT_REPAIRED)
12789120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "repair attempted");
12799120SStephen.Hanson@Sun.COM 	else if (status & FM_SUSPECT_ACQUITTED)
12809120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "acquitted");
12819120SStephen.Hanson@Sun.COM 	else
12829120SStephen.Hanson@Sun.COM 		msg = dgettext("FMD", "removed");
12839120SStephen.Hanson@Sun.COM 	(void) printf("%s     %s\n", label, msg);
12849120SStephen.Hanson@Sun.COM }
12859120SStephen.Hanson@Sun.COM 
12869120SStephen.Hanson@Sun.COM static void
12875255Sstephh print_name_list(name_list_t *list, char *label, char *(func)(char *),
12885255Sstephh     int limit, int pct, void (func1)(int, char *), int full)
12895255Sstephh {
12908245SStephen.Hanson@Sun.COM 	char *name, *fru_label = NULL;
12915255Sstephh 	char *padding;
12925255Sstephh 	int i, j, l, n;
12935255Sstephh 	name_list_t *end = list;
12945255Sstephh 
12955255Sstephh 	l = strlen(label);
12965255Sstephh 	padding = malloc(l + 1);
12975255Sstephh 	for (i = 0; i < l; i++)
12985255Sstephh 		padding[i] = ' ';
12995255Sstephh 	padding[l] = 0;
13005255Sstephh 	(void) printf("%s", label);
13015255Sstephh 	name = list->name;
13028245SStephen.Hanson@Sun.COM 	if (list->label)
13036002Sstephh 		(void) printf(" \"%s\" (%s)", list->label, name);
13048245SStephen.Hanson@Sun.COM 	else if (func && (fru_label = func(list->name)) != NULL) {
13058245SStephen.Hanson@Sun.COM 		(void) printf(" \"%s\" (%s)", fru_label, name);
13068245SStephen.Hanson@Sun.COM 		free(fru_label);
13078245SStephen.Hanson@Sun.COM 	} else
13088245SStephen.Hanson@Sun.COM 		(void) printf(" %s", name);
13095255Sstephh 	if (list->pct && pct > 0 && pct < 100) {
13105255Sstephh 		if (list->count > 1) {
13115255Sstephh 			if (full) {
13125255Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
13135255Sstephh 				    dgettext("FMD", "max"), list->max_pct);
13145255Sstephh 			} else {
13155255Sstephh 				(void) printf(" %s %d%%\n",
13165255Sstephh 				    dgettext("FMD", "max"), list->max_pct);
13175255Sstephh 			}
13185255Sstephh 		} else {
13195255Sstephh 			(void) printf(" %d%%\n", list->pct);
13205255Sstephh 		}
13215255Sstephh 	} else {
13225255Sstephh 		(void) printf("\n");
13235255Sstephh 	}
13245255Sstephh 	if (func1)
13255255Sstephh 		func1(list->status, padding);
13265255Sstephh 	n = 1;
13275255Sstephh 	j = 0;
13285255Sstephh 	while ((list = list->next) != end) {
13295255Sstephh 		if (limit == 0 || n < limit) {
13305255Sstephh 			print_name(list, func, padding, &n, pct, full);
13315255Sstephh 			if (func1)
13325255Sstephh 				func1(list->status, padding);
13335255Sstephh 		} else
13345255Sstephh 			j++;
13355255Sstephh 	}
13365255Sstephh 	if (j == 1) {
13375255Sstephh 		print_name(list->prev, func, padding, &n, pct, full);
13385255Sstephh 	} else if (j > 1) {
13395255Sstephh 		(void) printf("%s... %d %s\n", padding, j,
13405255Sstephh 		    dgettext("FMD", "more entries suppressed,"
13415255Sstephh 		    " use -v option for full list"));
13425255Sstephh 	}
13435255Sstephh 	free(padding);
13445255Sstephh }
13455255Sstephh 
13465255Sstephh static int
13475255Sstephh asru_same_status(name_list_t *list)
13485255Sstephh {
13495255Sstephh 	name_list_t *end = list;
13505255Sstephh 	int status = list->status;
13515255Sstephh 
13525255Sstephh 	while ((list = list->next) != end) {
13535255Sstephh 		if (status == -1) {
13545255Sstephh 			status = list->status;
13555255Sstephh 			continue;
13565255Sstephh 		}
13575255Sstephh 		if (list->status != -1 && status != list->status) {
13585255Sstephh 			status = -1;
13595255Sstephh 			break;
13605255Sstephh 		}
13615255Sstephh 	}
13625255Sstephh 	return (status);
13635255Sstephh }
13645255Sstephh 
13655255Sstephh static int
13665255Sstephh serial_in_fru(name_list_t *fru, name_list_t *serial)
13675255Sstephh {
13685255Sstephh 	name_list_t *sp = serial;
13695255Sstephh 	name_list_t *fp;
13705255Sstephh 	int nserial = 0;
13715255Sstephh 	int found = 0;
13725255Sstephh 	char buf[128];
13735255Sstephh 
13745255Sstephh 	while (sp) {
13755255Sstephh 		fp = fru;
13765255Sstephh 		nserial++;
13775255Sstephh 		(void) snprintf(buf, sizeof (buf), "serial=%s", sp->name);
13785255Sstephh 		buf[sizeof (buf) - 1] = 0;
13795255Sstephh 		while (fp) {
13805255Sstephh 			if (strstr(fp->name, buf) != NULL) {
13815255Sstephh 				found++;
13825255Sstephh 				break;
13835255Sstephh 			}
13845255Sstephh 			fp = fp->next;
13855255Sstephh 			if (fp == fru)
13865255Sstephh 				break;
13875255Sstephh 		}
13885255Sstephh 		sp = sp->next;
13895255Sstephh 		if (sp == serial)
13905255Sstephh 			break;
13915255Sstephh 	}
13925255Sstephh 	return (found == nserial ? 1 : 0);
13935255Sstephh }
13945255Sstephh 
13955255Sstephh static void
13965255Sstephh print_sup_record(status_record_t *srp, int opt_i, int full)
13975255Sstephh {
13985255Sstephh 	char buf[32];
13995255Sstephh 	uurec_t *uurp = srp->uurec;
14005255Sstephh 	int n, j, k, max;
14015255Sstephh 	int status;
14025255Sstephh 	ari_list_t *ari_list;
14035255Sstephh 
14045255Sstephh 	n = 0;
14055255Sstephh 	max = max_fault;
14065255Sstephh 	if (max < 0) {
14075255Sstephh 		max = 0;
14085255Sstephh 	}
14095255Sstephh 	j = max / 2;
14105255Sstephh 	max -= j;
14115255Sstephh 	k = srp->nrecs - max;
14125255Sstephh 	while ((uurp = uurp->next) != NULL) {
14135255Sstephh 		if (full || n < j || n >= k || max_fault == 0 ||
14145255Sstephh 		    srp->nrecs == max_fault+1) {
14155255Sstephh 			if (opt_i) {
14165255Sstephh 				ari_list = uurp->ari_uuid_list;
14175255Sstephh 				while (ari_list) {
14185255Sstephh 					(void) printf("%-15s %s\n",
14195255Sstephh 					    format_date(buf, sizeof (buf),
14205255Sstephh 					    uurp->sec), ari_list->ari_uuid);
14215255Sstephh 					ari_list = ari_list->next;
14225255Sstephh 				}
14235255Sstephh 			} else {
14245255Sstephh 				(void) printf("%-15s %s\n",
14255255Sstephh 				    format_date(buf, sizeof (buf), uurp->sec),
14265255Sstephh 				    uurp->uuid);
14275255Sstephh 			}
14285255Sstephh 		} else if (n == j)
14295255Sstephh 			(void) printf("... %d %s\n", srp->nrecs - max_fault,
14305255Sstephh 			    dgettext("FMD", "more entries suppressed"));
14315255Sstephh 		n++;
14325255Sstephh 	}
14335255Sstephh 	(void) printf("\n");
14349120SStephen.Hanson@Sun.COM 	(void) printf("%s %s", dgettext("FMD", "Host        :"),
14359120SStephen.Hanson@Sun.COM 	    srp->host->server);
14369120SStephen.Hanson@Sun.COM 	if (srp->host->domain)
14379120SStephen.Hanson@Sun.COM 		(void) printf("\t%s %s", dgettext("FMD", "Domain      :"),
14389120SStephen.Hanson@Sun.COM 		    srp->host->domain);
14399120SStephen.Hanson@Sun.COM 	(void) printf("\n%s %s", dgettext("FMD", "Platform    :"),
14409120SStephen.Hanson@Sun.COM 	    srp->host->platform);
14419120SStephen.Hanson@Sun.COM 	(void) printf("\t%s %s\n\n", dgettext("FMD", "Chassis_id  :"),
14429120SStephen.Hanson@Sun.COM 	    srp->host->chassis ? srp->host->chassis : "");
14435255Sstephh 	if (srp->class)
14445255Sstephh 		print_name_list(srp->class,
14455255Sstephh 		    dgettext("FMD", "Fault class :"), NULL, 0, srp->class->pct,
14465255Sstephh 		    NULL, full);
14475255Sstephh 	if (srp->asru) {
14485255Sstephh 		status = asru_same_status(srp->asru);
14495255Sstephh 		if (status != -1) {
14505255Sstephh 			print_name_list(srp->asru,
14515255Sstephh 			    dgettext("FMD", "Affects     :"), NULL,
14525255Sstephh 			    full ? 0 : max_display, 0, NULL, full);
14535255Sstephh 			print_asru_status(status, "             ");
14545255Sstephh 		} else
14555255Sstephh 			print_name_list(srp->asru,
14565255Sstephh 			    dgettext("FMD", "Affects     :"), NULL,
14575255Sstephh 			    full ? 0 : max_display, 0, print_asru_status, full);
14585255Sstephh 	}
14599120SStephen.Hanson@Sun.COM 	if (full || srp->fru == NULL || srp->asru == NULL) {
14605255Sstephh 		if (srp->resource) {
14615255Sstephh 			print_name_list(srp->resource,
14625255Sstephh 			    dgettext("FMD", "Problem in  :"),
14639120SStephen.Hanson@Sun.COM 			    NULL, full ? 0 : max_display, 0, print_rsrc_status,
14646228Sstephh 			    full);
14655255Sstephh 		}
14665255Sstephh 	}
14675255Sstephh 	if (srp->fru) {
14686228Sstephh 		status = asru_same_status(srp->fru);
14696228Sstephh 		if (status != -1) {
14706228Sstephh 			print_name_list(srp->fru, dgettext("FMD",
14716228Sstephh 			    "FRU         :"), get_fmri_label, 0,
14726228Sstephh 			    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
14736228Sstephh 			    NULL, full);
14746228Sstephh 			print_fru_status(status, "             ");
14756228Sstephh 		} else
14766228Sstephh 			print_name_list(srp->fru, dgettext("FMD",
14776228Sstephh 			    "FRU         :"), get_fmri_label, 0,
14786228Sstephh 			    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
14796228Sstephh 			    print_fru_status, full);
14805255Sstephh 	}
14815255Sstephh 	if (srp->serial && !serial_in_fru(srp->fru, srp->serial) &&
14825255Sstephh 	    !serial_in_fru(srp->asru, srp->serial)) {
14835255Sstephh 		print_name_list(srp->serial, dgettext("FMD", "Serial ID.  :"),
14845255Sstephh 		    NULL, 0, 0, NULL, full);
14855255Sstephh 	}
1486*9501SRobert.Johnston@Sun.COM 	print_dict_info(srp->msgid);
14875255Sstephh 	(void) printf("\n");
14885255Sstephh }
14895255Sstephh 
14905255Sstephh static void
14915255Sstephh print_status_record(status_record_t *srp, int summary, int opt_i, int full)
14925255Sstephh {
14935255Sstephh 	char buf[32];
14945255Sstephh 	uurec_t *uurp = srp->uurec;
14955255Sstephh 	static int header = 0;
14965255Sstephh 	char *head;
14975255Sstephh 	ari_list_t *ari_list;
14985255Sstephh 
14995255Sstephh 	if (!summary || !header) {
15005255Sstephh 		if (opt_i) {
15015255Sstephh 			head = "--------------- "
15025255Sstephh 			    "------------------------------------  "
15035255Sstephh 			    "-------------- ---------\n"
15045255Sstephh 			    "TIME            CACHE-ID"
15055255Sstephh 			    "                              MSG-ID"
15065255Sstephh 			    "         SEVERITY\n--------------- "
15075255Sstephh 			    "------------------------------------ "
15085255Sstephh 			    " -------------- ---------";
15095255Sstephh 		} else {
15105255Sstephh 			head = "--------------- "
15115255Sstephh 			    "------------------------------------  "
15125255Sstephh 			    "-------------- ---------\n"
15135255Sstephh 			    "TIME            EVENT-ID"
15145255Sstephh 			    "                              MSG-ID"
15155255Sstephh 			    "         SEVERITY\n--------------- "
15165255Sstephh 			    "------------------------------------ "
15175255Sstephh 			    " -------------- ---------";
15185255Sstephh 		}
15195255Sstephh 		(void) printf("%s\n", dgettext("FMD", head));
15205255Sstephh 		header = 1;
15215255Sstephh 	}
15225255Sstephh 	if (opt_i) {
15235255Sstephh 		ari_list = uurp->ari_uuid_list;
15245255Sstephh 		while (ari_list) {
15255255Sstephh 			(void) printf("%-15s %-37s %-14s %-9s\n",
15265255Sstephh 			    format_date(buf, sizeof (buf), uurp->sec),
1527*9501SRobert.Johnston@Sun.COM 			    ari_list->ari_uuid, srp->msgid, srp->severity);
15285255Sstephh 			ari_list = ari_list->next;
15295255Sstephh 		}
15305255Sstephh 	} else {
15315255Sstephh 		(void) printf("%-15s %-37s %-14s %-9s\n",
15325255Sstephh 		    format_date(buf, sizeof (buf), uurp->sec),
1533*9501SRobert.Johnston@Sun.COM 		    uurp->uuid, srp->msgid, srp->severity);
15345255Sstephh 	}
15355255Sstephh 
15365255Sstephh 	if (!summary)
15375255Sstephh 		print_sup_record(srp, opt_i, full);
15385255Sstephh }
15395255Sstephh 
15405255Sstephh static void
15415255Sstephh print_catalog(int summary, int opt_a, int full, int opt_i, int page_feed)
15425255Sstephh {
15435255Sstephh 	status_record_t *srp;
15445255Sstephh 	sr_list_t *slp;
15455255Sstephh 
15465255Sstephh 	slp = status_rec_list;
15475255Sstephh 	if (slp) {
15485255Sstephh 		for (;;) {
15495255Sstephh 			srp = slp->status_record;
15505255Sstephh 			if (opt_a || srp->not_suppressed) {
15515255Sstephh 				if (page_feed)
15525255Sstephh 					(void) printf("\f\n");
15535255Sstephh 				print_status_record(srp, summary, opt_i, full);
15545255Sstephh 			}
15555255Sstephh 			if (slp->next == status_rec_list)
15565255Sstephh 				break;
15575255Sstephh 			slp = slp->next;
15585255Sstephh 		}
15595255Sstephh 	}
15605255Sstephh }
15615255Sstephh 
15625255Sstephh static name_list_t *
15635255Sstephh find_fru(status_record_t *srp, char *resource)
15645255Sstephh {
15655255Sstephh 	name_list_t *rt = NULL;
15665255Sstephh 	name_list_t *fru = srp->fru;
15675255Sstephh 
15685255Sstephh 	while (fru) {
15695255Sstephh 		if (strcmp(resource, fru->name) == 0) {
15705255Sstephh 			rt = fru;
15715255Sstephh 			break;
15725255Sstephh 		}
15735255Sstephh 		fru = fru->next;
15745255Sstephh 		if (fru == srp->fru)
15755255Sstephh 			break;
15765255Sstephh 	}
15775255Sstephh 	return (rt);
15785255Sstephh }
15795255Sstephh 
15805255Sstephh static void
15815255Sstephh print_fru_line(name_list_t *fru, char *uuid)
15825255Sstephh {
15835255Sstephh 	if (fru->pct == 100) {
15845255Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
15855255Sstephh 		    dgettext("FMD", "suspects in this FRU total certainty"),
15865255Sstephh 		    100);
15875255Sstephh 	} else {
15885255Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
15895255Sstephh 		    dgettext("FMD", "suspects in this FRU max certainty"),
15905255Sstephh 		    fru->max_pct);
15915255Sstephh 	}
15925255Sstephh }
15935255Sstephh 
15945255Sstephh static void
15955255Sstephh print_fru(int summary, int opt_a, int opt_i, int page_feed)
15965255Sstephh {
15975255Sstephh 	resource_list_t *tp = status_fru_list;
15985255Sstephh 	status_record_t *srp;
15995255Sstephh 	sr_list_t *slp, *end;
16005255Sstephh 	char *msgid, *fru_label;
16015255Sstephh 	uurec_t *uurp;
16025255Sstephh 	name_list_t *fru;
16036228Sstephh 	int status;
16045255Sstephh 	ari_list_t *ari_list;
16055255Sstephh 
16065255Sstephh 	while (tp) {
16075255Sstephh 		if (opt_a || tp->not_suppressed) {
16085255Sstephh 			if (page_feed)
16095255Sstephh 				(void) printf("\f\n");
16105255Sstephh 			if (!summary)
16115255Sstephh 				(void) printf("-----------------------------"
16125255Sstephh 				    "---------------------------------------"
16135255Sstephh 				    "----------\n");
16146002Sstephh 			slp = tp->status_rec_list;
16156002Sstephh 			end = slp;
16166002Sstephh 			do {
16176002Sstephh 				srp = slp->status_record;
16186002Sstephh 				fru = find_fru(srp, tp->resource);
16196002Sstephh 				if (fru) {
16206002Sstephh 					if (fru->label)
16216228Sstephh 						(void) printf("\"%s\" (%s) ",
16226002Sstephh 						    fru->label, fru->name);
16236228Sstephh 					else if ((fru_label = get_fmri_label(
16246228Sstephh 					    fru->name)) != NULL) {
16256228Sstephh 						(void) printf("\"%s\" (%s) ",
16266002Sstephh 						    fru_label, fru->name);
16276002Sstephh 						free(fru_label);
16286002Sstephh 					} else
16296228Sstephh 						(void) printf("%s ",
16306002Sstephh 						    fru->name);
16316002Sstephh 					break;
16326002Sstephh 				}
16336002Sstephh 				slp = slp->next;
16346002Sstephh 			} while (slp != end);
16356002Sstephh 
16365255Sstephh 			slp = tp->status_rec_list;
16375255Sstephh 			end = slp;
16386228Sstephh 			status = 0;
16396228Sstephh 			do {
16406228Sstephh 				srp = slp->status_record;
16416228Sstephh 				fru = srp->fru;
16426228Sstephh 				while (fru) {
16436228Sstephh 					if (strcmp(tp->resource,
16446228Sstephh 					    fru->name) == 0)
16456228Sstephh 						status |= fru->status;
16466228Sstephh 					fru = fru->next;
16476228Sstephh 					if (fru == srp->fru)
16486228Sstephh 						break;
16496228Sstephh 				}
16506228Sstephh 				slp = slp->next;
16516228Sstephh 			} while (slp != end);
16526228Sstephh 			if (status & FM_SUSPECT_NOT_PRESENT)
16536228Sstephh 				(void) printf(dgettext("FMD", "not present\n"));
16546228Sstephh 			else if (status & FM_SUSPECT_FAULTY)
16556228Sstephh 				(void) printf(dgettext("FMD", "faulty\n"));
16567275Sstephh 			else if (status & FM_SUSPECT_REPLACED)
16577275Sstephh 				(void) printf(dgettext("FMD", "replaced\n"));
16587275Sstephh 			else if (status & FM_SUSPECT_REPAIRED)
16597275Sstephh 				(void) printf(dgettext("FMD",
16607275Sstephh 				    "repair attempted\n"));
16617275Sstephh 			else if (status & FM_SUSPECT_ACQUITTED)
16627275Sstephh 				(void) printf(dgettext("FMD", "acquitted\n"));
16636228Sstephh 			else
16647275Sstephh 				(void) printf(dgettext("FMD", "removed\n"));
16656228Sstephh 
16666228Sstephh 			slp = tp->status_rec_list;
16676228Sstephh 			end = slp;
16685255Sstephh 			do {
16695255Sstephh 				srp = slp->status_record;
16705255Sstephh 				uurp = srp->uurec;
16715255Sstephh 				fru = find_fru(srp, tp->resource);
16725255Sstephh 				if (fru) {
16735255Sstephh 					if (opt_i) {
16745255Sstephh 						ari_list = uurp->ari_uuid_list;
16755255Sstephh 						while (ari_list) {
16765255Sstephh 							print_fru_line(fru,
16775255Sstephh 							    ari_list->ari_uuid);
16785255Sstephh 							ari_list =
16795255Sstephh 							    ari_list->next;
16805255Sstephh 						}
16815255Sstephh 					} else {
16825255Sstephh 						print_fru_line(fru, uurp->uuid);
16835255Sstephh 					}
16845255Sstephh 				}
16855255Sstephh 				slp = slp->next;
16865255Sstephh 			} while (slp != end);
16875255Sstephh 			if (!summary) {
16885255Sstephh 				slp = tp->status_rec_list;
16895255Sstephh 				end = slp;
16905255Sstephh 				srp = slp->status_record;
16915255Sstephh 				if (srp->serial &&
16925255Sstephh 				    !serial_in_fru(srp->fru, srp->serial)) {
16935255Sstephh 					print_name_list(srp->serial,
16945255Sstephh 					    dgettext("FMD", "Serial ID.  :"),
16955255Sstephh 					    NULL, 0, 0, NULL, 1);
16965255Sstephh 				}
16975255Sstephh 				msgid = NULL;
16985255Sstephh 				do {
16995255Sstephh 					if (msgid == NULL ||
17005255Sstephh 					    strcmp(msgid, srp->msgid) != 0) {
17015255Sstephh 						msgid = srp->msgid;
1702*9501SRobert.Johnston@Sun.COM 						print_dict_info(srp->msgid);
17035255Sstephh 					}
17045255Sstephh 					slp = slp->next;
17055255Sstephh 				} while (slp != end);
17065255Sstephh 			}
17075255Sstephh 		}
17085255Sstephh 		tp = tp->next;
17095255Sstephh 		if (tp == status_fru_list)
17105255Sstephh 			break;
17115255Sstephh 	}
17125255Sstephh }
17135255Sstephh 
17145255Sstephh static void
17155255Sstephh print_asru(int opt_a)
17165255Sstephh {
17175255Sstephh 	resource_list_t *tp = status_asru_list;
17185255Sstephh 	status_record_t *srp;
17195255Sstephh 	sr_list_t *slp, *end;
17205255Sstephh 	char *msg;
17215255Sstephh 	int status;
17225255Sstephh 	name_list_t *asru;
17235255Sstephh 
17245255Sstephh 	while (tp) {
17255255Sstephh 		if (opt_a || tp->not_suppressed) {
17265255Sstephh 			status = 0;
17275255Sstephh 			slp = tp->status_rec_list;
17285255Sstephh 			end = slp;
17295255Sstephh 			do {
17305255Sstephh 				srp = slp->status_record;
17315255Sstephh 				asru = srp->asru;
17325255Sstephh 				while (asru) {
17335255Sstephh 					if (strcmp(tp->resource,
17345255Sstephh 					    asru->name) == 0)
17355255Sstephh 						status |= asru->status;
17365255Sstephh 					asru = asru->next;
17375255Sstephh 					if (asru == srp->asru)
17385255Sstephh 						break;
17395255Sstephh 				}
17405255Sstephh 				slp = slp->next;
17415255Sstephh 			} while (slp != end);
17425255Sstephh 			switch (status) {
17435255Sstephh 			case 0:
17445255Sstephh 				msg = dgettext("FMD", "ok");
17455255Sstephh 				break;
17467275Sstephh 			case FM_SUSPECT_DEGRADED:
17477275Sstephh 				msg = dgettext("FMD", "degraded");
17487275Sstephh 				break;
17497275Sstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED:
17507275Sstephh 				msg = dgettext("FMD", "degraded");
17517275Sstephh 				break;
17525255Sstephh 			case FM_SUSPECT_FAULTY:
17535255Sstephh 				msg = dgettext("FMD", "degraded");
17545255Sstephh 				break;
17555255Sstephh 			case FM_SUSPECT_UNUSABLE:
17565255Sstephh 				msg = dgettext("FMD", "unknown");
17575255Sstephh 				break;
17585255Sstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
17595255Sstephh 				msg = dgettext("FMD", "faulted");
17605255Sstephh 				break;
17615255Sstephh 			default:
17625255Sstephh 				msg = "";
17635255Sstephh 				break;
17645255Sstephh 			}
17655255Sstephh 			(void) printf("%-69s %s\n", tp->resource, msg);
17665255Sstephh 		}
17675255Sstephh 		tp = tp->next;
17685255Sstephh 		if (tp == status_asru_list)
17695255Sstephh 			break;
17705255Sstephh 	}
17715255Sstephh }
17725255Sstephh 
17735255Sstephh static int
17745255Sstephh uuid_in_list(char *uuid, uurec_select_t *uurecp)
17755255Sstephh {
17765255Sstephh 	while (uurecp) {
17775255Sstephh 		if (strcmp(uuid, uurecp->uuid) == 0)
17785255Sstephh 			return (1);
17795255Sstephh 		uurecp = uurecp->next;
17805255Sstephh 	}
17810Sstevel@tonic-gate 	return (0);
17820Sstevel@tonic-gate }
17830Sstevel@tonic-gate 
17845255Sstephh static int
17855255Sstephh dfault_rec(const fmd_adm_caseinfo_t *acp, void *arg)
17865255Sstephh {
17875255Sstephh 	int64_t *diag_time;
17885255Sstephh 	uint_t nelem;
17895255Sstephh 	int rt = 0;
17905255Sstephh 	char *uuid = "-";
17915255Sstephh 	uurec_select_t *uurecp = (uurec_select_t *)arg;
17925255Sstephh 
17935255Sstephh 	if (nvlist_lookup_int64_array(acp->aci_event, FM_SUSPECT_DIAG_TIME,
17945255Sstephh 	    &diag_time, &nelem) == 0 && nelem >= 2) {
17955255Sstephh 		(void) nvlist_lookup_string(acp->aci_event, FM_SUSPECT_UUID,
17965255Sstephh 		    &uuid);
17975255Sstephh 		if (uurecp == NULL || uuid_in_list(uuid, uurecp))
17985255Sstephh 			add_fault_record_to_catalog(acp->aci_event, *diag_time,
1799*9501SRobert.Johnston@Sun.COM 			    uuid);
18005255Sstephh 	} else {
18015255Sstephh 		rt = -1;
18025255Sstephh 	}
18035255Sstephh 	return (rt);
18045255Sstephh }
18055255Sstephh 
18060Sstevel@tonic-gate /*ARGSUSED*/
18070Sstevel@tonic-gate static int
18085255Sstephh dstatus_rec(const fmd_adm_rsrcinfo_t *ari, void *unused)
18090Sstevel@tonic-gate {
18105255Sstephh 	update_asru_state_in_catalog(ari->ari_case, ari->ari_uuid);
18110Sstevel@tonic-gate 	return (0);
18120Sstevel@tonic-gate }
18130Sstevel@tonic-gate 
18145255Sstephh static int
18155255Sstephh get_cases_from_fmd(fmd_adm_t *adm, uurec_select_t *uurecp, int opt_i)
18165255Sstephh {
18175255Sstephh 	int rt = FMADM_EXIT_SUCCESS;
18185255Sstephh 
18195255Sstephh 	/*
18205255Sstephh 	 * These calls may fail with Protocol error if message payload is to big
18215255Sstephh 	 */
18225255Sstephh 	if (fmd_adm_case_iter(adm, NULL, dfault_rec, uurecp) != 0)
18235255Sstephh 		die("failed to get case list from fmd");
18245255Sstephh 	if (opt_i && fmd_adm_rsrc_iter(adm, 1, dstatus_rec, NULL) != 0)
18255255Sstephh 		die("failed to get case status from fmd");
18265255Sstephh 	return (rt);
18275255Sstephh }
18285255Sstephh 
18295255Sstephh /*
18305255Sstephh  * fmadm faulty command
18315255Sstephh  *
18325255Sstephh  *	-a		show hidden fault records
18335255Sstephh  *	-f		show faulty fru's
18345255Sstephh  *	-g		force grouping of similar faults on the same fru
18355255Sstephh  *	-n		number of fault records to display
18365255Sstephh  *	-p		pipe output through pager
18375255Sstephh  *	-r		show faulty asru's
18385255Sstephh  *	-s		print summary of first fault
18395255Sstephh  *	-u		print listed uuid's only
18405255Sstephh  *	-v		full output
18415255Sstephh  */
18425255Sstephh 
18430Sstevel@tonic-gate int
18440Sstevel@tonic-gate cmd_faulty(fmd_adm_t *adm, int argc, char *argv[])
18450Sstevel@tonic-gate {
18465255Sstephh 	int opt_a = 0, opt_v = 0, opt_p = 0, opt_s = 0, opt_r = 0, opt_f = 0;
18475255Sstephh 	int opt_i = 0;
18485255Sstephh 	char *pager;
18495255Sstephh 	FILE *fp;
18505255Sstephh 	int rt, c, stat;
18515255Sstephh 	uurec_select_t *tp;
18525255Sstephh 	uurec_select_t *uurecp = NULL;
18530Sstevel@tonic-gate 
18545255Sstephh 	while ((c = getopt(argc, argv, "afgin:prsu:v")) != EOF) {
18550Sstevel@tonic-gate 		switch (c) {
18560Sstevel@tonic-gate 		case 'a':
18570Sstevel@tonic-gate 			opt_a++;
18580Sstevel@tonic-gate 			break;
18595255Sstephh 		case 'f':
18605255Sstephh 			opt_f++;
18615255Sstephh 			break;
18625255Sstephh 		case 'g':
18635255Sstephh 			opt_g++;
18645255Sstephh 			break;
18650Sstevel@tonic-gate 		case 'i':
18665255Sstephh 			opt_i++;
18675255Sstephh 			break;
18685255Sstephh 		case 'n':
18695255Sstephh 			max_fault = atoi(optarg);
18705255Sstephh 			break;
18715255Sstephh 		case 'p':
18725255Sstephh 			opt_p++;
18735255Sstephh 			break;
18745255Sstephh 		case 'r':
18755255Sstephh 			opt_r++;
18765255Sstephh 			break;
18775255Sstephh 		case 's':
18785255Sstephh 			opt_s++;
18795255Sstephh 			break;
18805255Sstephh 		case 'u':
18815255Sstephh 			tp = (uurec_select_t *)malloc(sizeof (uurec_select_t));
18825255Sstephh 			tp->uuid = optarg;
18835255Sstephh 			tp->next = uurecp;
18845255Sstephh 			uurecp = tp;
18855255Sstephh 			opt_a = 1;
18865255Sstephh 			break;
18875255Sstephh 		case 'v':
18885255Sstephh 			opt_v++;
18890Sstevel@tonic-gate 			break;
18900Sstevel@tonic-gate 		default:
18910Sstevel@tonic-gate 			return (FMADM_EXIT_USAGE);
18920Sstevel@tonic-gate 		}
18930Sstevel@tonic-gate 	}
18940Sstevel@tonic-gate 	if (optind < argc)
18950Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
18960Sstevel@tonic-gate 
1897*9501SRobert.Johnston@Sun.COM 	if ((fmadm_msghdl = fmd_msg_init(NULL, FMD_MSG_VERSION)) == NULL)
1898*9501SRobert.Johnston@Sun.COM 		return (FMADM_EXIT_ERROR);
18995255Sstephh 	rt = get_cases_from_fmd(adm, uurecp, opt_i);
19005255Sstephh 	if (opt_p) {
19015255Sstephh 		if ((pager = getenv("PAGER")) == NULL)
19025255Sstephh 			pager = "/usr/bin/more";
19035255Sstephh 		fp = popen(pager, "w");
19045255Sstephh 		if (fp == NULL) {
19055255Sstephh 			rt = FMADM_EXIT_ERROR;
19065255Sstephh 			opt_p = 0;
19075255Sstephh 		} else {
19085255Sstephh 			dup2(fileno(fp), 1);
19095255Sstephh 			setbuf(stdout, NULL);
19105255Sstephh 			(void) fclose(fp);
19115255Sstephh 		}
19125255Sstephh 	}
19135255Sstephh 	max_display = max_fault;
19145255Sstephh 	if (opt_f)
19155255Sstephh 		print_fru(opt_s, opt_a, opt_i, opt_p && !opt_s);
19165255Sstephh 	if (opt_r)
19175255Sstephh 		print_asru(opt_a);
19185255Sstephh 	if (opt_f == 0 && opt_r == 0)
19195255Sstephh 		print_catalog(opt_s, opt_a, opt_v, opt_i, opt_p && !opt_s);
1920*9501SRobert.Johnston@Sun.COM 	fmd_msg_fini(fmadm_msghdl);
19215255Sstephh 	label_release_topo();
19225255Sstephh 	if (opt_p) {
19235255Sstephh 		(void) fclose(stdout);
19245255Sstephh 		(void) wait(&stat);
19255255Sstephh 	}
19265255Sstephh 	return (rt);
19270Sstevel@tonic-gate }
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate int
19300Sstevel@tonic-gate cmd_flush(fmd_adm_t *adm, int argc, char *argv[])
19310Sstevel@tonic-gate {
19320Sstevel@tonic-gate 	int i, status = FMADM_EXIT_SUCCESS;
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 	if (argc < 2 || (i = getopt(argc, argv, "")) != EOF)
19350Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate 	for (i = 1; i < argc; i++) {
19380Sstevel@tonic-gate 		if (fmd_adm_rsrc_flush(adm, argv[i]) != 0) {
19390Sstevel@tonic-gate 			warn("failed to flush %s", argv[i]);
19400Sstevel@tonic-gate 			status = FMADM_EXIT_ERROR;
19410Sstevel@tonic-gate 		} else
19420Sstevel@tonic-gate 			note("flushed resource history for %s\n", argv[i]);
19430Sstevel@tonic-gate 	}
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 	return (status);
19460Sstevel@tonic-gate }
19470Sstevel@tonic-gate 
19480Sstevel@tonic-gate int
19490Sstevel@tonic-gate cmd_repair(fmd_adm_t *adm, int argc, char *argv[])
19500Sstevel@tonic-gate {
19510Sstevel@tonic-gate 	int err;
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 	if (getopt(argc, argv, "") != EOF)
19540Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	if (argc - optind != 1)
19570Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate 	/*
19607275Sstephh 	 * argument could be a uuid, an fmri (asru, fru or resource)
19616228Sstephh 	 * or a label. Try uuid first, If that fails try the others.
19620Sstevel@tonic-gate 	 */
19636228Sstephh 	err = fmd_adm_case_repair(adm, argv[optind]);
19646228Sstephh 	if (err != 0)
19657275Sstephh 		err = fmd_adm_rsrc_repaired(adm, argv[optind]);
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 	if (err != 0)
19680Sstevel@tonic-gate 		die("failed to record repair to %s", argv[optind]);
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate 	note("recorded repair to %s\n", argv[optind]);
19710Sstevel@tonic-gate 	return (FMADM_EXIT_SUCCESS);
19720Sstevel@tonic-gate }
19737275Sstephh 
19747275Sstephh int
19757275Sstephh cmd_repaired(fmd_adm_t *adm, int argc, char *argv[])
19767275Sstephh {
19777275Sstephh 	int err;
19787275Sstephh 
19797275Sstephh 	if (getopt(argc, argv, "") != EOF)
19807275Sstephh 		return (FMADM_EXIT_USAGE);
19817275Sstephh 
19827275Sstephh 	if (argc - optind != 1)
19837275Sstephh 		return (FMADM_EXIT_USAGE);
19847275Sstephh 
19857275Sstephh 	/*
19867275Sstephh 	 * argument could be an fmri (asru, fru or resource) or a label.
19877275Sstephh 	 */
19887275Sstephh 	err = fmd_adm_rsrc_repaired(adm, argv[optind]);
19897275Sstephh 	if (err != 0)
19907275Sstephh 		die("failed to record repair to %s", argv[optind]);
19917275Sstephh 
19927275Sstephh 	note("recorded repair to of %s\n", argv[optind]);
19937275Sstephh 	return (FMADM_EXIT_SUCCESS);
19947275Sstephh }
19957275Sstephh 
19967275Sstephh int
19977275Sstephh cmd_replaced(fmd_adm_t *adm, int argc, char *argv[])
19987275Sstephh {
19997275Sstephh 	int err;
20007275Sstephh 
20017275Sstephh 	if (getopt(argc, argv, "") != EOF)
20027275Sstephh 		return (FMADM_EXIT_USAGE);
20037275Sstephh 
20047275Sstephh 	if (argc - optind != 1)
20057275Sstephh 		return (FMADM_EXIT_USAGE);
20067275Sstephh 
20077275Sstephh 	/*
20087275Sstephh 	 * argument could be an fmri (asru, fru or resource) or a label.
20097275Sstephh 	 */
20107275Sstephh 	err = fmd_adm_rsrc_replaced(adm, argv[optind]);
20117275Sstephh 	if (err != 0)
20127275Sstephh 		die("failed to record replacement of %s", argv[optind]);
20137275Sstephh 
20147275Sstephh 	note("recorded replacement of %s\n", argv[optind]);
20157275Sstephh 	return (FMADM_EXIT_SUCCESS);
20167275Sstephh }
20177275Sstephh 
20187275Sstephh int
20197275Sstephh cmd_acquit(fmd_adm_t *adm, int argc, char *argv[])
20207275Sstephh {
20217275Sstephh 	int err;
20227275Sstephh 
20237275Sstephh 	if (getopt(argc, argv, "") != EOF)
20247275Sstephh 		return (FMADM_EXIT_USAGE);
20257275Sstephh 
20267275Sstephh 	if (argc - optind != 1 && argc - optind != 2)
20277275Sstephh 		return (FMADM_EXIT_USAGE);
20287275Sstephh 
20297275Sstephh 	/*
20307275Sstephh 	 * argument could be a uuid, an fmri (asru, fru or resource)
20317275Sstephh 	 * or a label. Or it could be a uuid and an fmri or label.
20327275Sstephh 	 */
20337275Sstephh 	if (argc - optind == 2) {
20347275Sstephh 		err = fmd_adm_rsrc_acquit(adm, argv[optind], argv[optind + 1]);
20357275Sstephh 		if (err != 0)
20367275Sstephh 			err = fmd_adm_rsrc_acquit(adm, argv[optind + 1],
20377275Sstephh 			    argv[optind]);
20387275Sstephh 	} else {
20397275Sstephh 		err = fmd_adm_case_acquit(adm, argv[optind]);
20407275Sstephh 		if (err != 0)
20417275Sstephh 			err = fmd_adm_rsrc_acquit(adm, argv[optind], "");
20427275Sstephh 	}
20437275Sstephh 
20447275Sstephh 	if (err != 0)
20457275Sstephh 		die("failed to record acquital of %s", argv[optind]);
20467275Sstephh 
20477275Sstephh 	note("recorded acquital of %s\n", argv[optind]);
20487275Sstephh 	return (FMADM_EXIT_SUCCESS);
20497275Sstephh }
2050