xref: /illumos-gate/usr/src/cmd/fm/fmadm/common/faulty.c (revision b6955755)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
544743693Sstephh  * Common Development and Distribution License (the "License").
644743693Sstephh  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22cbf75e67SStephen Hanson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
2644743693Sstephh #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <fmadm.h>
2844743693Sstephh #include <errno.h>
2944743693Sstephh #include <limits.h>
3044743693Sstephh #include <strings.h>
3144743693Sstephh #include <stdio.h>
3244743693Sstephh #include <unistd.h>
3344743693Sstephh #include <sys/wait.h>
3444743693Sstephh #include <sys/stat.h>
3544743693Sstephh #include <fcntl.h>
3644743693Sstephh #include <fm/fmd_log.h>
3744743693Sstephh #include <sys/fm/protocol.h>
3844743693Sstephh #include <fm/libtopo.h>
3944743693Sstephh #include <fm/fmd_adm.h>
40*b6955755SRobert Johnston #include <fm/fmd_msg.h>
4144743693Sstephh #include <dlfcn.h>
4244743693Sstephh #include <sys/systeminfo.h>
4344743693Sstephh #include <sys/utsname.h>
4444743693Sstephh #include <libintl.h>
4544743693Sstephh #include <locale.h>
4644743693Sstephh #include <sys/smbios.h>
4744743693Sstephh #include <libdevinfo.h>
4844743693Sstephh #include <stdlib.h>
4944743693Sstephh 
5044743693Sstephh #define	offsetof(s, m)	((size_t)(&(((s*)0)->m)))
5144743693Sstephh 
5244743693Sstephh /*
5344743693Sstephh  * Fault records are added to catalog by calling add_fault_record_to_catalog()
5444743693Sstephh  * records are stored in order of importance to the system.
5544743693Sstephh  * If -g flag is set or not_suppressed is not set and the class fru, fault,
5644743693Sstephh  * type are the same then details are merged into an existing record, with uuid
5744743693Sstephh  * records are stored in time order.
5844743693Sstephh  * For each record information is extracted from nvlist and merged into linked
5944743693Sstephh  * list each is checked for identical records for which percentage certainty are
6044743693Sstephh  * added together.
6144743693Sstephh  * print_catalog() is called to print out catalog and release external resources
6244743693Sstephh  *
6344743693Sstephh  *                         /---------------\
6444743693Sstephh  *	status_rec_list -> |               | -|
6544743693Sstephh  *                         \---------------/
6644743693Sstephh  *                                \/
6744743693Sstephh  *                         /---------------\    /-------\    /-------\
6844743693Sstephh  *      status_fru_list    | status_record | -> | uurec | -> | uurec | -|
6944743693Sstephh  *            \/           |               | |- |       | <- |       |
7044743693Sstephh  *      /-------------\    |               |    \-------/    \-------/
7144743693Sstephh  *      |             | -> |               |       \/           \/
7244743693Sstephh  *      \-------------/    |               |    /-------\    /-------\
7344743693Sstephh  *            \/           |               | -> | asru  | -> | asru  |
7444743693Sstephh  *            ---          |               |    |       | <- |       |
7544743693Sstephh  *                         |               |    \-------/    \-------/
7644743693Sstephh  *      status_asru_list   |  class        |
7744743693Sstephh  *            \/           |  resource     |    /-------\    /-------\
7844743693Sstephh  *      /-------------\    |  fru          | -> | list  | -> | list  |
7944743693Sstephh  *      |             | -> |  serial       |    |       | <- |       |
8044743693Sstephh  *      \-------------/    |               |    \-------/    \-------/
8144743693Sstephh  *            \/           \---------------/
8244743693Sstephh  *            ---               \/    /\
8344743693Sstephh  *                         /---------------\
8444743693Sstephh  *                         | status_record |
8544743693Sstephh  *                         \---------------/
8644743693Sstephh  *
8744743693Sstephh  * Fmadm faulty takes a number of options which affect the format of the
8844743693Sstephh  * output displayed. By default, the display reports the FRU and ASRU along
8944743693Sstephh  * with other information on per-case basis as in the example below.
9044743693Sstephh  *
9144743693Sstephh  * --------------- ------------------------------------  -------------- -------
9244743693Sstephh  * TIME            EVENT-ID                              MSG-ID         SEVERITY
9344743693Sstephh  * --------------- ------------------------------------  -------------- -------
9444743693Sstephh  * Sep 21 10:01:36 d482f935-5c8f-e9ab-9f25-d0aaafec1e6c  AMD-8000-2F    Major
9544743693Sstephh  *
9644743693Sstephh  * Fault class	: fault.memory.dimm_sb
9744743693Sstephh  * Affects	: mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0
9825c6ff4bSstephh  *		    faulted but still in service
9944743693Sstephh  * FRU		: "CPU 0 DIMM 0" (hc://.../memory-controller=0/dimm=0)
10044743693Sstephh  *		    faulty
10144743693Sstephh  *
10244743693Sstephh  * Description	: The number of errors associated with this memory module has
10344743693Sstephh  *		exceeded acceptable levels.  Refer to
10444743693Sstephh  *		http://sun.com/msg/AMD-8000-2F for more information.
10544743693Sstephh  *
10644743693Sstephh  * Response	: Pages of memory associated with this memory module are being
10744743693Sstephh  *		removed from service as errors are reported.
10844743693Sstephh  *
10944743693Sstephh  * Impact	: Total system memory capacity will be reduced as pages are
11044743693Sstephh  *		retired.
11144743693Sstephh  *
11244743693Sstephh  * Action	: Schedule a repair procedure to replace the affected memory
11344743693Sstephh  *		module.  Use fmdump -v -u <EVENT_ID> to identify the module.
11444743693Sstephh  *
11544743693Sstephh  * The -v flag is similar, but adds some additonal information such as the
11644743693Sstephh  * resource. The -s flag is also similar but just gives the top line summary.
11744743693Sstephh  * All these options (ie without the -f or -r flags) use the print_catalog()
11844743693Sstephh  * function to do the display.
11944743693Sstephh  *
12044743693Sstephh  * The -f flag changes the output so that it appears sorted on a per-fru basis.
12144743693Sstephh  * The output is somewhat cut down compared to the default output. If -f is
12244743693Sstephh  * used, then print_fru() is used to print the output.
12344743693Sstephh  *
12444743693Sstephh  * -----------------------------------------------------------------------------
12544743693Sstephh  * "SLOT 2" (hc://.../hostbridge=3/pciexrc=3/pciexbus=4/pciexdev=0) faulty
12644743693Sstephh  * 5ca4aeb3-36...f6be-c2e8166dc484 2 suspects in this FRU total certainty 100%
12744743693Sstephh  *
12844743693Sstephh  * Description	: A problem was detected for a PCI device.
12944743693Sstephh  *		Refer to http://sun.com/msg/PCI-8000-7J for more information.
13044743693Sstephh  *
13144743693Sstephh  * Response	: One or more device instances may be disabled
13244743693Sstephh  *
13344743693Sstephh  * Impact	: Possible loss of services provided by the device instances
13444743693Sstephh  *		associated with this fault
13544743693Sstephh  *
13644743693Sstephh  * Action	: Schedule a repair procedure to replace the affected device.
13744743693Sstephh  * 		Use fmdump -v -u <EVENT_ID> to identify the device or contact
13844743693Sstephh  *		Sun for support.
13944743693Sstephh  *
14044743693Sstephh  * The -r flag changes the output so that it appears sorted on a per-asru basis.
14144743693Sstephh  * The output is very much cut down compared to the default output, just giving
14244743693Sstephh  * the asru fmri and state. Here print_asru() is used to print the output.
14344743693Sstephh  *
14444743693Sstephh  * mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0	degraded
14544743693Sstephh  *
14644743693Sstephh  * For all fmadm faulty options, the sequence of events is
14744743693Sstephh  *
14844743693Sstephh  * 1) Walk through all the cases in the system using fmd_adm_case_iter() and
14944743693Sstephh  * for each case call dfault_rec(). This will call add_fault_record_to_catalog()
15044743693Sstephh  * This will extract the data from the nvlist and call catalog_new_record() to
15144743693Sstephh  * save the data away in various linked lists in the catalogue.
15244743693Sstephh  *
15344743693Sstephh  * 2) Once this is done, the data can be supplemented by using
15444743693Sstephh  * fmd_adm_rsrc_iter(). However this is now only necessary for the -i option.
15544743693Sstephh  *
15644743693Sstephh  * 3) Finally print_catalog(), print_fru() or print_asru() are called as
15744743693Sstephh  * appropriate to display the information from the catalogue sorted in the
15844743693Sstephh  * requested way.
15944743693Sstephh  *
16044743693Sstephh  */
16144743693Sstephh 
16244743693Sstephh typedef struct name_list {
16344743693Sstephh 	struct name_list *next;
16444743693Sstephh 	struct name_list *prev;
16544743693Sstephh 	char *name;
16644743693Sstephh 	uint8_t pct;
16744743693Sstephh 	uint8_t max_pct;
16844743693Sstephh 	ushort_t count;
16944743693Sstephh 	int status;
170d4c0a8c5Sstephh 	char *label;
17144743693Sstephh } name_list_t;
17244743693Sstephh 
17344743693Sstephh typedef struct ari_list {
17444743693Sstephh 	char *ari_uuid;
17544743693Sstephh 	struct ari_list *next;
17644743693Sstephh } ari_list_t;
17744743693Sstephh 
17844743693Sstephh typedef struct uurec {
17944743693Sstephh 	struct uurec *next;
18044743693Sstephh 	struct uurec *prev;
18144743693Sstephh 	char *uuid;
18244743693Sstephh 	ari_list_t *ari_uuid_list;
18344743693Sstephh 	name_list_t *asru;
18444743693Sstephh 	uint64_t sec;
18544743693Sstephh } uurec_t;
18644743693Sstephh 
18744743693Sstephh typedef struct uurec_select {
18844743693Sstephh 	struct uurec_select *next;
18944743693Sstephh 	char *uuid;
19044743693Sstephh } uurec_select_t;
19144743693Sstephh 
19244743693Sstephh typedef struct host_id {
19344743693Sstephh 	char *chassis;
19444743693Sstephh 	char *server;
19544743693Sstephh 	char *platform;
196cbf75e67SStephen Hanson 	char *domain;
19744743693Sstephh } hostid_t;
19844743693Sstephh 
19944743693Sstephh typedef struct host_id_list {
20044743693Sstephh 	hostid_t hostid;
20144743693Sstephh 	struct host_id_list *next;
20244743693Sstephh } host_id_list_t;
20344743693Sstephh 
20444743693Sstephh typedef struct status_record {
20544743693Sstephh 	hostid_t *host;
20644743693Sstephh 	int nrecs;
20744743693Sstephh 	uurec_t *uurec;
20844743693Sstephh 	char *severity;			/* in C locale */
20944743693Sstephh 	char *msgid;
21044743693Sstephh 	name_list_t *class;
21144743693Sstephh 	name_list_t *resource;
21244743693Sstephh 	name_list_t *asru;
21344743693Sstephh 	name_list_t *fru;
21444743693Sstephh 	name_list_t *serial;
21544743693Sstephh 	uint8_t not_suppressed;
21644743693Sstephh } status_record_t;
21744743693Sstephh 
21844743693Sstephh typedef struct sr_list {
21944743693Sstephh 	struct sr_list *next;
22044743693Sstephh 	struct sr_list *prev;
22144743693Sstephh 	struct status_record *status_record;
22244743693Sstephh } sr_list_t;
22344743693Sstephh 
22444743693Sstephh typedef struct resource_list {
22544743693Sstephh 	struct resource_list *next;
22644743693Sstephh 	struct resource_list *prev;
22744743693Sstephh 	sr_list_t *status_rec_list;
22844743693Sstephh 	char *resource;
22944743693Sstephh 	uint8_t not_suppressed;
23044743693Sstephh 	uint8_t max_pct;
23144743693Sstephh } resource_list_t;
23244743693Sstephh 
23344743693Sstephh typedef struct tgetlabel_data {
23444743693Sstephh 	char *label;
23544743693Sstephh 	char *fru;
23644743693Sstephh } tgetlabel_data_t;
23744743693Sstephh 
23844743693Sstephh sr_list_t *status_rec_list;
23944743693Sstephh resource_list_t *status_fru_list;
24044743693Sstephh resource_list_t *status_asru_list;
24144743693Sstephh 
24244743693Sstephh static int max_display;
24344743693Sstephh static int max_fault = 0;
24444743693Sstephh static topo_hdl_t *topo_handle;
24544743693Sstephh static char *topo_handle_uuid;
24644743693Sstephh static host_id_list_t *host_list;
24744743693Sstephh static int n_server;
24844743693Sstephh static int opt_g;
249*b6955755SRobert Johnston static fmd_msg_hdl_t *fmadm_msghdl = NULL; /* handle for libfmd_msg calls */
25044743693Sstephh 
25144743693Sstephh static char *
25244743693Sstephh format_date(char *buf, size_t len, uint64_t sec)
25344743693Sstephh {
25444743693Sstephh 	if (sec > LONG_MAX) {
25544743693Sstephh 		(void) fprintf(stderr,
25644743693Sstephh 		    "record time is too large for 32-bit utility\n");
25744743693Sstephh 		(void) snprintf(buf, len, "0x%llx", sec);
25844743693Sstephh 	} else {
25944743693Sstephh 		time_t tod = (time_t)sec;
26044743693Sstephh 		(void) strftime(buf, len, "%b %d %T", localtime(&tod));
26144743693Sstephh 	}
26244743693Sstephh 
26344743693Sstephh 	return (buf);
26444743693Sstephh }
26544743693Sstephh 
26644743693Sstephh static hostid_t *
267cbf75e67SStephen Hanson find_hostid_in_list(char *platform, char *chassis, char *server, char *domain)
26844743693Sstephh {
26944743693Sstephh 	hostid_t *rt = NULL;
27044743693Sstephh 	host_id_list_t *hostp;
27144743693Sstephh 
27244743693Sstephh 	if (platform == NULL)
27344743693Sstephh 		platform = "-";
27444743693Sstephh 	if (server == NULL)
27544743693Sstephh 		server = "-";
27644743693Sstephh 	hostp = host_list;
27744743693Sstephh 	while (hostp) {
27844743693Sstephh 		if (hostp->hostid.platform &&
27944743693Sstephh 		    strcmp(hostp->hostid.platform, platform) == 0 &&
28044743693Sstephh 		    hostp->hostid.server &&
28144743693Sstephh 		    strcmp(hostp->hostid.server, server) == 0 &&
28244743693Sstephh 		    (chassis == NULL || hostp->hostid.chassis == NULL ||
283cbf75e67SStephen Hanson 		    strcmp(chassis, hostp->hostid.chassis) == 0) &&
284cbf75e67SStephen Hanson 		    (domain == NULL || hostp->hostid.domain == NULL ||
285cbf75e67SStephen Hanson 		    strcmp(domain, hostp->hostid.domain) == 0)) {
28644743693Sstephh 			rt = &hostp->hostid;
28744743693Sstephh 			break;
28844743693Sstephh 		}
28944743693Sstephh 		hostp = hostp->next;
29044743693Sstephh 	}
29144743693Sstephh 	if (rt == NULL) {
29244743693Sstephh 		hostp = malloc(sizeof (host_id_list_t));
29344743693Sstephh 		hostp->hostid.platform = strdup(platform);
29444743693Sstephh 		hostp->hostid.server = strdup(server);
29544743693Sstephh 		hostp->hostid.chassis = chassis ? strdup(chassis) : NULL;
296cbf75e67SStephen Hanson 		hostp->hostid.domain = domain ? strdup(domain) : NULL;
29744743693Sstephh 		hostp->next = host_list;
29844743693Sstephh 		host_list = hostp;
29944743693Sstephh 		rt = &hostp->hostid;
30044743693Sstephh 		n_server++;
30144743693Sstephh 	}
30244743693Sstephh 	return (rt);
30344743693Sstephh }
30444743693Sstephh 
30544743693Sstephh static hostid_t *
30644743693Sstephh find_hostid(nvlist_t *nvl)
30744743693Sstephh {
308cbf75e67SStephen Hanson 	char *platform = NULL, *chassis = NULL, *server = NULL, *domain = NULL;
30944743693Sstephh 	nvlist_t *auth, *fmri;
31044743693Sstephh 	hostid_t *rt = NULL;
31144743693Sstephh 
31244743693Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &fmri) == 0 &&
31344743693Sstephh 	    nvlist_lookup_nvlist(fmri, FM_FMRI_AUTHORITY, &auth) == 0) {
31444743693Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT,
31544743693Sstephh 		    &platform);
31644743693Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server);
31744743693Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS,
31844743693Sstephh 		    &chassis);
319cbf75e67SStephen Hanson 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_DOMAIN, &domain);
320cbf75e67SStephen Hanson 		rt = find_hostid_in_list(platform, chassis, server, domain);
32144743693Sstephh 	}
32244743693Sstephh 	return (rt);
32344743693Sstephh }
32444743693Sstephh 
32544743693Sstephh /*
32644743693Sstephh  * compare two fru strings which are made up of substrings seperated by '/'
32744743693Sstephh  * return true if every substring is the same in the two strings, or if a
32844743693Sstephh  * substring is null in one.
32944743693Sstephh  */
33044743693Sstephh 
33144743693Sstephh static int
33244743693Sstephh frucmp(char *f1, char *f2)
33344743693Sstephh {
33444743693Sstephh 	char c1, c2;
33544743693Sstephh 	int i = 0;
33644743693Sstephh 
33744743693Sstephh 	for (;;) {
33844743693Sstephh 		c1 = *f1;
33944743693Sstephh 		c2 = *f2;
34044743693Sstephh 		if (c1 == c2) {
34144743693Sstephh 			i = (c1 == '/') ? 0 : i + 1;
34244743693Sstephh 		} else if (i == 0) {
34344743693Sstephh 			if (c1 == '/') {
34444743693Sstephh 				do {
34544743693Sstephh 					f2++;
34644743693Sstephh 				} while ((c2 = *f2) != 0 && c2 != '/');
34744743693Sstephh 				if (c2 == NULL)
34844743693Sstephh 					break;
34944743693Sstephh 			} else if (c2 == '/') {
35044743693Sstephh 				do {
35144743693Sstephh 					f1++;
35244743693Sstephh 				} while ((c1 = *f1) != 0 && c1 != '/');
35344743693Sstephh 				if (c1 == NULL)
35444743693Sstephh 					break;
35544743693Sstephh 			} else
35644743693Sstephh 				break;
35744743693Sstephh 		} else
35844743693Sstephh 			break;
35944743693Sstephh 		if (c1 == NULL)
36044743693Sstephh 			return (0);
36144743693Sstephh 		f1++;
36244743693Sstephh 		f2++;
36344743693Sstephh 	}
36444743693Sstephh 	return (1);
36544743693Sstephh }
36644743693Sstephh 
36744743693Sstephh static int
36844743693Sstephh tgetlabel(topo_hdl_t *thp, tnode_t *node, void *arg)
36944743693Sstephh {
37044743693Sstephh 	int err;
37144743693Sstephh 	char *fru_name, *lname;
37244743693Sstephh 	nvlist_t *fru = NULL;
37344743693Sstephh 	int rt = TOPO_WALK_NEXT;
37444743693Sstephh 	tgetlabel_data_t *tdp = (tgetlabel_data_t *)arg;
37544743693Sstephh 
37644743693Sstephh 	if (topo_node_fru(node, &fru, NULL, &err) == 0) {
37744743693Sstephh 		if (topo_fmri_nvl2str(thp, fru, &fru_name, &err) == 0) {
37844743693Sstephh 			if (frucmp(tdp->fru, fru_name) == 0 &&
37944743693Sstephh 			    topo_node_label(node, &lname, &err) == 0) {
38044743693Sstephh 				tdp->label = strdup(lname);
38144743693Sstephh 				topo_hdl_strfree(thp, lname);
38244743693Sstephh 				rt = TOPO_WALK_TERMINATE;
38344743693Sstephh 			}
38444743693Sstephh 			topo_hdl_strfree(thp, fru_name);
38544743693Sstephh 		}
38644743693Sstephh 		nvlist_free(fru);
38744743693Sstephh 	}
38844743693Sstephh 	return (rt);
38944743693Sstephh }
39044743693Sstephh 
39144743693Sstephh static void
39244743693Sstephh label_get_topo(void)
39344743693Sstephh {
39444743693Sstephh 	int err;
39544743693Sstephh 
39644743693Sstephh 	topo_handle = topo_open(TOPO_VERSION, 0, &err);
39744743693Sstephh 	if (topo_handle) {
39844743693Sstephh 		topo_handle_uuid = topo_snap_hold(topo_handle, NULL, &err);
39944743693Sstephh 	}
40044743693Sstephh }
40144743693Sstephh 
40244743693Sstephh static void
40344743693Sstephh label_release_topo(void)
40444743693Sstephh {
40544743693Sstephh 	if (topo_handle_uuid)
40644743693Sstephh 		topo_hdl_strfree(topo_handle, topo_handle_uuid);
40744743693Sstephh 	if (topo_handle) {
40844743693Sstephh 		topo_snap_release(topo_handle);
40944743693Sstephh 		topo_close(topo_handle);
41044743693Sstephh 	}
41144743693Sstephh }
41244743693Sstephh 
41344743693Sstephh static char *
41444743693Sstephh get_fmri_label(char *fru)
41544743693Sstephh {
41644743693Sstephh 	topo_walk_t *twp;
41744743693Sstephh 	tgetlabel_data_t td;
41844743693Sstephh 	int err;
41944743693Sstephh 
42044743693Sstephh 	td.label = NULL;
42144743693Sstephh 	td.fru = fru;
42244743693Sstephh 	if (topo_handle == NULL)
42344743693Sstephh 		label_get_topo();
42444743693Sstephh 	if (topo_handle_uuid) {
42544743693Sstephh 		twp = topo_walk_init(topo_handle, FM_FMRI_SCHEME_HC,
42644743693Sstephh 		    tgetlabel, &td, &err);
42744743693Sstephh 		if (twp) {
42844743693Sstephh 			topo_walk_step(twp, TOPO_WALK_CHILD);
42944743693Sstephh 			topo_walk_fini(twp);
43044743693Sstephh 		}
43144743693Sstephh 	}
43244743693Sstephh 	return (td.label);
43344743693Sstephh }
43444743693Sstephh 
43544743693Sstephh static char *
43644743693Sstephh get_nvl2str_topo(nvlist_t *nvl)
43744743693Sstephh {
43844743693Sstephh 	char *name = NULL;
43944743693Sstephh 	char *tname;
44044743693Sstephh 	int err;
44144743693Sstephh 	char *scheme = NULL;
44244743693Sstephh 	char *mod_name = NULL;
44344743693Sstephh 	char buf[128];
44444743693Sstephh 
44544743693Sstephh 	if (topo_handle == NULL)
44644743693Sstephh 		label_get_topo();
44744743693Sstephh 	if (topo_fmri_nvl2str(topo_handle, nvl, &tname, &err) == 0) {
44844743693Sstephh 		name = strdup(tname);
44944743693Sstephh 		topo_hdl_strfree(topo_handle, tname);
45044743693Sstephh 	} else {
45144743693Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme);
45244743693Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_MOD_NAME, &mod_name);
45344743693Sstephh 		if (scheme && strcmp(scheme, FM_FMRI_SCHEME_FMD) == 0 &&
45444743693Sstephh 		    mod_name) {
45544743693Sstephh 			(void) snprintf(buf, sizeof (buf), "%s:///module/%s",
45644743693Sstephh 			    scheme, mod_name);
45744743693Sstephh 			name = strdup(buf);
45844743693Sstephh 		}
45944743693Sstephh 	}
46044743693Sstephh 	return (name);
46144743693Sstephh }
46244743693Sstephh 
46344743693Sstephh static int
46444743693Sstephh set_priority(char *s)
46544743693Sstephh {
46644743693Sstephh 	int rt = 0;
46744743693Sstephh 
46844743693Sstephh 	if (s) {
46944743693Sstephh 		if (strcmp(s, "Minor") == 0)
47044743693Sstephh 			rt = 1;
47144743693Sstephh 		else if (strcmp(s, "Major") == 0)
47244743693Sstephh 			rt = 10;
47344743693Sstephh 		else if (strcmp(s, "Critical") == 0)
47444743693Sstephh 			rt = 100;
47544743693Sstephh 	}
47644743693Sstephh 	return (rt);
47744743693Sstephh }
47844743693Sstephh 
47944743693Sstephh static int
48044743693Sstephh cmp_priority(char *s1, char *s2, uint64_t t1, uint64_t t2, uint8_t p1,
48144743693Sstephh     uint8_t p2)
48244743693Sstephh {
48344743693Sstephh 	int r1, r2;
48444743693Sstephh 	int rt;
48544743693Sstephh 
48644743693Sstephh 	r1 = set_priority(s1);
48744743693Sstephh 	r2 = set_priority(s2);
48844743693Sstephh 	rt = r1 - r2;
48944743693Sstephh 	if (rt == 0) {
49044743693Sstephh 		if (t1 > t2)
49144743693Sstephh 			rt = 1;
49244743693Sstephh 		else if (t1 < t2)
49344743693Sstephh 			rt = -1;
49444743693Sstephh 		else
49544743693Sstephh 			rt = p1 - p2;
49644743693Sstephh 	}
49744743693Sstephh 	return (rt);
49844743693Sstephh }
49944743693Sstephh 
50044743693Sstephh /*
50144743693Sstephh  * merge two lists into one, by comparing enties in new and moving into list if
50244743693Sstephh  * name is not there or free off memory for names which are already there
50344743693Sstephh  * add_pct indicates if pct is the sum or highest pct
50444743693Sstephh  */
50544743693Sstephh static name_list_t *
50644743693Sstephh merge_name_list(name_list_t **list, name_list_t *new, int add_pct)
50744743693Sstephh {
50844743693Sstephh 	name_list_t *lp, *np, *sp, *rt = NULL;
50944743693Sstephh 	int max_pct;
51044743693Sstephh 
51144743693Sstephh 	rt = *list;
51244743693Sstephh 	np = new;
51344743693Sstephh 	while (np) {
51444743693Sstephh 		lp = *list;
51544743693Sstephh 		while (lp) {
51644743693Sstephh 			if (strcmp(lp->name, np->name) == 0)
51744743693Sstephh 				break;
51844743693Sstephh 			lp = lp->next;
51944743693Sstephh 			if (lp == *list)
52044743693Sstephh 				lp = NULL;
52144743693Sstephh 		}
52244743693Sstephh 		if (np->next == new)
52344743693Sstephh 			sp = NULL;
52444743693Sstephh 		else
52544743693Sstephh 			sp = np->next;
52644743693Sstephh 		if (lp) {
52744743693Sstephh 			lp->status |= (np->status & FM_SUSPECT_FAULTY);
52844743693Sstephh 			if (add_pct) {
52944743693Sstephh 				lp->pct += np->pct;
53044743693Sstephh 				lp->count += np->count;
53144743693Sstephh 			} else if (np->pct > lp->pct) {
53244743693Sstephh 				lp->pct = np->pct;
53344743693Sstephh 			}
53444743693Sstephh 			max_pct = np->max_pct;
535d4c0a8c5Sstephh 			if (np->label)
536d4c0a8c5Sstephh 				free(np->label);
53744743693Sstephh 			free(np->name);
53844743693Sstephh 			free(np);
53944743693Sstephh 			np = NULL;
54044743693Sstephh 			if (max_pct > lp->max_pct) {
54144743693Sstephh 				lp->max_pct = max_pct;
54244743693Sstephh 				if (lp->max_pct > lp->prev->max_pct &&
54344743693Sstephh 				    lp != *list) {
54444743693Sstephh 					lp->prev->next = lp->next;
54544743693Sstephh 					lp->next->prev = lp->prev;
54644743693Sstephh 					np = lp;
54744743693Sstephh 				}
54844743693Sstephh 			}
54944743693Sstephh 		}
55044743693Sstephh 		if (np) {
55144743693Sstephh 			lp = *list;
55244743693Sstephh 			if (lp) {
55344743693Sstephh 				if (np->max_pct > lp->max_pct) {
55444743693Sstephh 					np->next = lp;
55544743693Sstephh 					np->prev = lp->prev;
55644743693Sstephh 					lp->prev->next = np;
55744743693Sstephh 					lp->prev = np;
55844743693Sstephh 					*list = np;
55944743693Sstephh 					rt = np;
56044743693Sstephh 				} else {
56144743693Sstephh 					lp = lp->next;
56244743693Sstephh 					while (lp != *list &&
56344743693Sstephh 					    np->max_pct < lp->max_pct) {
56444743693Sstephh 						lp = lp->next;
56544743693Sstephh 					}
56644743693Sstephh 					np->next = lp;
56744743693Sstephh 					np->prev = lp->prev;
56844743693Sstephh 					lp->prev->next = np;
56944743693Sstephh 					lp->prev = np;
57044743693Sstephh 				}
57144743693Sstephh 			} else {
57244743693Sstephh 				*list = np;
57344743693Sstephh 				np->next = np;
57444743693Sstephh 				np->prev = np;
57544743693Sstephh 				rt = np;
57644743693Sstephh 			}
57744743693Sstephh 		}
57844743693Sstephh 		np = sp;
57944743693Sstephh 	}
58044743693Sstephh 	return (rt);
58144743693Sstephh }
58244743693Sstephh 
58344743693Sstephh /*
58444743693Sstephh  * compare entries in two lists return true if the two lists have identical
58544743693Sstephh  * content. The two lists may not have entries in the same order, so we compare
58644743693Sstephh  * the size of the list as well as trying to find every entry from one list in
58744743693Sstephh  * the other.
58844743693Sstephh  */
58944743693Sstephh static int
59044743693Sstephh cmp_name_list(name_list_t *lxp1, name_list_t *lxp2)
59144743693Sstephh {
59244743693Sstephh 	name_list_t *lp1, *lp2;
59344743693Sstephh 	int l1 = 0, l2 = 0, common = 0;
59444743693Sstephh 
59544743693Sstephh 	lp2 = lxp2;
59644743693Sstephh 	while (lp2) {
59744743693Sstephh 		l2++;
59844743693Sstephh 		lp2 = lp2->next;
59944743693Sstephh 		if (lp2 == lxp2)
60044743693Sstephh 			break;
60144743693Sstephh 	}
60244743693Sstephh 	lp1 = lxp1;
60344743693Sstephh 	while (lp1) {
60444743693Sstephh 		l1++;
60544743693Sstephh 		lp2 = lxp2;
60644743693Sstephh 		while (lp2) {
60744743693Sstephh 			if (strcmp(lp2->name, lp1->name) == 0) {
60844743693Sstephh 				common++;
60944743693Sstephh 				break;
61044743693Sstephh 			}
61144743693Sstephh 			lp2 = lp2->next;
61244743693Sstephh 			if (lp2 == lxp2)
61344743693Sstephh 				break;
61444743693Sstephh 		}
61544743693Sstephh 		lp1 = lp1->next;
61644743693Sstephh 		if (lp1 == lxp1)
61744743693Sstephh 			break;
61844743693Sstephh 	}
61944743693Sstephh 	if (l1 == l2 && l2 == common)
62044743693Sstephh 		return (0);
62144743693Sstephh 	else
62244743693Sstephh 		return (1);
62344743693Sstephh }
62444743693Sstephh 
62544743693Sstephh static name_list_t *
62644743693Sstephh alloc_name_list(char *name, uint8_t pct)
62744743693Sstephh {
62844743693Sstephh 	name_list_t *nlp;
62944743693Sstephh 
63044743693Sstephh 	nlp = malloc(sizeof (*nlp));
63144743693Sstephh 	nlp->name = strdup(name);
63244743693Sstephh 	nlp->pct = pct;
63344743693Sstephh 	nlp->max_pct = pct;
63444743693Sstephh 	nlp->count = 1;
63544743693Sstephh 	nlp->next = nlp;
63644743693Sstephh 	nlp->prev = nlp;
63744743693Sstephh 	nlp->status = 0;
638d4c0a8c5Sstephh 	nlp->label = NULL;
63944743693Sstephh 	return (nlp);
64044743693Sstephh }
64144743693Sstephh 
64244743693Sstephh static void
64344743693Sstephh free_name_list(name_list_t *list)
64444743693Sstephh {
64544743693Sstephh 	name_list_t *next = list;
64644743693Sstephh 	name_list_t *lp;
64744743693Sstephh 
64844743693Sstephh 	if (list) {
64944743693Sstephh 		do {
65044743693Sstephh 			lp = next;
65144743693Sstephh 			next = lp->next;
652d4c0a8c5Sstephh 			if (lp->label)
653d4c0a8c5Sstephh 				free(lp->label);
65444743693Sstephh 			free(lp->name);
65544743693Sstephh 			free(lp);
65644743693Sstephh 		} while (next != list);
65744743693Sstephh 	}
65844743693Sstephh }
65944743693Sstephh 
66044743693Sstephh static status_record_t *
66144743693Sstephh new_record_init(uurec_t *uurec_p, char *msgid, name_list_t *class,
66244743693Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
663*b6955755SRobert Johnston     name_list_t *serial, boolean_t not_suppressed,
66444743693Sstephh     hostid_t *hostid)
66544743693Sstephh {
66644743693Sstephh 	status_record_t *status_rec_p;
66744743693Sstephh 
66844743693Sstephh 	status_rec_p = (status_record_t *)malloc(sizeof (status_record_t));
66944743693Sstephh 	status_rec_p->nrecs = 1;
67044743693Sstephh 	status_rec_p->host = hostid;
67144743693Sstephh 	status_rec_p->uurec = uurec_p;
67244743693Sstephh 	uurec_p->next = NULL;
67344743693Sstephh 	uurec_p->prev = NULL;
67444743693Sstephh 	uurec_p->asru = asru;
675*b6955755SRobert Johnston 	if ((status_rec_p->severity = fmd_msg_getitem_id(fmadm_msghdl, NULL,
676*b6955755SRobert Johnston 	    msgid, FMD_MSG_ITEM_SEVERITY)) == NULL)
677*b6955755SRobert Johnston 		status_rec_p->severity = strdup("unknown");
67844743693Sstephh 	status_rec_p->class = class;
67944743693Sstephh 	status_rec_p->fru = fru;
68044743693Sstephh 	status_rec_p->asru = asru;
68144743693Sstephh 	status_rec_p->resource = resource;
68244743693Sstephh 	status_rec_p->serial = serial;
68344743693Sstephh 	status_rec_p->msgid = strdup(msgid);
68444743693Sstephh 	status_rec_p->not_suppressed = not_suppressed;
68544743693Sstephh 	return (status_rec_p);
68644743693Sstephh }
68744743693Sstephh 
68844743693Sstephh /*
68944743693Sstephh  * add record to given list maintaining order higher priority first.
69044743693Sstephh  */
69144743693Sstephh static void
69244743693Sstephh add_rec_list(status_record_t *status_rec_p, sr_list_t **list_pp)
69344743693Sstephh {
69444743693Sstephh 	sr_list_t *tp, *np, *sp;
69544743693Sstephh 	int order;
69644743693Sstephh 	uint64_t sec;
6977c478bd9Sstevel@tonic-gate 
69844743693Sstephh 	np = malloc(sizeof (sr_list_t));
69944743693Sstephh 	np->status_record = status_rec_p;
70044743693Sstephh 	sec = status_rec_p->uurec->sec;
70144743693Sstephh 	if ((sp = *list_pp) == NULL) {
70244743693Sstephh 		*list_pp = np;
70344743693Sstephh 		np->next = np;
70444743693Sstephh 		np->prev = np;
70544743693Sstephh 	} else {
70644743693Sstephh 		/* insert new record in front of lower priority */
70744743693Sstephh 		tp = sp;
70844743693Sstephh 		order = cmp_priority(status_rec_p->severity,
70944743693Sstephh 		    sp->status_record->severity, sec,
71044743693Sstephh 		    tp->status_record->uurec->sec, 0, 0);
71144743693Sstephh 		if (order > 0) {
71244743693Sstephh 			*list_pp = np;
71344743693Sstephh 		} else {
71444743693Sstephh 			tp = sp->next;
71544743693Sstephh 			while (tp != sp &&
71644743693Sstephh 			    cmp_priority(status_rec_p->severity,
71744743693Sstephh 			    tp->status_record->severity, sec,
71844743693Sstephh 			    tp->status_record->uurec->sec, 0, 0)) {
71944743693Sstephh 				tp = tp->next;
72044743693Sstephh 			}
72144743693Sstephh 		}
72244743693Sstephh 		np->next = tp;
72344743693Sstephh 		np->prev = tp->prev;
72444743693Sstephh 		tp->prev->next = np;
72544743693Sstephh 		tp->prev = np;
72644743693Sstephh 	}
72744743693Sstephh }
72844743693Sstephh 
72944743693Sstephh static void
73044743693Sstephh add_resource(status_record_t *status_rec_p, resource_list_t **rp,
73144743693Sstephh     resource_list_t *np)
73244743693Sstephh {
73344743693Sstephh 	int order;
73444743693Sstephh 	uint64_t sec;
73544743693Sstephh 	resource_list_t *sp, *tp;
73644743693Sstephh 	status_record_t *srp;
73744743693Sstephh 	char *severity = status_rec_p->severity;
73844743693Sstephh 
73944743693Sstephh 	add_rec_list(status_rec_p, &np->status_rec_list);
74044743693Sstephh 	if ((sp = *rp) == NULL) {
74144743693Sstephh 		np->next = np;
74244743693Sstephh 		np->prev = np;
74344743693Sstephh 		*rp = np;
74444743693Sstephh 	} else {
74544743693Sstephh 		/*
74644743693Sstephh 		 * insert new record in front of lower priority
74744743693Sstephh 		 */
74844743693Sstephh 		tp = sp->next;
74944743693Sstephh 		srp = sp->status_rec_list->status_record;
75044743693Sstephh 		sec = status_rec_p->uurec->sec;
75144743693Sstephh 		order = cmp_priority(severity, srp->severity, sec,
75244743693Sstephh 		    srp->uurec->sec, np->max_pct, sp->max_pct);
75344743693Sstephh 		if (order > 0) {
75444743693Sstephh 			*rp = np;
75544743693Sstephh 		} else {
75644743693Sstephh 			srp = tp->status_rec_list->status_record;
75744743693Sstephh 			while (tp != sp &&
75844743693Sstephh 			    cmp_priority(severity, srp->severity, sec,
75944743693Sstephh 			    srp->uurec->sec, np->max_pct, sp->max_pct) < 0) {
76044743693Sstephh 				tp = tp->next;
76144743693Sstephh 				srp = tp->status_rec_list->status_record;
76244743693Sstephh 			}
76344743693Sstephh 		}
76444743693Sstephh 		np->next = tp;
76544743693Sstephh 		np->prev = tp->prev;
76644743693Sstephh 		tp->prev->next = np;
76744743693Sstephh 		tp->prev = np;
76844743693Sstephh 	}
76944743693Sstephh }
77044743693Sstephh 
77144743693Sstephh static void
77244743693Sstephh add_resource_list(status_record_t *status_rec_p, name_list_t *fp,
77344743693Sstephh     resource_list_t **rpp)
77444743693Sstephh {
77544743693Sstephh 	int order;
77644743693Sstephh 	resource_list_t *np, *end;
77744743693Sstephh 	status_record_t *srp;
77844743693Sstephh 
77944743693Sstephh 	np = *rpp;
78044743693Sstephh 	end = np;
78144743693Sstephh 	while (np) {
78244743693Sstephh 		if (strcmp(fp->name, np->resource) == 0) {
78344743693Sstephh 			np->not_suppressed |= status_rec_p->not_suppressed;
78444743693Sstephh 			srp = np->status_rec_list->status_record;
78544743693Sstephh 			order = cmp_priority(status_rec_p->severity,
78644743693Sstephh 			    srp->severity, status_rec_p->uurec->sec,
78744743693Sstephh 			    srp->uurec->sec, fp->max_pct, np->max_pct);
78844743693Sstephh 			if (order > 0 && np != end) {
78944743693Sstephh 				/*
79044743693Sstephh 				 * remove from list and add again using
79144743693Sstephh 				 * new priority
79244743693Sstephh 				 */
79344743693Sstephh 				np->prev->next = np->next;
79444743693Sstephh 				np->next->prev = np->prev;
79544743693Sstephh 				add_resource(status_rec_p,
79644743693Sstephh 				    rpp, np);
79744743693Sstephh 			} else {
79844743693Sstephh 				add_rec_list(status_rec_p,
79944743693Sstephh 				    &np->status_rec_list);
80044743693Sstephh 			}
80144743693Sstephh 			break;
80244743693Sstephh 		}
80344743693Sstephh 		np = np->next;
80444743693Sstephh 		if (np == end) {
80544743693Sstephh 			np = NULL;
80644743693Sstephh 			break;
80744743693Sstephh 		}
80844743693Sstephh 	}
80944743693Sstephh 	if (np == NULL) {
81044743693Sstephh 		np = malloc(sizeof (resource_list_t));
81144743693Sstephh 		np->resource = fp->name;
81244743693Sstephh 		np->not_suppressed = status_rec_p->not_suppressed;
81344743693Sstephh 		np->status_rec_list = NULL;
81444743693Sstephh 		np->max_pct = fp->max_pct;
81544743693Sstephh 		add_resource(status_rec_p, rpp, np);
81644743693Sstephh 	}
81744743693Sstephh }
81844743693Sstephh 
81944743693Sstephh static void
82044743693Sstephh add_list(status_record_t *status_rec_p, name_list_t *listp,
82144743693Sstephh     resource_list_t **glistp)
8227c478bd9Sstevel@tonic-gate {
82344743693Sstephh 	name_list_t *fp, *end;
82444743693Sstephh 
82544743693Sstephh 	fp = listp;
82644743693Sstephh 	end = fp;
82744743693Sstephh 	while (fp) {
82844743693Sstephh 		add_resource_list(status_rec_p, fp, glistp);
82944743693Sstephh 		fp = fp->next;
83044743693Sstephh 		if (fp == end)
83144743693Sstephh 			break;
83244743693Sstephh 	}
83344743693Sstephh }
83444743693Sstephh 
83544743693Sstephh /*
83644743693Sstephh  * add record to rec, fru and asru lists.
83744743693Sstephh  */
83844743693Sstephh static void
83944743693Sstephh catalog_new_record(uurec_t *uurec_p, char *msgid, name_list_t *class,
84044743693Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
841*b6955755SRobert Johnston     name_list_t *serial, boolean_t not_suppressed,
84244743693Sstephh     hostid_t *hostid)
84344743693Sstephh {
84444743693Sstephh 	status_record_t *status_rec_p;
84544743693Sstephh 
84644743693Sstephh 	status_rec_p = new_record_init(uurec_p, msgid, class, fru, asru,
847*b6955755SRobert Johnston 	    resource, serial, not_suppressed, hostid);
84844743693Sstephh 	add_rec_list(status_rec_p, &status_rec_list);
84944743693Sstephh 	if (status_rec_p->fru)
85044743693Sstephh 		add_list(status_rec_p, status_rec_p->fru, &status_fru_list);
85144743693Sstephh 	if (status_rec_p->asru)
85244743693Sstephh 		add_list(status_rec_p, status_rec_p->asru, &status_asru_list);
85344743693Sstephh }
85444743693Sstephh 
85544743693Sstephh /*
85644743693Sstephh  * add uuid and diagnoses time to an existing record for similar fault on the
85744743693Sstephh  * same fru
85844743693Sstephh  */
85944743693Sstephh static void
86044743693Sstephh catalog_merge_record(status_record_t *status_rec_p, uurec_t *uurec_p,
86144743693Sstephh     name_list_t *asru, name_list_t *resource, name_list_t *serial,
862*b6955755SRobert Johnston     boolean_t not_suppressed)
86344743693Sstephh {
86444743693Sstephh 	uurec_t *uurec1_p;
86544743693Sstephh 
86644743693Sstephh 	status_rec_p->nrecs++;
86744743693Sstephh 	/* add uurec in time order */
86844743693Sstephh 	if (status_rec_p->uurec->sec > uurec_p->sec) {
86944743693Sstephh 		uurec_p->next = status_rec_p->uurec;
87044743693Sstephh 		uurec_p->prev = NULL;
87144743693Sstephh 		status_rec_p->uurec = uurec_p;
87244743693Sstephh 	} else {
87344743693Sstephh 		uurec1_p = status_rec_p->uurec;
87444743693Sstephh 		while (uurec1_p->next && uurec1_p->next->sec <= uurec_p->sec)
87544743693Sstephh 			uurec1_p = uurec1_p->next;
87644743693Sstephh 		if (uurec1_p->next)
87744743693Sstephh 			uurec1_p->next->prev = uurec_p;
87844743693Sstephh 		uurec_p->next = uurec1_p->next;
87944743693Sstephh 		uurec_p->prev = uurec1_p;
88044743693Sstephh 		uurec1_p->next = uurec_p;
88144743693Sstephh 	}
88244743693Sstephh 	status_rec_p->not_suppressed |= not_suppressed;
88344743693Sstephh 	uurec_p->asru = merge_name_list(&status_rec_p->asru, asru, 0);
88444743693Sstephh 	(void) merge_name_list(&status_rec_p->resource, resource, 0);
88544743693Sstephh 	(void) merge_name_list(&status_rec_p->serial, serial, 0);
88644743693Sstephh }
88744743693Sstephh 
88844743693Sstephh static status_record_t *
88944743693Sstephh record_in_catalog(name_list_t *class, name_list_t *fru,
89044743693Sstephh     char *msgid, hostid_t *host)
89144743693Sstephh {
89244743693Sstephh 	sr_list_t *status_rec_p;
89344743693Sstephh 	status_record_t *srp = NULL;
89444743693Sstephh 
89544743693Sstephh 	status_rec_p = status_rec_list;
89644743693Sstephh 	while (status_rec_p) {
89744743693Sstephh 		srp = status_rec_p->status_record;
89844743693Sstephh 		if (host == srp->host &&
89944743693Sstephh 		    cmp_name_list(class, srp->class) == 0 &&
90044743693Sstephh 		    cmp_name_list(fru, srp->fru) == 0 &&
90144743693Sstephh 		    strcmp(msgid, srp->msgid) == 0)
90244743693Sstephh 			break;
90344743693Sstephh 		if (status_rec_p->next == status_rec_list) {
90444743693Sstephh 			srp = NULL;
90544743693Sstephh 			break;
90644743693Sstephh 		} else {
90744743693Sstephh 			status_rec_p = status_rec_p->next;
90844743693Sstephh 		}
90944743693Sstephh 	}
91044743693Sstephh 	return (srp);
91144743693Sstephh }
91244743693Sstephh 
91344743693Sstephh static void
91444743693Sstephh get_serial_no(nvlist_t *nvl, name_list_t **serial_p, uint8_t pct)
91544743693Sstephh {
91644743693Sstephh 	char *name;
91744743693Sstephh 	char *serial = NULL;
91844743693Sstephh 	char **lserial = NULL;
91944743693Sstephh 	uint64_t serint;
92044743693Sstephh 	name_list_t *nlp;
92144743693Sstephh 	int j;
92244743693Sstephh 	uint_t nelem;
92344743693Sstephh 	char buf[64];
92444743693Sstephh 
92544743693Sstephh 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) == 0) {
92644743693Sstephh 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
92744743693Sstephh 			if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
92844743693Sstephh 			    &serint) == 0) {
92944743693Sstephh 				(void) snprintf(buf, sizeof (buf), "%llX",
93044743693Sstephh 				    serint);
93144743693Sstephh 				nlp = alloc_name_list(buf, pct);
93244743693Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
93344743693Sstephh 			}
93444743693Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
93544743693Sstephh 			if (nvlist_lookup_string_array(nvl,
93644743693Sstephh 			    FM_FMRI_MEM_SERIAL_ID, &lserial, &nelem) == 0) {
93744743693Sstephh 				nlp = alloc_name_list(lserial[0], pct);
93844743693Sstephh 				for (j = 1; j < nelem; j++) {
93944743693Sstephh 					name_list_t *n1lp;
94044743693Sstephh 					n1lp = alloc_name_list(lserial[j], pct);
94144743693Sstephh 					(void) merge_name_list(&nlp, n1lp, 1);
94244743693Sstephh 				}
94344743693Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
94444743693Sstephh 			}
94544743693Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_HC) == 0) {
94644743693Sstephh 			if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID,
94744743693Sstephh 			    &serial) == 0) {
94844743693Sstephh 				nlp = alloc_name_list(serial, pct);
94944743693Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
95044743693Sstephh 			}
95144743693Sstephh 		}
95244743693Sstephh 	}
95344743693Sstephh }
95444743693Sstephh 
95544743693Sstephh static void
95644743693Sstephh extract_record_info(nvlist_t *nvl, name_list_t **class_p,
95744743693Sstephh     name_list_t **fru_p, name_list_t **serial_p,
95844743693Sstephh     name_list_t **resource_p, name_list_t **asru_p, uint8_t status)
95944743693Sstephh {
96044743693Sstephh 	nvlist_t *lfru, *lasru, *rsrc;
96144743693Sstephh 	name_list_t *nlp;
96244743693Sstephh 	char *name;
96344743693Sstephh 	uint8_t lpct = 0;
96444743693Sstephh 	char *lclass = NULL;
965d4c0a8c5Sstephh 	char *label;
96644743693Sstephh 
96744743693Sstephh 	(void) nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &lpct);
96844743693Sstephh 	if (nvlist_lookup_string(nvl, FM_CLASS, &lclass) == 0) {
96944743693Sstephh 		nlp = alloc_name_list(lclass, lpct);
97044743693Sstephh 		(void) merge_name_list(class_p, nlp, 1);
97144743693Sstephh 	}
97244743693Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &lfru) == 0) {
97344743693Sstephh 		name = get_nvl2str_topo(lfru);
97444743693Sstephh 		if (name != NULL) {
97544743693Sstephh 			nlp = alloc_name_list(name, lpct);
97625c6ff4bSstephh 			nlp->status = status & ~(FM_SUSPECT_UNUSABLE |
97725c6ff4bSstephh 			    FM_SUSPECT_DEGRADED);
97844743693Sstephh 			free(name);
979d4c0a8c5Sstephh 			if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION,
980d4c0a8c5Sstephh 			    &label) == 0)
981d4c0a8c5Sstephh 				nlp->label = strdup(label);
98244743693Sstephh 			(void) merge_name_list(fru_p, nlp, 1);
98344743693Sstephh 		}
98444743693Sstephh 		get_serial_no(lfru, serial_p, lpct);
98544743693Sstephh 	}
98644743693Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &lasru) == 0) {
98744743693Sstephh 		name = get_nvl2str_topo(lasru);
98844743693Sstephh 		if (name != NULL) {
98944743693Sstephh 			nlp = alloc_name_list(name, lpct);
99025c6ff4bSstephh 			nlp->status = status & ~(FM_SUSPECT_NOT_PRESENT |
99125c6ff4bSstephh 			    FM_SUSPECT_REPAIRED | FM_SUSPECT_REPLACED |
99225c6ff4bSstephh 			    FM_SUSPECT_ACQUITTED);
99344743693Sstephh 			free(name);
99444743693Sstephh 			(void) merge_name_list(asru_p, nlp, 1);
99544743693Sstephh 		}
99644743693Sstephh 		get_serial_no(lasru, serial_p, lpct);
99744743693Sstephh 	}
99844743693Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
99944743693Sstephh 		name = get_nvl2str_topo(rsrc);
100044743693Sstephh 		if (name != NULL) {
100144743693Sstephh 			nlp = alloc_name_list(name, lpct);
1002567cc2e6Sstephh 			nlp->status = status;
100344743693Sstephh 			free(name);
10048e7248e5SStephen Hanson 			if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION,
10058e7248e5SStephen Hanson 			    &label) == 0)
10068e7248e5SStephen Hanson 				nlp->label = strdup(label);
100744743693Sstephh 			(void) merge_name_list(resource_p, nlp, 1);
100844743693Sstephh 		}
100944743693Sstephh 	}
101044743693Sstephh }
101144743693Sstephh 
101244743693Sstephh static void
1013*b6955755SRobert Johnston add_fault_record_to_catalog(nvlist_t *nvl, uint64_t sec, char *uuid)
101444743693Sstephh {
101544743693Sstephh 	char *msgid = "-";
101644743693Sstephh 	uint_t i, size = 0;
101744743693Sstephh 	name_list_t *class = NULL, *resource = NULL;
101844743693Sstephh 	name_list_t *asru = NULL, *fru = NULL, *serial = NULL;
101944743693Sstephh 	nvlist_t **nva;
102044743693Sstephh 	uint8_t *ba;
102144743693Sstephh 	status_record_t *status_rec_p;
102244743693Sstephh 	uurec_t *uurec_p;
102344743693Sstephh 	hostid_t *host;
102444743693Sstephh 	boolean_t not_suppressed = 1;
102544743693Sstephh 	boolean_t any_present = 0;
102644743693Sstephh 
102744743693Sstephh 	(void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &msgid);
102844743693Sstephh 	(void) nvlist_lookup_uint32(nvl, FM_SUSPECT_FAULT_SZ, &size);
102944743693Sstephh 	(void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_MESSAGE,
103044743693Sstephh 	    &not_suppressed);
103144743693Sstephh 
103244743693Sstephh 	if (size != 0) {
103344743693Sstephh 		(void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
103444743693Sstephh 		    &nva, &size);
103544743693Sstephh 		(void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS,
103644743693Sstephh 		    &ba, &size);
103744743693Sstephh 		for (i = 0; i < size; i++) {
103844743693Sstephh 			extract_record_info(nva[i], &class, &fru, &serial,
103944743693Sstephh 			    &resource, &asru, ba[i]);
104044743693Sstephh 			if (!(ba[i] & FM_SUSPECT_NOT_PRESENT) &&
104144743693Sstephh 			    (ba[i] & FM_SUSPECT_FAULTY))
104244743693Sstephh 				any_present = 1;
104344743693Sstephh 		}
104444743693Sstephh 		/*
104544743693Sstephh 		 * also suppress if no resources present
104644743693Sstephh 		 */
104744743693Sstephh 		if (any_present == 0)
104844743693Sstephh 			not_suppressed = 0;
104944743693Sstephh 	}
105044743693Sstephh 
105144743693Sstephh 	uurec_p = (uurec_t *)malloc(sizeof (uurec_t));
105244743693Sstephh 	uurec_p->uuid = strdup(uuid);
105344743693Sstephh 	uurec_p->sec = sec;
105444743693Sstephh 	uurec_p->ari_uuid_list = NULL;
105544743693Sstephh 	host = find_hostid(nvl);
105644743693Sstephh 	if (not_suppressed && !opt_g)
105744743693Sstephh 		status_rec_p = NULL;
105844743693Sstephh 	else
105944743693Sstephh 		status_rec_p = record_in_catalog(class, fru, msgid, host);
106044743693Sstephh 	if (status_rec_p) {
106144743693Sstephh 		catalog_merge_record(status_rec_p, uurec_p, asru, resource,
1062*b6955755SRobert Johnston 		    serial, not_suppressed);
106344743693Sstephh 		free_name_list(class);
106444743693Sstephh 		free_name_list(fru);
106544743693Sstephh 	} else {
106644743693Sstephh 		catalog_new_record(uurec_p, msgid, class, fru, asru,
1067*b6955755SRobert Johnston 		    resource, serial, not_suppressed, host);
106844743693Sstephh 	}
106944743693Sstephh }
107044743693Sstephh 
107144743693Sstephh static void
107244743693Sstephh update_asru_state_in_catalog(const char *uuid, const char *ari_uuid)
107344743693Sstephh {
107444743693Sstephh 	sr_list_t *srp;
107544743693Sstephh 	uurec_t *uurp;
107644743693Sstephh 	ari_list_t *ari_list;
107744743693Sstephh 
107844743693Sstephh 	srp = status_rec_list;
107944743693Sstephh 	if (srp) {
108044743693Sstephh 		for (;;) {
108144743693Sstephh 			uurp = srp->status_record->uurec;
108244743693Sstephh 			while (uurp) {
108344743693Sstephh 				if (strcmp(uuid, uurp->uuid) == 0) {
108444743693Sstephh 					ari_list = (ari_list_t *)
108544743693Sstephh 					    malloc(sizeof (ari_list_t));
108644743693Sstephh 					ari_list->ari_uuid = strdup(ari_uuid);
108744743693Sstephh 					ari_list->next = uurp->ari_uuid_list;
108844743693Sstephh 					uurp->ari_uuid_list = ari_list;
108944743693Sstephh 					return;
109044743693Sstephh 				}
109144743693Sstephh 				uurp = uurp->next;
109244743693Sstephh 			}
109344743693Sstephh 			if (srp->next == status_rec_list)
109444743693Sstephh 				break;
109544743693Sstephh 			srp = srp->next;
109644743693Sstephh 		}
109744743693Sstephh 	}
109844743693Sstephh }
109944743693Sstephh 
110044743693Sstephh static void
110144743693Sstephh print_line(char *label, char *buf)
110244743693Sstephh {
110344743693Sstephh 	char *cp, *ep, *wp;
110444743693Sstephh 	char c;
110544743693Sstephh 	int i;
110644743693Sstephh 	int lsz;
110744743693Sstephh 	char *padding;
110844743693Sstephh 
110944743693Sstephh 	lsz = strlen(label);
111044743693Sstephh 	padding = malloc(lsz + 1);
111144743693Sstephh 	for (i = 0; i < lsz; i++)
111244743693Sstephh 		padding[i] = ' ';
111344743693Sstephh 	padding[i] = 0;
111444743693Sstephh 	cp = buf;
111544743693Sstephh 	ep = buf;
111644743693Sstephh 	c = *ep;
111744743693Sstephh 	(void) printf("\n");
111844743693Sstephh 	while (c) {
111944743693Sstephh 		i = lsz;
112044743693Sstephh 		wp = NULL;
112144743693Sstephh 		while ((c = *ep) != NULL && (wp == NULL || i < 80)) {
112244743693Sstephh 			if (c == ' ')
112344743693Sstephh 				wp = ep;
112444743693Sstephh 			else if (c == '\n') {
112544743693Sstephh 				i = 0;
112644743693Sstephh 				*ep = 0;
112744743693Sstephh 				do {
112844743693Sstephh 					ep++;
112944743693Sstephh 				} while ((c = *ep) != NULL && c == ' ');
113044743693Sstephh 				break;
113144743693Sstephh 			}
113244743693Sstephh 			ep++;
113344743693Sstephh 			i++;
113444743693Sstephh 		}
113544743693Sstephh 		if (i >= 80 && wp) {
113644743693Sstephh 			*wp = 0;
113744743693Sstephh 			ep = wp + 1;
113844743693Sstephh 			c = *ep;
113944743693Sstephh 		}
114044743693Sstephh 		(void) printf("%s%s\n", label, cp);
114144743693Sstephh 		cp = ep;
114244743693Sstephh 		label = padding;
114344743693Sstephh 	}
114444743693Sstephh 	free(padding);
114544743693Sstephh }
114644743693Sstephh 
114744743693Sstephh static void
1148*b6955755SRobert Johnston print_dict_info_line(char *msgid, fmd_msg_item_t what, const char *linehdr)
114944743693Sstephh {
1150*b6955755SRobert Johnston 	char *cp = fmd_msg_getitem_id(fmadm_msghdl, NULL, msgid, what);
115144743693Sstephh 
115244743693Sstephh 	if (cp) {
1153*b6955755SRobert Johnston 		print_line(dgettext("FMD", linehdr), cp);
1154*b6955755SRobert Johnston 		free(cp);
115544743693Sstephh 	}
115644743693Sstephh }
115744743693Sstephh 
1158*b6955755SRobert Johnston static void
1159*b6955755SRobert Johnston print_dict_info(char *msgid)
1160*b6955755SRobert Johnston {
1161*b6955755SRobert Johnston 	print_dict_info_line(msgid, FMD_MSG_ITEM_DESC, "Description : ");
1162*b6955755SRobert Johnston 	print_dict_info_line(msgid, FMD_MSG_ITEM_RESPONSE, "Response    : ");
1163*b6955755SRobert Johnston 	print_dict_info_line(msgid, FMD_MSG_ITEM_IMPACT, "Impact      : ");
1164*b6955755SRobert Johnston 	print_dict_info_line(msgid, FMD_MSG_ITEM_ACTION, "Action      : ");
1165*b6955755SRobert Johnston }
1166*b6955755SRobert Johnston 
116744743693Sstephh static void
116844743693Sstephh print_name(name_list_t *list, char *(func)(char *), char *padding, int *np,
116944743693Sstephh     int pct, int full)
117044743693Sstephh {
11718e7248e5SStephen Hanson 	char *name, *fru_label = NULL;
117244743693Sstephh 
117344743693Sstephh 	name = list->name;
11748e7248e5SStephen Hanson 	if (list->label) {
11758e7248e5SStephen Hanson 		(void) printf("%s \"%s\" (%s)", padding, list->label, name);
11768e7248e5SStephen Hanson 		*np += 1;
11778e7248e5SStephen Hanson 	} else if (func && (fru_label = func(list->name)) != NULL) {
11788e7248e5SStephen Hanson 		(void) printf("%s \"%s\" (%s)", padding, fru_label, name);
117944743693Sstephh 		*np += 1;
11808e7248e5SStephen Hanson 		free(fru_label);
118144743693Sstephh 	} else {
118244743693Sstephh 		(void) printf("%s %s", padding, name);
118344743693Sstephh 		*np += 1;
118444743693Sstephh 	}
118544743693Sstephh 	if (list->pct && pct > 0 && pct < 100) {
118644743693Sstephh 		if (list->count > 1) {
118744743693Sstephh 			if (full) {
118844743693Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
118944743693Sstephh 				    dgettext("FMD", "max"),
119044743693Sstephh 				    list->max_pct);
119144743693Sstephh 			} else {
119244743693Sstephh 				(void) printf(" %s %d%%\n",
119344743693Sstephh 				    dgettext("FMD", "max"),
119444743693Sstephh 				    list->max_pct);
119544743693Sstephh 			}
119644743693Sstephh 		} else {
119744743693Sstephh 			(void) printf(" %d%%\n", list->pct);
119844743693Sstephh 		}
119944743693Sstephh 	} else {
120044743693Sstephh 		(void) printf("\n");
120144743693Sstephh 	}
120244743693Sstephh }
120344743693Sstephh 
120444743693Sstephh static void
120544743693Sstephh print_asru_status(int status, char *label)
120644743693Sstephh {
120744743693Sstephh 	char *msg = NULL;
120844743693Sstephh 
120944743693Sstephh 	switch (status) {
121044743693Sstephh 	case 0:
121144743693Sstephh 		msg = dgettext("FMD", "ok and in service");
121244743693Sstephh 		break;
121325c6ff4bSstephh 	case FM_SUSPECT_DEGRADED:
121425c6ff4bSstephh 		msg = dgettext("FMD", "service degraded, "
121525c6ff4bSstephh 		    "but associated components no longer faulty");
121625c6ff4bSstephh 		break;
121725c6ff4bSstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED:
121825c6ff4bSstephh 		msg = dgettext("FMD", "faulted but still "
121925c6ff4bSstephh 		    "providing degraded service");
122025c6ff4bSstephh 		break;
122144743693Sstephh 	case FM_SUSPECT_FAULTY:
122225c6ff4bSstephh 		msg = dgettext("FMD", "faulted but still in service");
122344743693Sstephh 		break;
122444743693Sstephh 	case FM_SUSPECT_UNUSABLE:
122525c6ff4bSstephh 		msg = dgettext("FMD", "out of service, "
122625c6ff4bSstephh 		    "but associated components no longer faulty");
122744743693Sstephh 		break;
122844743693Sstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
122944743693Sstephh 		msg = dgettext("FMD", "faulted and taken out of service");
123044743693Sstephh 		break;
12317c478bd9Sstevel@tonic-gate 	default:
123244743693Sstephh 		break;
123344743693Sstephh 	}
123444743693Sstephh 	if (msg) {
123544743693Sstephh 		(void) printf("%s     %s\n", label, msg);
12367c478bd9Sstevel@tonic-gate 	}
12377c478bd9Sstevel@tonic-gate }
12387c478bd9Sstevel@tonic-gate 
1239567cc2e6Sstephh static void
1240567cc2e6Sstephh print_fru_status(int status, char *label)
1241567cc2e6Sstephh {
1242567cc2e6Sstephh 	char *msg = NULL;
1243567cc2e6Sstephh 
1244567cc2e6Sstephh 	if (status & FM_SUSPECT_NOT_PRESENT)
1245567cc2e6Sstephh 		msg = dgettext("FMD", "not present");
1246567cc2e6Sstephh 	else if (status & FM_SUSPECT_FAULTY)
1247567cc2e6Sstephh 		msg = dgettext("FMD", "faulty");
124825c6ff4bSstephh 	else if (status & FM_SUSPECT_REPLACED)
124925c6ff4bSstephh 		msg = dgettext("FMD", "replaced");
125025c6ff4bSstephh 	else if (status & FM_SUSPECT_REPAIRED)
125125c6ff4bSstephh 		msg = dgettext("FMD", "repair attempted");
125225c6ff4bSstephh 	else if (status & FM_SUSPECT_ACQUITTED)
125325c6ff4bSstephh 		msg = dgettext("FMD", "acquitted");
1254567cc2e6Sstephh 	else
125525c6ff4bSstephh 		msg = dgettext("FMD", "removed");
1256567cc2e6Sstephh 	(void) printf("%s     %s\n", label, msg);
1257567cc2e6Sstephh }
1258567cc2e6Sstephh 
1259cbf75e67SStephen Hanson static void
1260cbf75e67SStephen Hanson print_rsrc_status(int status, char *label)
1261cbf75e67SStephen Hanson {
1262cbf75e67SStephen Hanson 	char *msg = "";
1263cbf75e67SStephen Hanson 
1264cbf75e67SStephen Hanson 	if (status & FM_SUSPECT_NOT_PRESENT)
1265cbf75e67SStephen Hanson 		msg = dgettext("FMD", "not present");
1266cbf75e67SStephen Hanson 	else if (status & FM_SUSPECT_FAULTY) {
1267cbf75e67SStephen Hanson 		if (status & FM_SUSPECT_DEGRADED)
1268cbf75e67SStephen Hanson 			msg = dgettext("FMD",
1269cbf75e67SStephen Hanson 			    "faulted but still providing degraded service");
1270cbf75e67SStephen Hanson 		else if (status & FM_SUSPECT_UNUSABLE)
1271cbf75e67SStephen Hanson 			msg = dgettext("FMD",
1272cbf75e67SStephen Hanson 			    "faulted and taken out of service");
1273cbf75e67SStephen Hanson 		else
1274cbf75e67SStephen Hanson 			msg = dgettext("FMD", "faulted but still in service");
1275cbf75e67SStephen Hanson 	} else if (status & FM_SUSPECT_REPLACED)
1276cbf75e67SStephen Hanson 		msg = dgettext("FMD", "replaced");
1277cbf75e67SStephen Hanson 	else if (status & FM_SUSPECT_REPAIRED)
1278cbf75e67SStephen Hanson 		msg = dgettext("FMD", "repair attempted");
1279cbf75e67SStephen Hanson 	else if (status & FM_SUSPECT_ACQUITTED)
1280cbf75e67SStephen Hanson 		msg = dgettext("FMD", "acquitted");
1281cbf75e67SStephen Hanson 	else
1282cbf75e67SStephen Hanson 		msg = dgettext("FMD", "removed");
1283cbf75e67SStephen Hanson 	(void) printf("%s     %s\n", label, msg);
1284cbf75e67SStephen Hanson }
1285cbf75e67SStephen Hanson 
128644743693Sstephh static void
128744743693Sstephh print_name_list(name_list_t *list, char *label, char *(func)(char *),
128844743693Sstephh     int limit, int pct, void (func1)(int, char *), int full)
128944743693Sstephh {
12908e7248e5SStephen Hanson 	char *name, *fru_label = NULL;
129144743693Sstephh 	char *padding;
129244743693Sstephh 	int i, j, l, n;
129344743693Sstephh 	name_list_t *end = list;
12947c478bd9Sstevel@tonic-gate 
129544743693Sstephh 	l = strlen(label);
129644743693Sstephh 	padding = malloc(l + 1);
129744743693Sstephh 	for (i = 0; i < l; i++)
129844743693Sstephh 		padding[i] = ' ';
129944743693Sstephh 	padding[l] = 0;
130044743693Sstephh 	(void) printf("%s", label);
130144743693Sstephh 	name = list->name;
13028e7248e5SStephen Hanson 	if (list->label)
1303d4c0a8c5Sstephh 		(void) printf(" \"%s\" (%s)", list->label, name);
13048e7248e5SStephen Hanson 	else if (func && (fru_label = func(list->name)) != NULL) {
13058e7248e5SStephen Hanson 		(void) printf(" \"%s\" (%s)", fru_label, name);
13068e7248e5SStephen Hanson 		free(fru_label);
13078e7248e5SStephen Hanson 	} else
13088e7248e5SStephen Hanson 		(void) printf(" %s", name);
130944743693Sstephh 	if (list->pct && pct > 0 && pct < 100) {
131044743693Sstephh 		if (list->count > 1) {
131144743693Sstephh 			if (full) {
131244743693Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
131344743693Sstephh 				    dgettext("FMD", "max"), list->max_pct);
131444743693Sstephh 			} else {
131544743693Sstephh 				(void) printf(" %s %d%%\n",
131644743693Sstephh 				    dgettext("FMD", "max"), list->max_pct);
131744743693Sstephh 			}
131844743693Sstephh 		} else {
131944743693Sstephh 			(void) printf(" %d%%\n", list->pct);
132044743693Sstephh 		}
132144743693Sstephh 	} else {
132244743693Sstephh 		(void) printf("\n");
132344743693Sstephh 	}
132444743693Sstephh 	if (func1)
132544743693Sstephh 		func1(list->status, padding);
132644743693Sstephh 	n = 1;
132744743693Sstephh 	j = 0;
132844743693Sstephh 	while ((list = list->next) != end) {
132944743693Sstephh 		if (limit == 0 || n < limit) {
133044743693Sstephh 			print_name(list, func, padding, &n, pct, full);
133144743693Sstephh 			if (func1)
133244743693Sstephh 				func1(list->status, padding);
133344743693Sstephh 		} else
133444743693Sstephh 			j++;
133544743693Sstephh 	}
133644743693Sstephh 	if (j == 1) {
133744743693Sstephh 		print_name(list->prev, func, padding, &n, pct, full);
133844743693Sstephh 	} else if (j > 1) {
133944743693Sstephh 		(void) printf("%s... %d %s\n", padding, j,
134044743693Sstephh 		    dgettext("FMD", "more entries suppressed,"
134144743693Sstephh 		    " use -v option for full list"));
134244743693Sstephh 	}
134344743693Sstephh 	free(padding);
134444743693Sstephh }
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate static int
134744743693Sstephh asru_same_status(name_list_t *list)
13487c478bd9Sstevel@tonic-gate {
134944743693Sstephh 	name_list_t *end = list;
135044743693Sstephh 	int status = list->status;
135144743693Sstephh 
135244743693Sstephh 	while ((list = list->next) != end) {
135344743693Sstephh 		if (status == -1) {
135444743693Sstephh 			status = list->status;
135544743693Sstephh 			continue;
135644743693Sstephh 		}
135744743693Sstephh 		if (list->status != -1 && status != list->status) {
135844743693Sstephh 			status = -1;
135944743693Sstephh 			break;
136044743693Sstephh 		}
13617c478bd9Sstevel@tonic-gate 	}
136244743693Sstephh 	return (status);
136344743693Sstephh }
136444743693Sstephh 
136544743693Sstephh static int
136644743693Sstephh serial_in_fru(name_list_t *fru, name_list_t *serial)
136744743693Sstephh {
136844743693Sstephh 	name_list_t *sp = serial;
136944743693Sstephh 	name_list_t *fp;
137044743693Sstephh 	int nserial = 0;
137144743693Sstephh 	int found = 0;
137244743693Sstephh 	char buf[128];
13737c478bd9Sstevel@tonic-gate 
137444743693Sstephh 	while (sp) {
137544743693Sstephh 		fp = fru;
137644743693Sstephh 		nserial++;
137744743693Sstephh 		(void) snprintf(buf, sizeof (buf), "serial=%s", sp->name);
137844743693Sstephh 		buf[sizeof (buf) - 1] = 0;
137944743693Sstephh 		while (fp) {
138044743693Sstephh 			if (strstr(fp->name, buf) != NULL) {
138144743693Sstephh 				found++;
138244743693Sstephh 				break;
138344743693Sstephh 			}
138444743693Sstephh 			fp = fp->next;
138544743693Sstephh 			if (fp == fru)
138644743693Sstephh 				break;
138744743693Sstephh 		}
138844743693Sstephh 		sp = sp->next;
138944743693Sstephh 		if (sp == serial)
139044743693Sstephh 			break;
139144743693Sstephh 	}
139244743693Sstephh 	return (found == nserial ? 1 : 0);
139344743693Sstephh }
139444743693Sstephh 
139544743693Sstephh static void
139644743693Sstephh print_sup_record(status_record_t *srp, int opt_i, int full)
139744743693Sstephh {
139844743693Sstephh 	char buf[32];
139944743693Sstephh 	uurec_t *uurp = srp->uurec;
140044743693Sstephh 	int n, j, k, max;
140144743693Sstephh 	int status;
140244743693Sstephh 	ari_list_t *ari_list;
140344743693Sstephh 
140444743693Sstephh 	n = 0;
140544743693Sstephh 	max = max_fault;
140644743693Sstephh 	if (max < 0) {
140744743693Sstephh 		max = 0;
140844743693Sstephh 	}
140944743693Sstephh 	j = max / 2;
141044743693Sstephh 	max -= j;
141144743693Sstephh 	k = srp->nrecs - max;
141244743693Sstephh 	while ((uurp = uurp->next) != NULL) {
141344743693Sstephh 		if (full || n < j || n >= k || max_fault == 0 ||
141444743693Sstephh 		    srp->nrecs == max_fault+1) {
141544743693Sstephh 			if (opt_i) {
141644743693Sstephh 				ari_list = uurp->ari_uuid_list;
141744743693Sstephh 				while (ari_list) {
141844743693Sstephh 					(void) printf("%-15s %s\n",
141944743693Sstephh 					    format_date(buf, sizeof (buf),
142044743693Sstephh 					    uurp->sec), ari_list->ari_uuid);
142144743693Sstephh 					ari_list = ari_list->next;
142244743693Sstephh 				}
142344743693Sstephh 			} else {
142444743693Sstephh 				(void) printf("%-15s %s\n",
142544743693Sstephh 				    format_date(buf, sizeof (buf), uurp->sec),
142644743693Sstephh 				    uurp->uuid);
142744743693Sstephh 			}
142844743693Sstephh 		} else if (n == j)
142944743693Sstephh 			(void) printf("... %d %s\n", srp->nrecs - max_fault,
143044743693Sstephh 			    dgettext("FMD", "more entries suppressed"));
143144743693Sstephh 		n++;
143244743693Sstephh 	}
143344743693Sstephh 	(void) printf("\n");
1434cbf75e67SStephen Hanson 	(void) printf("%s %s", dgettext("FMD", "Host        :"),
1435cbf75e67SStephen Hanson 	    srp->host->server);
1436cbf75e67SStephen Hanson 	if (srp->host->domain)
1437cbf75e67SStephen Hanson 		(void) printf("\t%s %s", dgettext("FMD", "Domain      :"),
1438cbf75e67SStephen Hanson 		    srp->host->domain);
1439cbf75e67SStephen Hanson 	(void) printf("\n%s %s", dgettext("FMD", "Platform    :"),
1440cbf75e67SStephen Hanson 	    srp->host->platform);
1441cbf75e67SStephen Hanson 	(void) printf("\t%s %s\n\n", dgettext("FMD", "Chassis_id  :"),
1442cbf75e67SStephen Hanson 	    srp->host->chassis ? srp->host->chassis : "");
144344743693Sstephh 	if (srp->class)
144444743693Sstephh 		print_name_list(srp->class,
144544743693Sstephh 		    dgettext("FMD", "Fault class :"), NULL, 0, srp->class->pct,
144644743693Sstephh 		    NULL, full);
144744743693Sstephh 	if (srp->asru) {
144844743693Sstephh 		status = asru_same_status(srp->asru);
144944743693Sstephh 		if (status != -1) {
145044743693Sstephh 			print_name_list(srp->asru,
145144743693Sstephh 			    dgettext("FMD", "Affects     :"), NULL,
145244743693Sstephh 			    full ? 0 : max_display, 0, NULL, full);
145344743693Sstephh 			print_asru_status(status, "             ");
145444743693Sstephh 		} else
145544743693Sstephh 			print_name_list(srp->asru,
145644743693Sstephh 			    dgettext("FMD", "Affects     :"), NULL,
145744743693Sstephh 			    full ? 0 : max_display, 0, print_asru_status, full);
145844743693Sstephh 	}
1459cbf75e67SStephen Hanson 	if (full || srp->fru == NULL || srp->asru == NULL) {
146044743693Sstephh 		if (srp->resource) {
146144743693Sstephh 			print_name_list(srp->resource,
146244743693Sstephh 			    dgettext("FMD", "Problem in  :"),
1463cbf75e67SStephen Hanson 			    NULL, full ? 0 : max_display, 0, print_rsrc_status,
1464567cc2e6Sstephh 			    full);
146544743693Sstephh 		}
146644743693Sstephh 	}
146744743693Sstephh 	if (srp->fru) {
1468567cc2e6Sstephh 		status = asru_same_status(srp->fru);
1469567cc2e6Sstephh 		if (status != -1) {
1470567cc2e6Sstephh 			print_name_list(srp->fru, dgettext("FMD",
1471567cc2e6Sstephh 			    "FRU         :"), get_fmri_label, 0,
1472567cc2e6Sstephh 			    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
1473567cc2e6Sstephh 			    NULL, full);
1474567cc2e6Sstephh 			print_fru_status(status, "             ");
1475567cc2e6Sstephh 		} else
1476567cc2e6Sstephh 			print_name_list(srp->fru, dgettext("FMD",
1477567cc2e6Sstephh 			    "FRU         :"), get_fmri_label, 0,
1478567cc2e6Sstephh 			    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
1479567cc2e6Sstephh 			    print_fru_status, full);
148044743693Sstephh 	}
148144743693Sstephh 	if (srp->serial && !serial_in_fru(srp->fru, srp->serial) &&
148244743693Sstephh 	    !serial_in_fru(srp->asru, srp->serial)) {
148344743693Sstephh 		print_name_list(srp->serial, dgettext("FMD", "Serial ID.  :"),
148444743693Sstephh 		    NULL, 0, 0, NULL, full);
148544743693Sstephh 	}
1486*b6955755SRobert Johnston 	print_dict_info(srp->msgid);
148744743693Sstephh 	(void) printf("\n");
148844743693Sstephh }
148944743693Sstephh 
149044743693Sstephh static void
149144743693Sstephh print_status_record(status_record_t *srp, int summary, int opt_i, int full)
149244743693Sstephh {
149344743693Sstephh 	char buf[32];
149444743693Sstephh 	uurec_t *uurp = srp->uurec;
149544743693Sstephh 	static int header = 0;
149644743693Sstephh 	char *head;
149744743693Sstephh 	ari_list_t *ari_list;
149844743693Sstephh 
149944743693Sstephh 	if (!summary || !header) {
150044743693Sstephh 		if (opt_i) {
150144743693Sstephh 			head = "--------------- "
150244743693Sstephh 			    "------------------------------------  "
150344743693Sstephh 			    "-------------- ---------\n"
150444743693Sstephh 			    "TIME            CACHE-ID"
150544743693Sstephh 			    "                              MSG-ID"
150644743693Sstephh 			    "         SEVERITY\n--------------- "
150744743693Sstephh 			    "------------------------------------ "
150844743693Sstephh 			    " -------------- ---------";
150944743693Sstephh 		} else {
151044743693Sstephh 			head = "--------------- "
151144743693Sstephh 			    "------------------------------------  "
151244743693Sstephh 			    "-------------- ---------\n"
151344743693Sstephh 			    "TIME            EVENT-ID"
151444743693Sstephh 			    "                              MSG-ID"
151544743693Sstephh 			    "         SEVERITY\n--------------- "
151644743693Sstephh 			    "------------------------------------ "
151744743693Sstephh 			    " -------------- ---------";
151844743693Sstephh 		}
151944743693Sstephh 		(void) printf("%s\n", dgettext("FMD", head));
152044743693Sstephh 		header = 1;
152144743693Sstephh 	}
152244743693Sstephh 	if (opt_i) {
152344743693Sstephh 		ari_list = uurp->ari_uuid_list;
152444743693Sstephh 		while (ari_list) {
152544743693Sstephh 			(void) printf("%-15s %-37s %-14s %-9s\n",
152644743693Sstephh 			    format_date(buf, sizeof (buf), uurp->sec),
1527*b6955755SRobert Johnston 			    ari_list->ari_uuid, srp->msgid, srp->severity);
152844743693Sstephh 			ari_list = ari_list->next;
152944743693Sstephh 		}
153044743693Sstephh 	} else {
153144743693Sstephh 		(void) printf("%-15s %-37s %-14s %-9s\n",
153244743693Sstephh 		    format_date(buf, sizeof (buf), uurp->sec),
1533*b6955755SRobert Johnston 		    uurp->uuid, srp->msgid, srp->severity);
153444743693Sstephh 	}
153544743693Sstephh 
153644743693Sstephh 	if (!summary)
153744743693Sstephh 		print_sup_record(srp, opt_i, full);
153844743693Sstephh }
153944743693Sstephh 
154044743693Sstephh static void
154144743693Sstephh print_catalog(int summary, int opt_a, int full, int opt_i, int page_feed)
154244743693Sstephh {
154344743693Sstephh 	status_record_t *srp;
154444743693Sstephh 	sr_list_t *slp;
154544743693Sstephh 
154644743693Sstephh 	slp = status_rec_list;
154744743693Sstephh 	if (slp) {
154844743693Sstephh 		for (;;) {
154944743693Sstephh 			srp = slp->status_record;
155044743693Sstephh 			if (opt_a || srp->not_suppressed) {
155144743693Sstephh 				if (page_feed)
155244743693Sstephh 					(void) printf("\f\n");
155344743693Sstephh 				print_status_record(srp, summary, opt_i, full);
155444743693Sstephh 			}
155544743693Sstephh 			if (slp->next == status_rec_list)
155644743693Sstephh 				break;
155744743693Sstephh 			slp = slp->next;
155844743693Sstephh 		}
155944743693Sstephh 	}
156044743693Sstephh }
156144743693Sstephh 
156244743693Sstephh static name_list_t *
156344743693Sstephh find_fru(status_record_t *srp, char *resource)
156444743693Sstephh {
156544743693Sstephh 	name_list_t *rt = NULL;
156644743693Sstephh 	name_list_t *fru = srp->fru;
156744743693Sstephh 
156844743693Sstephh 	while (fru) {
156944743693Sstephh 		if (strcmp(resource, fru->name) == 0) {
157044743693Sstephh 			rt = fru;
157144743693Sstephh 			break;
157244743693Sstephh 		}
157344743693Sstephh 		fru = fru->next;
157444743693Sstephh 		if (fru == srp->fru)
157544743693Sstephh 			break;
157644743693Sstephh 	}
157744743693Sstephh 	return (rt);
157844743693Sstephh }
157944743693Sstephh 
158044743693Sstephh static void
158144743693Sstephh print_fru_line(name_list_t *fru, char *uuid)
158244743693Sstephh {
158344743693Sstephh 	if (fru->pct == 100) {
158444743693Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
158544743693Sstephh 		    dgettext("FMD", "suspects in this FRU total certainty"),
158644743693Sstephh 		    100);
158744743693Sstephh 	} else {
158844743693Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
158944743693Sstephh 		    dgettext("FMD", "suspects in this FRU max certainty"),
159044743693Sstephh 		    fru->max_pct);
159144743693Sstephh 	}
159244743693Sstephh }
159344743693Sstephh 
159444743693Sstephh static void
159544743693Sstephh print_fru(int summary, int opt_a, int opt_i, int page_feed)
159644743693Sstephh {
159744743693Sstephh 	resource_list_t *tp = status_fru_list;
159844743693Sstephh 	status_record_t *srp;
159944743693Sstephh 	sr_list_t *slp, *end;
160044743693Sstephh 	char *msgid, *fru_label;
160144743693Sstephh 	uurec_t *uurp;
160244743693Sstephh 	name_list_t *fru;
1603567cc2e6Sstephh 	int status;
160444743693Sstephh 	ari_list_t *ari_list;
160544743693Sstephh 
160644743693Sstephh 	while (tp) {
160744743693Sstephh 		if (opt_a || tp->not_suppressed) {
160844743693Sstephh 			if (page_feed)
160944743693Sstephh 				(void) printf("\f\n");
161044743693Sstephh 			if (!summary)
161144743693Sstephh 				(void) printf("-----------------------------"
161244743693Sstephh 				    "---------------------------------------"
161344743693Sstephh 				    "----------\n");
1614d4c0a8c5Sstephh 			slp = tp->status_rec_list;
1615d4c0a8c5Sstephh 			end = slp;
1616d4c0a8c5Sstephh 			do {
1617d4c0a8c5Sstephh 				srp = slp->status_record;
1618d4c0a8c5Sstephh 				fru = find_fru(srp, tp->resource);
1619d4c0a8c5Sstephh 				if (fru) {
1620d4c0a8c5Sstephh 					if (fru->label)
1621567cc2e6Sstephh 						(void) printf("\"%s\" (%s) ",
1622d4c0a8c5Sstephh 						    fru->label, fru->name);
1623567cc2e6Sstephh 					else if ((fru_label = get_fmri_label(
1624567cc2e6Sstephh 					    fru->name)) != NULL) {
1625567cc2e6Sstephh 						(void) printf("\"%s\" (%s) ",
1626d4c0a8c5Sstephh 						    fru_label, fru->name);
1627d4c0a8c5Sstephh 						free(fru_label);
1628d4c0a8c5Sstephh 					} else
1629567cc2e6Sstephh 						(void) printf("%s ",
1630d4c0a8c5Sstephh 						    fru->name);
1631d4c0a8c5Sstephh 					break;
1632d4c0a8c5Sstephh 				}
1633d4c0a8c5Sstephh 				slp = slp->next;
1634d4c0a8c5Sstephh 			} while (slp != end);
1635d4c0a8c5Sstephh 
1636567cc2e6Sstephh 			slp = tp->status_rec_list;
1637567cc2e6Sstephh 			end = slp;
1638567cc2e6Sstephh 			status = 0;
1639567cc2e6Sstephh 			do {
1640567cc2e6Sstephh 				srp = slp->status_record;
1641567cc2e6Sstephh 				fru = srp->fru;
1642567cc2e6Sstephh 				while (fru) {
1643567cc2e6Sstephh 					if (strcmp(tp->resource,
1644567cc2e6Sstephh 					    fru->name) == 0)
1645567cc2e6Sstephh 						status |= fru->status;
1646567cc2e6Sstephh 					fru = fru->next;
1647567cc2e6Sstephh 					if (fru == srp->fru)
1648567cc2e6Sstephh 						break;
1649567cc2e6Sstephh 				}
1650567cc2e6Sstephh 				slp = slp->next;
1651567cc2e6Sstephh 			} while (slp != end);
1652567cc2e6Sstephh 			if (status & FM_SUSPECT_NOT_PRESENT)
1653567cc2e6Sstephh 				(void) printf(dgettext("FMD", "not present\n"));
1654567cc2e6Sstephh 			else if (status & FM_SUSPECT_FAULTY)
1655567cc2e6Sstephh 				(void) printf(dgettext("FMD", "faulty\n"));
165625c6ff4bSstephh 			else if (status & FM_SUSPECT_REPLACED)
165725c6ff4bSstephh 				(void) printf(dgettext("FMD", "replaced\n"));
165825c6ff4bSstephh 			else if (status & FM_SUSPECT_REPAIRED)
165925c6ff4bSstephh 				(void) printf(dgettext("FMD",
166025c6ff4bSstephh 				    "repair attempted\n"));
166125c6ff4bSstephh 			else if (status & FM_SUSPECT_ACQUITTED)
166225c6ff4bSstephh 				(void) printf(dgettext("FMD", "acquitted\n"));
1663567cc2e6Sstephh 			else
166425c6ff4bSstephh 				(void) printf(dgettext("FMD", "removed\n"));
1665567cc2e6Sstephh 
166644743693Sstephh 			slp = tp->status_rec_list;
166744743693Sstephh 			end = slp;
166844743693Sstephh 			do {
166944743693Sstephh 				srp = slp->status_record;
167044743693Sstephh 				uurp = srp->uurec;
167144743693Sstephh 				fru = find_fru(srp, tp->resource);
167244743693Sstephh 				if (fru) {
167344743693Sstephh 					if (opt_i) {
167444743693Sstephh 						ari_list = uurp->ari_uuid_list;
167544743693Sstephh 						while (ari_list) {
167644743693Sstephh 							print_fru_line(fru,
167744743693Sstephh 							    ari_list->ari_uuid);
167844743693Sstephh 							ari_list =
167944743693Sstephh 							    ari_list->next;
168044743693Sstephh 						}
168144743693Sstephh 					} else {
168244743693Sstephh 						print_fru_line(fru, uurp->uuid);
168344743693Sstephh 					}
168444743693Sstephh 				}
168544743693Sstephh 				slp = slp->next;
168644743693Sstephh 			} while (slp != end);
168744743693Sstephh 			if (!summary) {
168844743693Sstephh 				slp = tp->status_rec_list;
168944743693Sstephh 				end = slp;
169044743693Sstephh 				srp = slp->status_record;
169144743693Sstephh 				if (srp->serial &&
169244743693Sstephh 				    !serial_in_fru(srp->fru, srp->serial)) {
169344743693Sstephh 					print_name_list(srp->serial,
169444743693Sstephh 					    dgettext("FMD", "Serial ID.  :"),
169544743693Sstephh 					    NULL, 0, 0, NULL, 1);
169644743693Sstephh 				}
169744743693Sstephh 				msgid = NULL;
169844743693Sstephh 				do {
169944743693Sstephh 					if (msgid == NULL ||
170044743693Sstephh 					    strcmp(msgid, srp->msgid) != 0) {
170144743693Sstephh 						msgid = srp->msgid;
1702*b6955755SRobert Johnston 						print_dict_info(srp->msgid);
170344743693Sstephh 					}
170444743693Sstephh 					slp = slp->next;
170544743693Sstephh 				} while (slp != end);
170644743693Sstephh 			}
170744743693Sstephh 		}
170844743693Sstephh 		tp = tp->next;
170944743693Sstephh 		if (tp == status_fru_list)
171044743693Sstephh 			break;
171144743693Sstephh 	}
171244743693Sstephh }
171344743693Sstephh 
171444743693Sstephh static void
171544743693Sstephh print_asru(int opt_a)
171644743693Sstephh {
171744743693Sstephh 	resource_list_t *tp = status_asru_list;
171844743693Sstephh 	status_record_t *srp;
171944743693Sstephh 	sr_list_t *slp, *end;
172044743693Sstephh 	char *msg;
172144743693Sstephh 	int status;
172244743693Sstephh 	name_list_t *asru;
172344743693Sstephh 
172444743693Sstephh 	while (tp) {
172544743693Sstephh 		if (opt_a || tp->not_suppressed) {
172644743693Sstephh 			status = 0;
172744743693Sstephh 			slp = tp->status_rec_list;
172844743693Sstephh 			end = slp;
172944743693Sstephh 			do {
173044743693Sstephh 				srp = slp->status_record;
173144743693Sstephh 				asru = srp->asru;
173244743693Sstephh 				while (asru) {
173344743693Sstephh 					if (strcmp(tp->resource,
173444743693Sstephh 					    asru->name) == 0)
173544743693Sstephh 						status |= asru->status;
173644743693Sstephh 					asru = asru->next;
173744743693Sstephh 					if (asru == srp->asru)
173844743693Sstephh 						break;
173944743693Sstephh 				}
174044743693Sstephh 				slp = slp->next;
174144743693Sstephh 			} while (slp != end);
174244743693Sstephh 			switch (status) {
174344743693Sstephh 			case 0:
174444743693Sstephh 				msg = dgettext("FMD", "ok");
174544743693Sstephh 				break;
174625c6ff4bSstephh 			case FM_SUSPECT_DEGRADED:
174725c6ff4bSstephh 				msg = dgettext("FMD", "degraded");
174825c6ff4bSstephh 				break;
174925c6ff4bSstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED:
175025c6ff4bSstephh 				msg = dgettext("FMD", "degraded");
175125c6ff4bSstephh 				break;
175244743693Sstephh 			case FM_SUSPECT_FAULTY:
175344743693Sstephh 				msg = dgettext("FMD", "degraded");
175444743693Sstephh 				break;
175544743693Sstephh 			case FM_SUSPECT_UNUSABLE:
175644743693Sstephh 				msg = dgettext("FMD", "unknown");
175744743693Sstephh 				break;
175844743693Sstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
175944743693Sstephh 				msg = dgettext("FMD", "faulted");
176044743693Sstephh 				break;
176144743693Sstephh 			default:
176244743693Sstephh 				msg = "";
176344743693Sstephh 				break;
176444743693Sstephh 			}
176544743693Sstephh 			(void) printf("%-69s %s\n", tp->resource, msg);
176644743693Sstephh 		}
176744743693Sstephh 		tp = tp->next;
176844743693Sstephh 		if (tp == status_asru_list)
176944743693Sstephh 			break;
177044743693Sstephh 	}
177144743693Sstephh }
177244743693Sstephh 
177344743693Sstephh static int
177444743693Sstephh uuid_in_list(char *uuid, uurec_select_t *uurecp)
177544743693Sstephh {
177644743693Sstephh 	while (uurecp) {
177744743693Sstephh 		if (strcmp(uuid, uurecp->uuid) == 0)
177844743693Sstephh 			return (1);
177944743693Sstephh 		uurecp = uurecp->next;
178044743693Sstephh 	}
17817c478bd9Sstevel@tonic-gate 	return (0);
17827c478bd9Sstevel@tonic-gate }
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate static int
178544743693Sstephh dfault_rec(const fmd_adm_caseinfo_t *acp, void *arg)
17867c478bd9Sstevel@tonic-gate {
178744743693Sstephh 	int64_t *diag_time;
178844743693Sstephh 	uint_t nelem;
178944743693Sstephh 	int rt = 0;
179044743693Sstephh 	char *uuid = "-";
179144743693Sstephh 	uurec_select_t *uurecp = (uurec_select_t *)arg;
179244743693Sstephh 
179344743693Sstephh 	if (nvlist_lookup_int64_array(acp->aci_event, FM_SUSPECT_DIAG_TIME,
179444743693Sstephh 	    &diag_time, &nelem) == 0 && nelem >= 2) {
179544743693Sstephh 		(void) nvlist_lookup_string(acp->aci_event, FM_SUSPECT_UUID,
179644743693Sstephh 		    &uuid);
179744743693Sstephh 		if (uurecp == NULL || uuid_in_list(uuid, uurecp))
179844743693Sstephh 			add_fault_record_to_catalog(acp->aci_event, *diag_time,
1799*b6955755SRobert Johnston 			    uuid);
180044743693Sstephh 	} else {
180144743693Sstephh 		rt = -1;
18027c478bd9Sstevel@tonic-gate 	}
180344743693Sstephh 	return (rt);
180444743693Sstephh }
18057c478bd9Sstevel@tonic-gate 
180644743693Sstephh /*ARGSUSED*/
180744743693Sstephh static int
180844743693Sstephh dstatus_rec(const fmd_adm_rsrcinfo_t *ari, void *unused)
180944743693Sstephh {
181044743693Sstephh 	update_asru_state_in_catalog(ari->ari_case, ari->ari_uuid);
18117c478bd9Sstevel@tonic-gate 	return (0);
18127c478bd9Sstevel@tonic-gate }
18137c478bd9Sstevel@tonic-gate 
181444743693Sstephh static int
181544743693Sstephh get_cases_from_fmd(fmd_adm_t *adm, uurec_select_t *uurecp, int opt_i)
181644743693Sstephh {
181744743693Sstephh 	int rt = FMADM_EXIT_SUCCESS;
181844743693Sstephh 
181944743693Sstephh 	/*
182044743693Sstephh 	 * These calls may fail with Protocol error if message payload is to big
182144743693Sstephh 	 */
182244743693Sstephh 	if (fmd_adm_case_iter(adm, NULL, dfault_rec, uurecp) != 0)
182344743693Sstephh 		die("failed to get case list from fmd");
182444743693Sstephh 	if (opt_i && fmd_adm_rsrc_iter(adm, 1, dstatus_rec, NULL) != 0)
182544743693Sstephh 		die("failed to get case status from fmd");
182644743693Sstephh 	return (rt);
182744743693Sstephh }
182844743693Sstephh 
182944743693Sstephh /*
183044743693Sstephh  * fmadm faulty command
183144743693Sstephh  *
183244743693Sstephh  *	-a		show hidden fault records
183344743693Sstephh  *	-f		show faulty fru's
183444743693Sstephh  *	-g		force grouping of similar faults on the same fru
183544743693Sstephh  *	-n		number of fault records to display
183644743693Sstephh  *	-p		pipe output through pager
183744743693Sstephh  *	-r		show faulty asru's
183844743693Sstephh  *	-s		print summary of first fault
183944743693Sstephh  *	-u		print listed uuid's only
184044743693Sstephh  *	-v		full output
184144743693Sstephh  */
184244743693Sstephh 
18437c478bd9Sstevel@tonic-gate int
18447c478bd9Sstevel@tonic-gate cmd_faulty(fmd_adm_t *adm, int argc, char *argv[])
18457c478bd9Sstevel@tonic-gate {
184644743693Sstephh 	int opt_a = 0, opt_v = 0, opt_p = 0, opt_s = 0, opt_r = 0, opt_f = 0;
184744743693Sstephh 	int opt_i = 0;
184844743693Sstephh 	char *pager;
184944743693Sstephh 	FILE *fp;
185044743693Sstephh 	int rt, c, stat;
185144743693Sstephh 	uurec_select_t *tp;
185244743693Sstephh 	uurec_select_t *uurecp = NULL;
18537c478bd9Sstevel@tonic-gate 
185444743693Sstephh 	while ((c = getopt(argc, argv, "afgin:prsu:v")) != EOF) {
18557c478bd9Sstevel@tonic-gate 		switch (c) {
18567c478bd9Sstevel@tonic-gate 		case 'a':
18577c478bd9Sstevel@tonic-gate 			opt_a++;
18587c478bd9Sstevel@tonic-gate 			break;
185944743693Sstephh 		case 'f':
186044743693Sstephh 			opt_f++;
186144743693Sstephh 			break;
186244743693Sstephh 		case 'g':
186344743693Sstephh 			opt_g++;
186444743693Sstephh 			break;
18657c478bd9Sstevel@tonic-gate 		case 'i':
186644743693Sstephh 			opt_i++;
186744743693Sstephh 			break;
186844743693Sstephh 		case 'n':
186944743693Sstephh 			max_fault = atoi(optarg);
187044743693Sstephh 			break;
187144743693Sstephh 		case 'p':
187244743693Sstephh 			opt_p++;
187344743693Sstephh 			break;
187444743693Sstephh 		case 'r':
187544743693Sstephh 			opt_r++;
187644743693Sstephh 			break;
187744743693Sstephh 		case 's':
187844743693Sstephh 			opt_s++;
187944743693Sstephh 			break;
188044743693Sstephh 		case 'u':
188144743693Sstephh 			tp = (uurec_select_t *)malloc(sizeof (uurec_select_t));
188244743693Sstephh 			tp->uuid = optarg;
188344743693Sstephh 			tp->next = uurecp;
188444743693Sstephh 			uurecp = tp;
188544743693Sstephh 			opt_a = 1;
188644743693Sstephh 			break;
188744743693Sstephh 		case 'v':
188844743693Sstephh 			opt_v++;
18897c478bd9Sstevel@tonic-gate 			break;
18907c478bd9Sstevel@tonic-gate 		default:
18917c478bd9Sstevel@tonic-gate 			return (FMADM_EXIT_USAGE);
18927c478bd9Sstevel@tonic-gate 		}
18937c478bd9Sstevel@tonic-gate 	}
18947c478bd9Sstevel@tonic-gate 	if (optind < argc)
18957c478bd9Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
18967c478bd9Sstevel@tonic-gate 
1897*b6955755SRobert Johnston 	if ((fmadm_msghdl = fmd_msg_init(NULL, FMD_MSG_VERSION)) == NULL)
1898*b6955755SRobert Johnston 		return (FMADM_EXIT_ERROR);
189944743693Sstephh 	rt = get_cases_from_fmd(adm, uurecp, opt_i);
190044743693Sstephh 	if (opt_p) {
190144743693Sstephh 		if ((pager = getenv("PAGER")) == NULL)
190244743693Sstephh 			pager = "/usr/bin/more";
190344743693Sstephh 		fp = popen(pager, "w");
190444743693Sstephh 		if (fp == NULL) {
190544743693Sstephh 			rt = FMADM_EXIT_ERROR;
190644743693Sstephh 			opt_p = 0;
190744743693Sstephh 		} else {
190844743693Sstephh 			dup2(fileno(fp), 1);
190944743693Sstephh 			setbuf(stdout, NULL);
191044743693Sstephh 			(void) fclose(fp);
191144743693Sstephh 		}
191244743693Sstephh 	}
191344743693Sstephh 	max_display = max_fault;
191444743693Sstephh 	if (opt_f)
191544743693Sstephh 		print_fru(opt_s, opt_a, opt_i, opt_p && !opt_s);
191644743693Sstephh 	if (opt_r)
191744743693Sstephh 		print_asru(opt_a);
191844743693Sstephh 	if (opt_f == 0 && opt_r == 0)
191944743693Sstephh 		print_catalog(opt_s, opt_a, opt_v, opt_i, opt_p && !opt_s);
1920*b6955755SRobert Johnston 	fmd_msg_fini(fmadm_msghdl);
192144743693Sstephh 	label_release_topo();
192244743693Sstephh 	if (opt_p) {
192344743693Sstephh 		(void) fclose(stdout);
192444743693Sstephh 		(void) wait(&stat);
192544743693Sstephh 	}
192644743693Sstephh 	return (rt);
19277c478bd9Sstevel@tonic-gate }
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate int
19307c478bd9Sstevel@tonic-gate cmd_flush(fmd_adm_t *adm, int argc, char *argv[])
19317c478bd9Sstevel@tonic-gate {
19327c478bd9Sstevel@tonic-gate 	int i, status = FMADM_EXIT_SUCCESS;
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 	if (argc < 2 || (i = getopt(argc, argv, "")) != EOF)
19357c478bd9Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 	for (i = 1; i < argc; i++) {
19387c478bd9Sstevel@tonic-gate 		if (fmd_adm_rsrc_flush(adm, argv[i]) != 0) {
19397c478bd9Sstevel@tonic-gate 			warn("failed to flush %s", argv[i]);
19407c478bd9Sstevel@tonic-gate 			status = FMADM_EXIT_ERROR;
19417c478bd9Sstevel@tonic-gate 		} else
19427c478bd9Sstevel@tonic-gate 			note("flushed resource history for %s\n", argv[i]);
19437c478bd9Sstevel@tonic-gate 	}
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 	return (status);
19467c478bd9Sstevel@tonic-gate }
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate int
19497c478bd9Sstevel@tonic-gate cmd_repair(fmd_adm_t *adm, int argc, char *argv[])
19507c478bd9Sstevel@tonic-gate {
19517c478bd9Sstevel@tonic-gate 	int err;
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	if (getopt(argc, argv, "") != EOF)
19547c478bd9Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	if (argc - optind != 1)
19577c478bd9Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 	/*
196025c6ff4bSstephh 	 * argument could be a uuid, an fmri (asru, fru or resource)
1961567cc2e6Sstephh 	 * or a label. Try uuid first, If that fails try the others.
19627c478bd9Sstevel@tonic-gate 	 */
1963567cc2e6Sstephh 	err = fmd_adm_case_repair(adm, argv[optind]);
1964567cc2e6Sstephh 	if (err != 0)
196525c6ff4bSstephh 		err = fmd_adm_rsrc_repaired(adm, argv[optind]);
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	if (err != 0)
19687c478bd9Sstevel@tonic-gate 		die("failed to record repair to %s", argv[optind]);
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 	note("recorded repair to %s\n", argv[optind]);
19717c478bd9Sstevel@tonic-gate 	return (FMADM_EXIT_SUCCESS);
19727c478bd9Sstevel@tonic-gate }
197325c6ff4bSstephh 
197425c6ff4bSstephh int
197525c6ff4bSstephh cmd_repaired(fmd_adm_t *adm, int argc, char *argv[])
197625c6ff4bSstephh {
197725c6ff4bSstephh 	int err;
197825c6ff4bSstephh 
197925c6ff4bSstephh 	if (getopt(argc, argv, "") != EOF)
198025c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
198125c6ff4bSstephh 
198225c6ff4bSstephh 	if (argc - optind != 1)
198325c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
198425c6ff4bSstephh 
198525c6ff4bSstephh 	/*
198625c6ff4bSstephh 	 * argument could be an fmri (asru, fru or resource) or a label.
198725c6ff4bSstephh 	 */
198825c6ff4bSstephh 	err = fmd_adm_rsrc_repaired(adm, argv[optind]);
198925c6ff4bSstephh 	if (err != 0)
199025c6ff4bSstephh 		die("failed to record repair to %s", argv[optind]);
199125c6ff4bSstephh 
199225c6ff4bSstephh 	note("recorded repair to of %s\n", argv[optind]);
199325c6ff4bSstephh 	return (FMADM_EXIT_SUCCESS);
199425c6ff4bSstephh }
199525c6ff4bSstephh 
199625c6ff4bSstephh int
199725c6ff4bSstephh cmd_replaced(fmd_adm_t *adm, int argc, char *argv[])
199825c6ff4bSstephh {
199925c6ff4bSstephh 	int err;
200025c6ff4bSstephh 
200125c6ff4bSstephh 	if (getopt(argc, argv, "") != EOF)
200225c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
200325c6ff4bSstephh 
200425c6ff4bSstephh 	if (argc - optind != 1)
200525c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
200625c6ff4bSstephh 
200725c6ff4bSstephh 	/*
200825c6ff4bSstephh 	 * argument could be an fmri (asru, fru or resource) or a label.
200925c6ff4bSstephh 	 */
201025c6ff4bSstephh 	err = fmd_adm_rsrc_replaced(adm, argv[optind]);
201125c6ff4bSstephh 	if (err != 0)
201225c6ff4bSstephh 		die("failed to record replacement of %s", argv[optind]);
201325c6ff4bSstephh 
201425c6ff4bSstephh 	note("recorded replacement of %s\n", argv[optind]);
201525c6ff4bSstephh 	return (FMADM_EXIT_SUCCESS);
201625c6ff4bSstephh }
201725c6ff4bSstephh 
201825c6ff4bSstephh int
201925c6ff4bSstephh cmd_acquit(fmd_adm_t *adm, int argc, char *argv[])
202025c6ff4bSstephh {
202125c6ff4bSstephh 	int err;
202225c6ff4bSstephh 
202325c6ff4bSstephh 	if (getopt(argc, argv, "") != EOF)
202425c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
202525c6ff4bSstephh 
202625c6ff4bSstephh 	if (argc - optind != 1 && argc - optind != 2)
202725c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
202825c6ff4bSstephh 
202925c6ff4bSstephh 	/*
203025c6ff4bSstephh 	 * argument could be a uuid, an fmri (asru, fru or resource)
203125c6ff4bSstephh 	 * or a label. Or it could be a uuid and an fmri or label.
203225c6ff4bSstephh 	 */
203325c6ff4bSstephh 	if (argc - optind == 2) {
203425c6ff4bSstephh 		err = fmd_adm_rsrc_acquit(adm, argv[optind], argv[optind + 1]);
203525c6ff4bSstephh 		if (err != 0)
203625c6ff4bSstephh 			err = fmd_adm_rsrc_acquit(adm, argv[optind + 1],
203725c6ff4bSstephh 			    argv[optind]);
203825c6ff4bSstephh 	} else {
203925c6ff4bSstephh 		err = fmd_adm_case_acquit(adm, argv[optind]);
204025c6ff4bSstephh 		if (err != 0)
204125c6ff4bSstephh 			err = fmd_adm_rsrc_acquit(adm, argv[optind], "");
204225c6ff4bSstephh 	}
204325c6ff4bSstephh 
204425c6ff4bSstephh 	if (err != 0)
204525c6ff4bSstephh 		die("failed to record acquital of %s", argv[optind]);
204625c6ff4bSstephh 
204725c6ff4bSstephh 	note("recorded acquital of %s\n", argv[optind]);
204825c6ff4bSstephh 	return (FMADM_EXIT_SUCCESS);
204925c6ff4bSstephh }
2050