xref: /illumos-gate/usr/src/cmd/fm/fmadm/common/faulty.c (revision 7adb68a6)
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 /*
22e58a33b6SStephen Hanson  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23*7adb68a6SHans Rosenfeld  * Copyright 2020 Joyent, Inc.
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>
40b6955755SRobert 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>
495c5f1371SRichard Lowe #include <stddef.h>
5044743693Sstephh 
5144743693Sstephh /*
5244743693Sstephh  * Fault records are added to catalog by calling add_fault_record_to_catalog()
5344743693Sstephh  * records are stored in order of importance to the system.
5444743693Sstephh  * If -g flag is set or not_suppressed is not set and the class fru, fault,
5544743693Sstephh  * type are the same then details are merged into an existing record, with uuid
5644743693Sstephh  * records are stored in time order.
5744743693Sstephh  * For each record information is extracted from nvlist and merged into linked
5844743693Sstephh  * list each is checked for identical records for which percentage certainty are
5944743693Sstephh  * added together.
6044743693Sstephh  * print_catalog() is called to print out catalog and release external resources
6144743693Sstephh  *
6244743693Sstephh  *                         /---------------\
6344743693Sstephh  *	status_rec_list -> |               | -|
6444743693Sstephh  *                         \---------------/
6544743693Sstephh  *                                \/
6644743693Sstephh  *                         /---------------\    /-------\    /-------\
6744743693Sstephh  *      status_fru_list    | status_record | -> | uurec | -> | uurec | -|
6844743693Sstephh  *            \/           |               | |- |       | <- |       |
6944743693Sstephh  *      /-------------\    |               |    \-------/    \-------/
7044743693Sstephh  *      |             | -> |               |       \/           \/
7144743693Sstephh  *      \-------------/    |               |    /-------\    /-------\
7244743693Sstephh  *            \/           |               | -> | asru  | -> | asru  |
7344743693Sstephh  *            ---          |               |    |       | <- |       |
7444743693Sstephh  *                         |               |    \-------/    \-------/
7544743693Sstephh  *      status_asru_list   |  class        |
7644743693Sstephh  *            \/           |  resource     |    /-------\    /-------\
7744743693Sstephh  *      /-------------\    |  fru          | -> | list  | -> | list  |
7844743693Sstephh  *      |             | -> |  serial       |    |       | <- |       |
7944743693Sstephh  *      \-------------/    |               |    \-------/    \-------/
8044743693Sstephh  *            \/           \---------------/
8144743693Sstephh  *            ---               \/    /\
8244743693Sstephh  *                         /---------------\
8344743693Sstephh  *                         | status_record |
8444743693Sstephh  *                         \---------------/
8544743693Sstephh  *
8644743693Sstephh  * Fmadm faulty takes a number of options which affect the format of the
8744743693Sstephh  * output displayed. By default, the display reports the FRU and ASRU along
8844743693Sstephh  * with other information on per-case basis as in the example below.
8944743693Sstephh  *
9044743693Sstephh  * --------------- ------------------------------------  -------------- -------
9144743693Sstephh  * TIME            EVENT-ID                              MSG-ID         SEVERITY
9244743693Sstephh  * --------------- ------------------------------------  -------------- -------
9344743693Sstephh  * Sep 21 10:01:36 d482f935-5c8f-e9ab-9f25-d0aaafec1e6c  AMD-8000-2F    Major
9444743693Sstephh  *
9544743693Sstephh  * Fault class	: fault.memory.dimm_sb
9644743693Sstephh  * Affects	: mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0
9725c6ff4bSstephh  *		    faulted but still in service
9844743693Sstephh  * FRU		: "CPU 0 DIMM 0" (hc://.../memory-controller=0/dimm=0)
9944743693Sstephh  *		    faulty
10044743693Sstephh  *
10144743693Sstephh  * Description	: The number of errors associated with this memory module has
10244743693Sstephh  *		exceeded acceptable levels.  Refer to
103654b400cSJoshua M. Clulow  *		http://illumos.org/msg/AMD-8000-2F for more information.
10444743693Sstephh  *
10544743693Sstephh  * Response	: Pages of memory associated with this memory module are being
10644743693Sstephh  *		removed from service as errors are reported.
10744743693Sstephh  *
10844743693Sstephh  * Impact	: Total system memory capacity will be reduced as pages are
10944743693Sstephh  *		retired.
11044743693Sstephh  *
11144743693Sstephh  * Action	: Schedule a repair procedure to replace the affected memory
11244743693Sstephh  *		module.  Use fmdump -v -u <EVENT_ID> to identify the module.
11344743693Sstephh  *
11444743693Sstephh  * The -v flag is similar, but adds some additonal information such as the
11544743693Sstephh  * resource. The -s flag is also similar but just gives the top line summary.
11644743693Sstephh  * All these options (ie without the -f or -r flags) use the print_catalog()
11744743693Sstephh  * function to do the display.
11844743693Sstephh  *
11944743693Sstephh  * The -f flag changes the output so that it appears sorted on a per-fru basis.
12044743693Sstephh  * The output is somewhat cut down compared to the default output. If -f is
12144743693Sstephh  * used, then print_fru() is used to print the output.
12244743693Sstephh  *
12344743693Sstephh  * -----------------------------------------------------------------------------
12444743693Sstephh  * "SLOT 2" (hc://.../hostbridge=3/pciexrc=3/pciexbus=4/pciexdev=0) faulty
12544743693Sstephh  * 5ca4aeb3-36...f6be-c2e8166dc484 2 suspects in this FRU total certainty 100%
12644743693Sstephh  *
12744743693Sstephh  * Description	: A problem was detected for a PCI device.
128654b400cSJoshua M. Clulow  *		Refer to http://illumos.org/msg/PCI-8000-7J
129654b400cSJoshua M. Clulow  *		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.
137940f2f58SToomas Soome  *		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;
18588045cffSRobert Johnston 	nvlist_t *event;
18644743693Sstephh } uurec_t;
18744743693Sstephh 
18844743693Sstephh typedef struct uurec_select {
18944743693Sstephh 	struct uurec_select *next;
19044743693Sstephh 	char *uuid;
19144743693Sstephh } uurec_select_t;
19244743693Sstephh 
19344743693Sstephh typedef struct host_id {
19444743693Sstephh 	char *chassis;
19544743693Sstephh 	char *server;
19644743693Sstephh 	char *platform;
197cbf75e67SStephen Hanson 	char *domain;
1989c94f155SCheng Sean Ye 	char *product_sn;
19944743693Sstephh } hostid_t;
20044743693Sstephh 
20144743693Sstephh typedef struct host_id_list {
20244743693Sstephh 	hostid_t hostid;
20344743693Sstephh 	struct host_id_list *next;
20444743693Sstephh } host_id_list_t;
20544743693Sstephh 
20644743693Sstephh typedef struct status_record {
20744743693Sstephh 	hostid_t *host;
20844743693Sstephh 	int nrecs;
20944743693Sstephh 	uurec_t *uurec;
21044743693Sstephh 	char *severity;			/* in C locale */
21144743693Sstephh 	char *msgid;
21244743693Sstephh 	name_list_t *class;
21344743693Sstephh 	name_list_t *resource;
21444743693Sstephh 	name_list_t *asru;
21544743693Sstephh 	name_list_t *fru;
21644743693Sstephh 	name_list_t *serial;
21744743693Sstephh 	uint8_t not_suppressed;
218540db9a9SStephen Hanson 	uint8_t injected;
21944743693Sstephh } status_record_t;
22044743693Sstephh 
22144743693Sstephh typedef struct sr_list {
22244743693Sstephh 	struct sr_list *next;
22344743693Sstephh 	struct sr_list *prev;
22444743693Sstephh 	struct status_record *status_record;
22544743693Sstephh } sr_list_t;
22644743693Sstephh 
22744743693Sstephh typedef struct resource_list {
22844743693Sstephh 	struct resource_list *next;
22944743693Sstephh 	struct resource_list *prev;
23044743693Sstephh 	sr_list_t *status_rec_list;
23144743693Sstephh 	char *resource;
23244743693Sstephh 	uint8_t not_suppressed;
233540db9a9SStephen Hanson 	uint8_t injected;
23444743693Sstephh 	uint8_t max_pct;
23544743693Sstephh } resource_list_t;
23644743693Sstephh 
23744743693Sstephh sr_list_t *status_rec_list;
23844743693Sstephh resource_list_t *status_fru_list;
23944743693Sstephh resource_list_t *status_asru_list;
24044743693Sstephh 
24144743693Sstephh static int max_display;
24244743693Sstephh static int max_fault = 0;
24344743693Sstephh static topo_hdl_t *topo_handle;
24444743693Sstephh static host_id_list_t *host_list;
24544743693Sstephh static int n_server;
24644743693Sstephh static int opt_g;
247b6955755SRobert Johnston static fmd_msg_hdl_t *fmadm_msghdl = NULL; /* handle for libfmd_msg calls */
24844743693Sstephh 
24944743693Sstephh static char *
format_date(char * buf,size_t len,uint64_t sec)25044743693Sstephh format_date(char *buf, size_t len, uint64_t sec)
25144743693Sstephh {
25244743693Sstephh 	if (sec > LONG_MAX) {
25344743693Sstephh 		(void) fprintf(stderr,
25444743693Sstephh 		    "record time is too large for 32-bit utility\n");
25544743693Sstephh 		(void) snprintf(buf, len, "0x%llx", sec);
25644743693Sstephh 	} else {
25744743693Sstephh 		time_t tod = (time_t)sec;
258540db9a9SStephen Hanson 		time_t now = time(NULL);
259540db9a9SStephen Hanson 		if (tod > now+60 ||
260540db9a9SStephen Hanson 		    tod < now - 6L*30L*24L*60L*60L) { /* 6 months ago */
261540db9a9SStephen Hanson 			(void) strftime(buf, len, "%b %d %Y    ",
262540db9a9SStephen Hanson 			    localtime(&tod));
263540db9a9SStephen Hanson 		} else {
264540db9a9SStephen Hanson 			(void) strftime(buf, len, "%b %d %T", localtime(&tod));
265540db9a9SStephen Hanson 		}
26644743693Sstephh 	}
26744743693Sstephh 
26844743693Sstephh 	return (buf);
26944743693Sstephh }
27044743693Sstephh 
27144743693Sstephh static hostid_t *
find_hostid_in_list(char * platform,char * chassis,char * server,char * domain,char * product_sn)2729c94f155SCheng Sean Ye find_hostid_in_list(char *platform, char *chassis, char *server, char *domain,
2739c94f155SCheng Sean Ye     char *product_sn)
27444743693Sstephh {
27544743693Sstephh 	hostid_t *rt = NULL;
27644743693Sstephh 	host_id_list_t *hostp;
27744743693Sstephh 
27844743693Sstephh 	if (platform == NULL)
27944743693Sstephh 		platform = "-";
28044743693Sstephh 	if (server == NULL)
28144743693Sstephh 		server = "-";
28244743693Sstephh 	hostp = host_list;
28344743693Sstephh 	while (hostp) {
28444743693Sstephh 		if (hostp->hostid.platform &&
28544743693Sstephh 		    strcmp(hostp->hostid.platform, platform) == 0 &&
28644743693Sstephh 		    hostp->hostid.server &&
28744743693Sstephh 		    strcmp(hostp->hostid.server, server) == 0 &&
28844743693Sstephh 		    (chassis == NULL || hostp->hostid.chassis == NULL ||
289cbf75e67SStephen Hanson 		    strcmp(chassis, hostp->hostid.chassis) == 0) &&
2909c94f155SCheng Sean Ye 		    (product_sn == NULL || hostp->hostid.product_sn == NULL ||
2919c94f155SCheng Sean Ye 		    strcmp(product_sn, hostp->hostid.product_sn) == 0) &&
292cbf75e67SStephen Hanson 		    (domain == NULL || hostp->hostid.domain == NULL ||
293cbf75e67SStephen Hanson 		    strcmp(domain, hostp->hostid.domain) == 0)) {
29444743693Sstephh 			rt = &hostp->hostid;
29544743693Sstephh 			break;
29644743693Sstephh 		}
29744743693Sstephh 		hostp = hostp->next;
29844743693Sstephh 	}
29944743693Sstephh 	if (rt == NULL) {
30044743693Sstephh 		hostp = malloc(sizeof (host_id_list_t));
30144743693Sstephh 		hostp->hostid.platform = strdup(platform);
3029c94f155SCheng Sean Ye 		hostp->hostid.product_sn =
3039c94f155SCheng Sean Ye 		    product_sn ? strdup(product_sn) : NULL;
30444743693Sstephh 		hostp->hostid.server = strdup(server);
30544743693Sstephh 		hostp->hostid.chassis = chassis ? strdup(chassis) : NULL;
306cbf75e67SStephen Hanson 		hostp->hostid.domain = domain ? strdup(domain) : NULL;
30744743693Sstephh 		hostp->next = host_list;
30844743693Sstephh 		host_list = hostp;
30944743693Sstephh 		rt = &hostp->hostid;
31044743693Sstephh 		n_server++;
31144743693Sstephh 	}
31244743693Sstephh 	return (rt);
31344743693Sstephh }
31444743693Sstephh 
31544743693Sstephh static hostid_t *
find_hostid(nvlist_t * nvl)31644743693Sstephh find_hostid(nvlist_t *nvl)
31744743693Sstephh {
318cbf75e67SStephen Hanson 	char *platform = NULL, *chassis = NULL, *server = NULL, *domain = NULL;
3199c94f155SCheng Sean Ye 	char *product_sn = NULL;
32044743693Sstephh 	nvlist_t *auth, *fmri;
32144743693Sstephh 	hostid_t *rt = NULL;
32244743693Sstephh 
32344743693Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &fmri) == 0 &&
32444743693Sstephh 	    nvlist_lookup_nvlist(fmri, FM_FMRI_AUTHORITY, &auth) == 0) {
32544743693Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT,
32644743693Sstephh 		    &platform);
3279c94f155SCheng Sean Ye 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN,
3289c94f155SCheng Sean Ye 		    &product_sn);
32944743693Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server);
33044743693Sstephh 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS,
33144743693Sstephh 		    &chassis);
332cbf75e67SStephen Hanson 		(void) nvlist_lookup_string(auth, FM_FMRI_AUTH_DOMAIN, &domain);
3339c94f155SCheng Sean Ye 		rt = find_hostid_in_list(platform, chassis, server,
3349c94f155SCheng Sean Ye 		    domain, product_sn);
33544743693Sstephh 	}
33644743693Sstephh 	return (rt);
33744743693Sstephh }
33844743693Sstephh 
33944743693Sstephh static char *
get_nvl2str_topo(nvlist_t * nvl)34044743693Sstephh get_nvl2str_topo(nvlist_t *nvl)
34144743693Sstephh {
34244743693Sstephh 	char *name = NULL;
34344743693Sstephh 	char *tname;
34444743693Sstephh 	int err;
34544743693Sstephh 	char *scheme = NULL;
34644743693Sstephh 	char *mod_name = NULL;
34744743693Sstephh 	char buf[128];
34844743693Sstephh 
34944743693Sstephh 	if (topo_handle == NULL)
350e58a33b6SStephen Hanson 		topo_handle = topo_open(TOPO_VERSION, 0, &err);
35144743693Sstephh 	if (topo_fmri_nvl2str(topo_handle, nvl, &tname, &err) == 0) {
35244743693Sstephh 		name = strdup(tname);
35344743693Sstephh 		topo_hdl_strfree(topo_handle, tname);
35444743693Sstephh 	} else {
35544743693Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme);
35644743693Sstephh 		(void) nvlist_lookup_string(nvl, FM_FMRI_MOD_NAME, &mod_name);
35744743693Sstephh 		if (scheme && strcmp(scheme, FM_FMRI_SCHEME_FMD) == 0 &&
35844743693Sstephh 		    mod_name) {
35944743693Sstephh 			(void) snprintf(buf, sizeof (buf), "%s:///module/%s",
36044743693Sstephh 			    scheme, mod_name);
36144743693Sstephh 			name = strdup(buf);
36244743693Sstephh 		}
36344743693Sstephh 	}
36444743693Sstephh 	return (name);
36544743693Sstephh }
36644743693Sstephh 
36744743693Sstephh static int
set_priority(char * s)36844743693Sstephh set_priority(char *s)
36944743693Sstephh {
37044743693Sstephh 	int rt = 0;
37144743693Sstephh 
37244743693Sstephh 	if (s) {
37344743693Sstephh 		if (strcmp(s, "Minor") == 0)
37444743693Sstephh 			rt = 1;
37544743693Sstephh 		else if (strcmp(s, "Major") == 0)
37644743693Sstephh 			rt = 10;
37744743693Sstephh 		else if (strcmp(s, "Critical") == 0)
37844743693Sstephh 			rt = 100;
37944743693Sstephh 	}
38044743693Sstephh 	return (rt);
38144743693Sstephh }
38244743693Sstephh 
38344743693Sstephh static int
cmp_priority(char * s1,char * s2,uint64_t t1,uint64_t t2,uint8_t p1,uint8_t p2)38444743693Sstephh cmp_priority(char *s1, char *s2, uint64_t t1, uint64_t t2, uint8_t p1,
38544743693Sstephh     uint8_t p2)
38644743693Sstephh {
38744743693Sstephh 	int r1, r2;
38844743693Sstephh 	int rt;
38944743693Sstephh 
39044743693Sstephh 	r1 = set_priority(s1);
39144743693Sstephh 	r2 = set_priority(s2);
39244743693Sstephh 	rt = r1 - r2;
39344743693Sstephh 	if (rt == 0) {
39444743693Sstephh 		if (t1 > t2)
39544743693Sstephh 			rt = 1;
39644743693Sstephh 		else if (t1 < t2)
39744743693Sstephh 			rt = -1;
39844743693Sstephh 		else
39944743693Sstephh 			rt = p1 - p2;
40044743693Sstephh 	}
40144743693Sstephh 	return (rt);
40244743693Sstephh }
40344743693Sstephh 
40444743693Sstephh /*
40544743693Sstephh  * merge two lists into one, by comparing enties in new and moving into list if
40644743693Sstephh  * name is not there or free off memory for names which are already there
40744743693Sstephh  * add_pct indicates if pct is the sum or highest pct
40844743693Sstephh  */
40944743693Sstephh static name_list_t *
merge_name_list(name_list_t ** list,name_list_t * new,int add_pct)41044743693Sstephh merge_name_list(name_list_t **list, name_list_t *new, int add_pct)
41144743693Sstephh {
41244743693Sstephh 	name_list_t *lp, *np, *sp, *rt = NULL;
41344743693Sstephh 	int max_pct;
41444743693Sstephh 
41544743693Sstephh 	rt = *list;
41644743693Sstephh 	np = new;
41744743693Sstephh 	while (np) {
41844743693Sstephh 		lp = *list;
41944743693Sstephh 		while (lp) {
42044743693Sstephh 			if (strcmp(lp->name, np->name) == 0)
42144743693Sstephh 				break;
42244743693Sstephh 			lp = lp->next;
42344743693Sstephh 			if (lp == *list)
42444743693Sstephh 				lp = NULL;
42544743693Sstephh 		}
42644743693Sstephh 		if (np->next == new)
42744743693Sstephh 			sp = NULL;
42844743693Sstephh 		else
42944743693Sstephh 			sp = np->next;
43044743693Sstephh 		if (lp) {
43144743693Sstephh 			lp->status |= (np->status & FM_SUSPECT_FAULTY);
43244743693Sstephh 			if (add_pct) {
43344743693Sstephh 				lp->pct += np->pct;
43444743693Sstephh 				lp->count += np->count;
43544743693Sstephh 			} else if (np->pct > lp->pct) {
43644743693Sstephh 				lp->pct = np->pct;
43744743693Sstephh 			}
43844743693Sstephh 			max_pct = np->max_pct;
439d4c0a8c5Sstephh 			if (np->label)
440d4c0a8c5Sstephh 				free(np->label);
44144743693Sstephh 			free(np->name);
44244743693Sstephh 			free(np);
44344743693Sstephh 			np = NULL;
44444743693Sstephh 			if (max_pct > lp->max_pct) {
44544743693Sstephh 				lp->max_pct = max_pct;
44644743693Sstephh 				if (lp->max_pct > lp->prev->max_pct &&
44744743693Sstephh 				    lp != *list) {
44844743693Sstephh 					lp->prev->next = lp->next;
44944743693Sstephh 					lp->next->prev = lp->prev;
45044743693Sstephh 					np = lp;
45144743693Sstephh 				}
45244743693Sstephh 			}
45344743693Sstephh 		}
45444743693Sstephh 		if (np) {
45544743693Sstephh 			lp = *list;
45644743693Sstephh 			if (lp) {
45744743693Sstephh 				if (np->max_pct > lp->max_pct) {
45844743693Sstephh 					np->next = lp;
45944743693Sstephh 					np->prev = lp->prev;
46044743693Sstephh 					lp->prev->next = np;
46144743693Sstephh 					lp->prev = np;
46244743693Sstephh 					*list = np;
46344743693Sstephh 					rt = np;
46444743693Sstephh 				} else {
46544743693Sstephh 					lp = lp->next;
46644743693Sstephh 					while (lp != *list &&
46744743693Sstephh 					    np->max_pct < lp->max_pct) {
46844743693Sstephh 						lp = lp->next;
46944743693Sstephh 					}
47044743693Sstephh 					np->next = lp;
47144743693Sstephh 					np->prev = lp->prev;
47244743693Sstephh 					lp->prev->next = np;
47344743693Sstephh 					lp->prev = np;
47444743693Sstephh 				}
47544743693Sstephh 			} else {
47644743693Sstephh 				*list = np;
47744743693Sstephh 				np->next = np;
47844743693Sstephh 				np->prev = np;
47944743693Sstephh 				rt = np;
48044743693Sstephh 			}
48144743693Sstephh 		}
48244743693Sstephh 		np = sp;
48344743693Sstephh 	}
48444743693Sstephh 	return (rt);
48544743693Sstephh }
48644743693Sstephh 
48744743693Sstephh static name_list_t *
alloc_name_list(char * name,uint8_t pct)48844743693Sstephh alloc_name_list(char *name, uint8_t pct)
48944743693Sstephh {
49044743693Sstephh 	name_list_t *nlp;
49144743693Sstephh 
49244743693Sstephh 	nlp = malloc(sizeof (*nlp));
49344743693Sstephh 	nlp->name = strdup(name);
49444743693Sstephh 	nlp->pct = pct;
49544743693Sstephh 	nlp->max_pct = pct;
49644743693Sstephh 	nlp->count = 1;
49744743693Sstephh 	nlp->next = nlp;
49844743693Sstephh 	nlp->prev = nlp;
49944743693Sstephh 	nlp->status = 0;
500d4c0a8c5Sstephh 	nlp->label = NULL;
50144743693Sstephh 	return (nlp);
50244743693Sstephh }
50344743693Sstephh 
50444743693Sstephh static status_record_t *
new_record_init(uurec_t * uurec_p,char * msgid,name_list_t * class,name_list_t * fru,name_list_t * asru,name_list_t * resource,name_list_t * serial,boolean_t not_suppressed,hostid_t * hostid,boolean_t injected)50544743693Sstephh new_record_init(uurec_t *uurec_p, char *msgid, name_list_t *class,
50644743693Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
507b6955755SRobert Johnston     name_list_t *serial, boolean_t not_suppressed,
508540db9a9SStephen Hanson     hostid_t *hostid, boolean_t injected)
50944743693Sstephh {
51044743693Sstephh 	status_record_t *status_rec_p;
51144743693Sstephh 
51244743693Sstephh 	status_rec_p = (status_record_t *)malloc(sizeof (status_record_t));
51344743693Sstephh 	status_rec_p->nrecs = 1;
51444743693Sstephh 	status_rec_p->host = hostid;
51544743693Sstephh 	status_rec_p->uurec = uurec_p;
51644743693Sstephh 	uurec_p->next = NULL;
51744743693Sstephh 	uurec_p->prev = NULL;
51844743693Sstephh 	uurec_p->asru = asru;
519b6955755SRobert Johnston 	if ((status_rec_p->severity = fmd_msg_getitem_id(fmadm_msghdl, NULL,
520b6955755SRobert Johnston 	    msgid, FMD_MSG_ITEM_SEVERITY)) == NULL)
521b6955755SRobert Johnston 		status_rec_p->severity = strdup("unknown");
52244743693Sstephh 	status_rec_p->class = class;
52344743693Sstephh 	status_rec_p->fru = fru;
52444743693Sstephh 	status_rec_p->asru = asru;
52544743693Sstephh 	status_rec_p->resource = resource;
52644743693Sstephh 	status_rec_p->serial = serial;
52744743693Sstephh 	status_rec_p->msgid = strdup(msgid);
52844743693Sstephh 	status_rec_p->not_suppressed = not_suppressed;
529540db9a9SStephen Hanson 	status_rec_p->injected = injected;
53044743693Sstephh 	return (status_rec_p);
53144743693Sstephh }
53244743693Sstephh 
53344743693Sstephh /*
53444743693Sstephh  * add record to given list maintaining order higher priority first.
53544743693Sstephh  */
53644743693Sstephh static void
add_rec_list(status_record_t * status_rec_p,sr_list_t ** list_pp)53744743693Sstephh add_rec_list(status_record_t *status_rec_p, sr_list_t **list_pp)
53844743693Sstephh {
53944743693Sstephh 	sr_list_t *tp, *np, *sp;
54044743693Sstephh 	int order;
54144743693Sstephh 	uint64_t sec;
5427c478bd9Sstevel@tonic-gate 
54344743693Sstephh 	np = malloc(sizeof (sr_list_t));
54444743693Sstephh 	np->status_record = status_rec_p;
54544743693Sstephh 	sec = status_rec_p->uurec->sec;
54644743693Sstephh 	if ((sp = *list_pp) == NULL) {
54744743693Sstephh 		*list_pp = np;
54844743693Sstephh 		np->next = np;
54944743693Sstephh 		np->prev = np;
55044743693Sstephh 	} else {
55144743693Sstephh 		/* insert new record in front of lower priority */
55244743693Sstephh 		tp = sp;
55344743693Sstephh 		order = cmp_priority(status_rec_p->severity,
55444743693Sstephh 		    sp->status_record->severity, sec,
55544743693Sstephh 		    tp->status_record->uurec->sec, 0, 0);
55644743693Sstephh 		if (order > 0) {
55744743693Sstephh 			*list_pp = np;
55844743693Sstephh 		} else {
55944743693Sstephh 			tp = sp->next;
56044743693Sstephh 			while (tp != sp &&
56144743693Sstephh 			    cmp_priority(status_rec_p->severity,
56244743693Sstephh 			    tp->status_record->severity, sec,
56344743693Sstephh 			    tp->status_record->uurec->sec, 0, 0)) {
56444743693Sstephh 				tp = tp->next;
56544743693Sstephh 			}
56644743693Sstephh 		}
56744743693Sstephh 		np->next = tp;
56844743693Sstephh 		np->prev = tp->prev;
56944743693Sstephh 		tp->prev->next = np;
57044743693Sstephh 		tp->prev = np;
57144743693Sstephh 	}
57244743693Sstephh }
57344743693Sstephh 
57444743693Sstephh static void
add_resource(status_record_t * status_rec_p,resource_list_t ** rp,resource_list_t * np)57544743693Sstephh add_resource(status_record_t *status_rec_p, resource_list_t **rp,
57644743693Sstephh     resource_list_t *np)
57744743693Sstephh {
57844743693Sstephh 	int order;
57944743693Sstephh 	uint64_t sec;
58044743693Sstephh 	resource_list_t *sp, *tp;
58144743693Sstephh 	status_record_t *srp;
58244743693Sstephh 	char *severity = status_rec_p->severity;
58344743693Sstephh 
58444743693Sstephh 	add_rec_list(status_rec_p, &np->status_rec_list);
58544743693Sstephh 	if ((sp = *rp) == NULL) {
58644743693Sstephh 		np->next = np;
58744743693Sstephh 		np->prev = np;
58844743693Sstephh 		*rp = np;
58944743693Sstephh 	} else {
59044743693Sstephh 		/*
59144743693Sstephh 		 * insert new record in front of lower priority
59244743693Sstephh 		 */
59344743693Sstephh 		tp = sp->next;
59444743693Sstephh 		srp = sp->status_rec_list->status_record;
59544743693Sstephh 		sec = status_rec_p->uurec->sec;
59644743693Sstephh 		order = cmp_priority(severity, srp->severity, sec,
59744743693Sstephh 		    srp->uurec->sec, np->max_pct, sp->max_pct);
59844743693Sstephh 		if (order > 0) {
59944743693Sstephh 			*rp = np;
60044743693Sstephh 		} else {
60144743693Sstephh 			srp = tp->status_rec_list->status_record;
60244743693Sstephh 			while (tp != sp &&
60344743693Sstephh 			    cmp_priority(severity, srp->severity, sec,
60444743693Sstephh 			    srp->uurec->sec, np->max_pct, sp->max_pct) < 0) {
60544743693Sstephh 				tp = tp->next;
60644743693Sstephh 				srp = tp->status_rec_list->status_record;
60744743693Sstephh 			}
60844743693Sstephh 		}
60944743693Sstephh 		np->next = tp;
61044743693Sstephh 		np->prev = tp->prev;
61144743693Sstephh 		tp->prev->next = np;
61244743693Sstephh 		tp->prev = np;
61344743693Sstephh 	}
61444743693Sstephh }
61544743693Sstephh 
61644743693Sstephh static void
add_resource_list(status_record_t * status_rec_p,name_list_t * fp,resource_list_t ** rpp)61744743693Sstephh add_resource_list(status_record_t *status_rec_p, name_list_t *fp,
61844743693Sstephh     resource_list_t **rpp)
61944743693Sstephh {
62044743693Sstephh 	int order;
62144743693Sstephh 	resource_list_t *np, *end;
62244743693Sstephh 	status_record_t *srp;
62344743693Sstephh 
62444743693Sstephh 	np = *rpp;
62544743693Sstephh 	end = np;
62644743693Sstephh 	while (np) {
62744743693Sstephh 		if (strcmp(fp->name, np->resource) == 0) {
62844743693Sstephh 			np->not_suppressed |= status_rec_p->not_suppressed;
629540db9a9SStephen Hanson 			np->injected |= status_rec_p->injected;
63044743693Sstephh 			srp = np->status_rec_list->status_record;
63144743693Sstephh 			order = cmp_priority(status_rec_p->severity,
63244743693Sstephh 			    srp->severity, status_rec_p->uurec->sec,
63344743693Sstephh 			    srp->uurec->sec, fp->max_pct, np->max_pct);
63444743693Sstephh 			if (order > 0 && np != end) {
63544743693Sstephh 				/*
63644743693Sstephh 				 * remove from list and add again using
63744743693Sstephh 				 * new priority
63844743693Sstephh 				 */
63944743693Sstephh 				np->prev->next = np->next;
64044743693Sstephh 				np->next->prev = np->prev;
64144743693Sstephh 				add_resource(status_rec_p,
64244743693Sstephh 				    rpp, np);
64344743693Sstephh 			} else {
64444743693Sstephh 				add_rec_list(status_rec_p,
64544743693Sstephh 				    &np->status_rec_list);
64644743693Sstephh 			}
64744743693Sstephh 			break;
64844743693Sstephh 		}
64944743693Sstephh 		np = np->next;
65044743693Sstephh 		if (np == end) {
65144743693Sstephh 			np = NULL;
65244743693Sstephh 			break;
65344743693Sstephh 		}
65444743693Sstephh 	}
65544743693Sstephh 	if (np == NULL) {
65644743693Sstephh 		np = malloc(sizeof (resource_list_t));
65744743693Sstephh 		np->resource = fp->name;
65844743693Sstephh 		np->not_suppressed = status_rec_p->not_suppressed;
659540db9a9SStephen Hanson 		np->injected = status_rec_p->injected;
66044743693Sstephh 		np->status_rec_list = NULL;
66144743693Sstephh 		np->max_pct = fp->max_pct;
66244743693Sstephh 		add_resource(status_rec_p, rpp, np);
66344743693Sstephh 	}
66444743693Sstephh }
66544743693Sstephh 
66644743693Sstephh static void
add_list(status_record_t * status_rec_p,name_list_t * listp,resource_list_t ** glistp)66744743693Sstephh add_list(status_record_t *status_rec_p, name_list_t *listp,
66844743693Sstephh     resource_list_t **glistp)
6697c478bd9Sstevel@tonic-gate {
67044743693Sstephh 	name_list_t *fp, *end;
67144743693Sstephh 
67244743693Sstephh 	fp = listp;
67344743693Sstephh 	end = fp;
67444743693Sstephh 	while (fp) {
67544743693Sstephh 		add_resource_list(status_rec_p, fp, glistp);
67644743693Sstephh 		fp = fp->next;
67744743693Sstephh 		if (fp == end)
67844743693Sstephh 			break;
67944743693Sstephh 	}
68044743693Sstephh }
68144743693Sstephh 
68244743693Sstephh /*
68344743693Sstephh  * add record to rec, fru and asru lists.
68444743693Sstephh  */
68544743693Sstephh static void
catalog_new_record(uurec_t * uurec_p,char * msgid,name_list_t * class,name_list_t * fru,name_list_t * asru,name_list_t * resource,name_list_t * serial,boolean_t not_suppressed,hostid_t * hostid,boolean_t injected,boolean_t dummy_fru)68644743693Sstephh catalog_new_record(uurec_t *uurec_p, char *msgid, name_list_t *class,
68744743693Sstephh     name_list_t *fru, name_list_t *asru, name_list_t *resource,
688b6955755SRobert Johnston     name_list_t *serial, boolean_t not_suppressed,
689705e9f42SStephen Hanson     hostid_t *hostid, boolean_t injected, boolean_t dummy_fru)
69044743693Sstephh {
69144743693Sstephh 	status_record_t *status_rec_p;
69244743693Sstephh 
69344743693Sstephh 	status_rec_p = new_record_init(uurec_p, msgid, class, fru, asru,
694540db9a9SStephen Hanson 	    resource, serial, not_suppressed, hostid, injected);
69544743693Sstephh 	add_rec_list(status_rec_p, &status_rec_list);
696705e9f42SStephen Hanson 	if (status_rec_p->fru && !dummy_fru)
69744743693Sstephh 		add_list(status_rec_p, status_rec_p->fru, &status_fru_list);
69844743693Sstephh 	if (status_rec_p->asru)
69944743693Sstephh 		add_list(status_rec_p, status_rec_p->asru, &status_asru_list);
70044743693Sstephh }
70144743693Sstephh 
70244743693Sstephh static void
get_serial_no(nvlist_t * nvl,name_list_t ** serial_p,uint8_t pct)70344743693Sstephh get_serial_no(nvlist_t *nvl, name_list_t **serial_p, uint8_t pct)
70444743693Sstephh {
70544743693Sstephh 	char *name;
70644743693Sstephh 	char *serial = NULL;
70744743693Sstephh 	char **lserial = NULL;
70844743693Sstephh 	uint64_t serint;
70944743693Sstephh 	name_list_t *nlp;
71044743693Sstephh 	int j;
71144743693Sstephh 	uint_t nelem;
71244743693Sstephh 	char buf[64];
71344743693Sstephh 
71444743693Sstephh 	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) == 0) {
71544743693Sstephh 		if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) {
71644743693Sstephh 			if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID,
71744743693Sstephh 			    &serint) == 0) {
71844743693Sstephh 				(void) snprintf(buf, sizeof (buf), "%llX",
71944743693Sstephh 				    serint);
72044743693Sstephh 				nlp = alloc_name_list(buf, pct);
72144743693Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
72244743693Sstephh 			}
72344743693Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) {
72444743693Sstephh 			if (nvlist_lookup_string_array(nvl,
72544743693Sstephh 			    FM_FMRI_MEM_SERIAL_ID, &lserial, &nelem) == 0) {
72644743693Sstephh 				nlp = alloc_name_list(lserial[0], pct);
72744743693Sstephh 				for (j = 1; j < nelem; j++) {
72844743693Sstephh 					name_list_t *n1lp;
72944743693Sstephh 					n1lp = alloc_name_list(lserial[j], pct);
73044743693Sstephh 					(void) merge_name_list(&nlp, n1lp, 1);
73144743693Sstephh 				}
73244743693Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
73344743693Sstephh 			}
73444743693Sstephh 		} else if (strcmp(name, FM_FMRI_SCHEME_HC) == 0) {
73544743693Sstephh 			if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID,
73644743693Sstephh 			    &serial) == 0) {
73744743693Sstephh 				nlp = alloc_name_list(serial, pct);
73844743693Sstephh 				(void) merge_name_list(serial_p, nlp, 1);
73944743693Sstephh 			}
74044743693Sstephh 		}
74144743693Sstephh 	}
74244743693Sstephh }
74344743693Sstephh 
74444743693Sstephh static void
extract_record_info(nvlist_t * nvl,name_list_t ** class_p,name_list_t ** fru_p,name_list_t ** serial_p,name_list_t ** resource_p,name_list_t ** asru_p,boolean_t * dummy_fru,uint8_t status)74544743693Sstephh extract_record_info(nvlist_t *nvl, name_list_t **class_p,
746705e9f42SStephen Hanson     name_list_t **fru_p, name_list_t **serial_p, name_list_t **resource_p,
747705e9f42SStephen Hanson     name_list_t **asru_p, boolean_t *dummy_fru, uint8_t status)
74844743693Sstephh {
74944743693Sstephh 	nvlist_t *lfru, *lasru, *rsrc;
75044743693Sstephh 	name_list_t *nlp;
75144743693Sstephh 	char *name;
75244743693Sstephh 	uint8_t lpct = 0;
75344743693Sstephh 	char *lclass = NULL;
754d4c0a8c5Sstephh 	char *label;
75544743693Sstephh 
75644743693Sstephh 	(void) nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &lpct);
75744743693Sstephh 	if (nvlist_lookup_string(nvl, FM_CLASS, &lclass) == 0) {
75844743693Sstephh 		nlp = alloc_name_list(lclass, lpct);
75944743693Sstephh 		(void) merge_name_list(class_p, nlp, 1);
76044743693Sstephh 	}
76144743693Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &lfru) == 0) {
76244743693Sstephh 		name = get_nvl2str_topo(lfru);
76344743693Sstephh 		if (name != NULL) {
76444743693Sstephh 			nlp = alloc_name_list(name, lpct);
76525c6ff4bSstephh 			nlp->status = status & ~(FM_SUSPECT_UNUSABLE |
76625c6ff4bSstephh 			    FM_SUSPECT_DEGRADED);
76744743693Sstephh 			free(name);
768d4c0a8c5Sstephh 			if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION,
769d4c0a8c5Sstephh 			    &label) == 0)
770d4c0a8c5Sstephh 				nlp->label = strdup(label);
77144743693Sstephh 			(void) merge_name_list(fru_p, nlp, 1);
77244743693Sstephh 		}
77344743693Sstephh 		get_serial_no(lfru, serial_p, lpct);
7745750ef5cSStephen Hanson 	} else if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) != 0) {
7755750ef5cSStephen Hanson 		/*
7765750ef5cSStephen Hanson 		 * No FRU or resource. But we want to display the repair status
7775750ef5cSStephen Hanson 		 * somehow, so create a dummy FRU field.
7785750ef5cSStephen Hanson 		 */
779705e9f42SStephen Hanson 		*dummy_fru = 1;
7805750ef5cSStephen Hanson 		nlp = alloc_name_list(dgettext("FMD", "None"), lpct);
7815750ef5cSStephen Hanson 		nlp->status = status & ~(FM_SUSPECT_UNUSABLE |
7825750ef5cSStephen Hanson 		    FM_SUSPECT_DEGRADED);
7835750ef5cSStephen Hanson 		(void) merge_name_list(fru_p, nlp, 1);
78444743693Sstephh 	}
78544743693Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &lasru) == 0) {
78644743693Sstephh 		name = get_nvl2str_topo(lasru);
78744743693Sstephh 		if (name != NULL) {
78844743693Sstephh 			nlp = alloc_name_list(name, lpct);
78925c6ff4bSstephh 			nlp->status = status & ~(FM_SUSPECT_NOT_PRESENT |
79025c6ff4bSstephh 			    FM_SUSPECT_REPAIRED | FM_SUSPECT_REPLACED |
79125c6ff4bSstephh 			    FM_SUSPECT_ACQUITTED);
79244743693Sstephh 			free(name);
79344743693Sstephh 			(void) merge_name_list(asru_p, nlp, 1);
79444743693Sstephh 		}
79544743693Sstephh 		get_serial_no(lasru, serial_p, lpct);
79644743693Sstephh 	}
79744743693Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
79844743693Sstephh 		name = get_nvl2str_topo(rsrc);
79944743693Sstephh 		if (name != NULL) {
80044743693Sstephh 			nlp = alloc_name_list(name, lpct);
801567cc2e6Sstephh 			nlp->status = status;
80244743693Sstephh 			free(name);
8038e7248e5SStephen Hanson 			if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION,
8048e7248e5SStephen Hanson 			    &label) == 0)
8058e7248e5SStephen Hanson 				nlp->label = strdup(label);
80644743693Sstephh 			(void) merge_name_list(resource_p, nlp, 1);
80744743693Sstephh 		}
80844743693Sstephh 	}
80944743693Sstephh }
81044743693Sstephh 
81144743693Sstephh static void
add_fault_record_to_catalog(nvlist_t * nvl,uint64_t sec,char * uuid)812b6955755SRobert Johnston add_fault_record_to_catalog(nvlist_t *nvl, uint64_t sec, char *uuid)
81344743693Sstephh {
81444743693Sstephh 	char *msgid = "-";
81544743693Sstephh 	uint_t i, size = 0;
81644743693Sstephh 	name_list_t *class = NULL, *resource = NULL;
81744743693Sstephh 	name_list_t *asru = NULL, *fru = NULL, *serial = NULL;
81844743693Sstephh 	nvlist_t **nva;
81944743693Sstephh 	uint8_t *ba;
82044743693Sstephh 	uurec_t *uurec_p;
82144743693Sstephh 	hostid_t *host;
82244743693Sstephh 	boolean_t not_suppressed = 1;
82344743693Sstephh 	boolean_t any_present = 0;
824540db9a9SStephen Hanson 	boolean_t injected = 0;
825705e9f42SStephen Hanson 	boolean_t dummy_fru = 0;
82644743693Sstephh 
82744743693Sstephh 	(void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &msgid);
82844743693Sstephh 	(void) nvlist_lookup_uint32(nvl, FM_SUSPECT_FAULT_SZ, &size);
82944743693Sstephh 	(void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_MESSAGE,
83044743693Sstephh 	    &not_suppressed);
831540db9a9SStephen Hanson 	(void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED, &injected);
83244743693Sstephh 
83344743693Sstephh 	if (size != 0) {
83444743693Sstephh 		(void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
83544743693Sstephh 		    &nva, &size);
83644743693Sstephh 		(void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS,
83744743693Sstephh 		    &ba, &size);
83844743693Sstephh 		for (i = 0; i < size; i++) {
83944743693Sstephh 			extract_record_info(nva[i], &class, &fru, &serial,
840705e9f42SStephen Hanson 			    &resource, &asru, &dummy_fru, ba[i]);
84144743693Sstephh 			if (!(ba[i] & FM_SUSPECT_NOT_PRESENT) &&
84244743693Sstephh 			    (ba[i] & FM_SUSPECT_FAULTY))
84344743693Sstephh 				any_present = 1;
84444743693Sstephh 		}
84544743693Sstephh 		/*
84644743693Sstephh 		 * also suppress if no resources present
84744743693Sstephh 		 */
84844743693Sstephh 		if (any_present == 0)
84944743693Sstephh 			not_suppressed = 0;
85044743693Sstephh 	}
85144743693Sstephh 
85244743693Sstephh 	uurec_p = (uurec_t *)malloc(sizeof (uurec_t));
85344743693Sstephh 	uurec_p->uuid = strdup(uuid);
85444743693Sstephh 	uurec_p->sec = sec;
85544743693Sstephh 	uurec_p->ari_uuid_list = NULL;
85688045cffSRobert Johnston 	uurec_p->event = NULL;
85788045cffSRobert Johnston 	(void) nvlist_dup(nvl, &uurec_p->event, 0);
85844743693Sstephh 	host = find_hostid(nvl);
8595750ef5cSStephen Hanson 	catalog_new_record(uurec_p, msgid, class, fru, asru,
860705e9f42SStephen Hanson 	    resource, serial, not_suppressed, host, injected, dummy_fru);
86144743693Sstephh }
86244743693Sstephh 
86344743693Sstephh static void
update_asru_state_in_catalog(const char * uuid,const char * ari_uuid)86444743693Sstephh update_asru_state_in_catalog(const char *uuid, const char *ari_uuid)
86544743693Sstephh {
86644743693Sstephh 	sr_list_t *srp;
86744743693Sstephh 	uurec_t *uurp;
86844743693Sstephh 	ari_list_t *ari_list;
86944743693Sstephh 
87044743693Sstephh 	srp = status_rec_list;
87144743693Sstephh 	if (srp) {
87244743693Sstephh 		for (;;) {
87344743693Sstephh 			uurp = srp->status_record->uurec;
87444743693Sstephh 			while (uurp) {
87544743693Sstephh 				if (strcmp(uuid, uurp->uuid) == 0) {
87644743693Sstephh 					ari_list = (ari_list_t *)
87744743693Sstephh 					    malloc(sizeof (ari_list_t));
87844743693Sstephh 					ari_list->ari_uuid = strdup(ari_uuid);
87944743693Sstephh 					ari_list->next = uurp->ari_uuid_list;
88044743693Sstephh 					uurp->ari_uuid_list = ari_list;
88144743693Sstephh 					return;
88244743693Sstephh 				}
88344743693Sstephh 				uurp = uurp->next;
88444743693Sstephh 			}
88544743693Sstephh 			if (srp->next == status_rec_list)
88644743693Sstephh 				break;
88744743693Sstephh 			srp = srp->next;
88844743693Sstephh 		}
88944743693Sstephh 	}
89044743693Sstephh }
89144743693Sstephh 
89244743693Sstephh static void
print_line(char * label,char * buf)89344743693Sstephh print_line(char *label, char *buf)
89444743693Sstephh {
89544743693Sstephh 	char *cp, *ep, *wp;
89644743693Sstephh 	char c;
89744743693Sstephh 	int i;
89844743693Sstephh 	int lsz;
89944743693Sstephh 	char *padding;
90044743693Sstephh 
90144743693Sstephh 	lsz = strlen(label);
90244743693Sstephh 	padding = malloc(lsz + 1);
90344743693Sstephh 	for (i = 0; i < lsz; i++)
90444743693Sstephh 		padding[i] = ' ';
90544743693Sstephh 	padding[i] = 0;
90644743693Sstephh 	cp = buf;
90744743693Sstephh 	ep = buf;
90844743693Sstephh 	c = *ep;
90944743693Sstephh 	(void) printf("\n");
91044743693Sstephh 	while (c) {
91144743693Sstephh 		i = lsz;
91244743693Sstephh 		wp = NULL;
913940f2f58SToomas Soome 		while ((c = *ep) != '\0' && (wp == NULL || i < 80)) {
91444743693Sstephh 			if (c == ' ')
91544743693Sstephh 				wp = ep;
91644743693Sstephh 			else if (c == '\n') {
91744743693Sstephh 				i = 0;
91844743693Sstephh 				*ep = 0;
91944743693Sstephh 				do {
92044743693Sstephh 					ep++;
921940f2f58SToomas Soome 				} while ((c = *ep) != '\0' && c == ' ');
92244743693Sstephh 				break;
92344743693Sstephh 			}
92444743693Sstephh 			ep++;
92544743693Sstephh 			i++;
92644743693Sstephh 		}
92744743693Sstephh 		if (i >= 80 && wp) {
92844743693Sstephh 			*wp = 0;
92944743693Sstephh 			ep = wp + 1;
93044743693Sstephh 			c = *ep;
93144743693Sstephh 		}
93244743693Sstephh 		(void) printf("%s%s\n", label, cp);
93344743693Sstephh 		cp = ep;
93444743693Sstephh 		label = padding;
93544743693Sstephh 	}
93644743693Sstephh 	free(padding);
93744743693Sstephh }
93844743693Sstephh 
93944743693Sstephh static void
print_dict_info_line(nvlist_t * e,fmd_msg_item_t what,const char * linehdr)94088045cffSRobert Johnston print_dict_info_line(nvlist_t *e, fmd_msg_item_t what, const char *linehdr)
94144743693Sstephh {
94288045cffSRobert Johnston 	char *cp = fmd_msg_getitem_nv(fmadm_msghdl, NULL, e, what);
94344743693Sstephh 
94444743693Sstephh 	if (cp) {
945b6955755SRobert Johnston 		print_line(dgettext("FMD", linehdr), cp);
946b6955755SRobert Johnston 		free(cp);
94744743693Sstephh 	}
94844743693Sstephh }
94944743693Sstephh 
950b6955755SRobert Johnston static void
print_dict_info(nvlist_t * nvl)95188045cffSRobert Johnston print_dict_info(nvlist_t *nvl)
952b6955755SRobert Johnston {
95388045cffSRobert Johnston 	print_dict_info_line(nvl, FMD_MSG_ITEM_DESC, "Description : ");
95488045cffSRobert Johnston 	print_dict_info_line(nvl, FMD_MSG_ITEM_RESPONSE, "Response    : ");
95588045cffSRobert Johnston 	print_dict_info_line(nvl, FMD_MSG_ITEM_IMPACT, "Impact      : ");
95688045cffSRobert Johnston 	print_dict_info_line(nvl, FMD_MSG_ITEM_ACTION, "Action      : ");
957b6955755SRobert Johnston }
958b6955755SRobert Johnston 
95944743693Sstephh static void
print_name(name_list_t * list,char * padding,int * np,int pct,int full)960e58a33b6SStephen Hanson print_name(name_list_t *list, char *padding, int *np, int pct, int full)
96144743693Sstephh {
962e58a33b6SStephen Hanson 	char *name;
96344743693Sstephh 
96444743693Sstephh 	name = list->name;
9658e7248e5SStephen Hanson 	if (list->label) {
9668e7248e5SStephen Hanson 		(void) printf("%s \"%s\" (%s)", padding, list->label, name);
9678e7248e5SStephen Hanson 		*np += 1;
96844743693Sstephh 	} else {
96944743693Sstephh 		(void) printf("%s %s", padding, name);
97044743693Sstephh 		*np += 1;
97144743693Sstephh 	}
97244743693Sstephh 	if (list->pct && pct > 0 && pct < 100) {
97344743693Sstephh 		if (list->count > 1) {
97444743693Sstephh 			if (full) {
97544743693Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
97644743693Sstephh 				    dgettext("FMD", "max"),
97744743693Sstephh 				    list->max_pct);
97844743693Sstephh 			} else {
97944743693Sstephh 				(void) printf(" %s %d%%\n",
98044743693Sstephh 				    dgettext("FMD", "max"),
98144743693Sstephh 				    list->max_pct);
98244743693Sstephh 			}
98344743693Sstephh 		} else {
98444743693Sstephh 			(void) printf(" %d%%\n", list->pct);
98544743693Sstephh 		}
98644743693Sstephh 	} else {
98744743693Sstephh 		(void) printf("\n");
98844743693Sstephh 	}
98944743693Sstephh }
99044743693Sstephh 
99144743693Sstephh static void
print_asru_status(int status,char * label)99244743693Sstephh print_asru_status(int status, char *label)
99344743693Sstephh {
99444743693Sstephh 	char *msg = NULL;
99544743693Sstephh 
99644743693Sstephh 	switch (status) {
99744743693Sstephh 	case 0:
99844743693Sstephh 		msg = dgettext("FMD", "ok and in service");
99944743693Sstephh 		break;
100025c6ff4bSstephh 	case FM_SUSPECT_DEGRADED:
100125c6ff4bSstephh 		msg = dgettext("FMD", "service degraded, "
100225c6ff4bSstephh 		    "but associated components no longer faulty");
100325c6ff4bSstephh 		break;
100425c6ff4bSstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED:
100525c6ff4bSstephh 		msg = dgettext("FMD", "faulted but still "
100625c6ff4bSstephh 		    "providing degraded service");
100725c6ff4bSstephh 		break;
100844743693Sstephh 	case FM_SUSPECT_FAULTY:
100925c6ff4bSstephh 		msg = dgettext("FMD", "faulted but still in service");
101044743693Sstephh 		break;
101144743693Sstephh 	case FM_SUSPECT_UNUSABLE:
101225c6ff4bSstephh 		msg = dgettext("FMD", "out of service, "
101325c6ff4bSstephh 		    "but associated components no longer faulty");
101444743693Sstephh 		break;
101544743693Sstephh 	case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
101644743693Sstephh 		msg = dgettext("FMD", "faulted and taken out of service");
101744743693Sstephh 		break;
10187c478bd9Sstevel@tonic-gate 	default:
101944743693Sstephh 		break;
102044743693Sstephh 	}
102144743693Sstephh 	if (msg) {
102244743693Sstephh 		(void) printf("%s     %s\n", label, msg);
10237c478bd9Sstevel@tonic-gate 	}
10247c478bd9Sstevel@tonic-gate }
10257c478bd9Sstevel@tonic-gate 
1026567cc2e6Sstephh static void
print_fru_status(int status,char * label)1027567cc2e6Sstephh print_fru_status(int status, char *label)
1028567cc2e6Sstephh {
1029567cc2e6Sstephh 	char *msg = NULL;
1030567cc2e6Sstephh 
1031567cc2e6Sstephh 	if (status & FM_SUSPECT_NOT_PRESENT)
1032567cc2e6Sstephh 		msg = dgettext("FMD", "not present");
1033567cc2e6Sstephh 	else if (status & FM_SUSPECT_FAULTY)
1034567cc2e6Sstephh 		msg = dgettext("FMD", "faulty");
103525c6ff4bSstephh 	else if (status & FM_SUSPECT_REPLACED)
103625c6ff4bSstephh 		msg = dgettext("FMD", "replaced");
103725c6ff4bSstephh 	else if (status & FM_SUSPECT_REPAIRED)
103825c6ff4bSstephh 		msg = dgettext("FMD", "repair attempted");
103925c6ff4bSstephh 	else if (status & FM_SUSPECT_ACQUITTED)
104025c6ff4bSstephh 		msg = dgettext("FMD", "acquitted");
1041567cc2e6Sstephh 	else
104225c6ff4bSstephh 		msg = dgettext("FMD", "removed");
1043567cc2e6Sstephh 	(void) printf("%s     %s\n", label, msg);
1044567cc2e6Sstephh }
1045567cc2e6Sstephh 
1046cbf75e67SStephen Hanson static void
print_rsrc_status(int status,char * label)1047cbf75e67SStephen Hanson print_rsrc_status(int status, char *label)
1048cbf75e67SStephen Hanson {
1049cbf75e67SStephen Hanson 	char *msg = "";
1050cbf75e67SStephen Hanson 
1051cbf75e67SStephen Hanson 	if (status & FM_SUSPECT_NOT_PRESENT)
1052cbf75e67SStephen Hanson 		msg = dgettext("FMD", "not present");
1053cbf75e67SStephen Hanson 	else if (status & FM_SUSPECT_FAULTY) {
1054cbf75e67SStephen Hanson 		if (status & FM_SUSPECT_DEGRADED)
1055cbf75e67SStephen Hanson 			msg = dgettext("FMD",
1056cbf75e67SStephen Hanson 			    "faulted but still providing degraded service");
1057cbf75e67SStephen Hanson 		else if (status & FM_SUSPECT_UNUSABLE)
1058cbf75e67SStephen Hanson 			msg = dgettext("FMD",
1059cbf75e67SStephen Hanson 			    "faulted and taken out of service");
1060cbf75e67SStephen Hanson 		else
1061cbf75e67SStephen Hanson 			msg = dgettext("FMD", "faulted but still in service");
1062cbf75e67SStephen Hanson 	} else if (status & FM_SUSPECT_REPLACED)
1063cbf75e67SStephen Hanson 		msg = dgettext("FMD", "replaced");
1064cbf75e67SStephen Hanson 	else if (status & FM_SUSPECT_REPAIRED)
1065cbf75e67SStephen Hanson 		msg = dgettext("FMD", "repair attempted");
1066cbf75e67SStephen Hanson 	else if (status & FM_SUSPECT_ACQUITTED)
1067cbf75e67SStephen Hanson 		msg = dgettext("FMD", "acquitted");
1068cbf75e67SStephen Hanson 	else
1069cbf75e67SStephen Hanson 		msg = dgettext("FMD", "removed");
1070cbf75e67SStephen Hanson 	(void) printf("%s     %s\n", label, msg);
1071cbf75e67SStephen Hanson }
1072cbf75e67SStephen Hanson 
107344743693Sstephh static void
print_name_list(name_list_t * list,char * label,int limit,int pct,void (func1)(int,char *),int full)1074e58a33b6SStephen Hanson print_name_list(name_list_t *list, char *label,
107544743693Sstephh     int limit, int pct, void (func1)(int, char *), int full)
107644743693Sstephh {
1077e58a33b6SStephen Hanson 	char *name;
107844743693Sstephh 	char *padding;
107944743693Sstephh 	int i, j, l, n;
108044743693Sstephh 	name_list_t *end = list;
10817c478bd9Sstevel@tonic-gate 
108244743693Sstephh 	l = strlen(label);
108344743693Sstephh 	padding = malloc(l + 1);
108444743693Sstephh 	for (i = 0; i < l; i++)
108544743693Sstephh 		padding[i] = ' ';
108644743693Sstephh 	padding[l] = 0;
108744743693Sstephh 	(void) printf("%s", label);
108844743693Sstephh 	name = list->name;
10898e7248e5SStephen Hanson 	if (list->label)
1090d4c0a8c5Sstephh 		(void) printf(" \"%s\" (%s)", list->label, name);
1091e58a33b6SStephen Hanson 	else
10928e7248e5SStephen Hanson 		(void) printf(" %s", name);
109344743693Sstephh 	if (list->pct && pct > 0 && pct < 100) {
109444743693Sstephh 		if (list->count > 1) {
109544743693Sstephh 			if (full) {
109644743693Sstephh 				(void) printf(" %d @ %s %d%%\n", list->count,
109744743693Sstephh 				    dgettext("FMD", "max"), list->max_pct);
109844743693Sstephh 			} else {
109944743693Sstephh 				(void) printf(" %s %d%%\n",
110044743693Sstephh 				    dgettext("FMD", "max"), list->max_pct);
110144743693Sstephh 			}
110244743693Sstephh 		} else {
110344743693Sstephh 			(void) printf(" %d%%\n", list->pct);
110444743693Sstephh 		}
110544743693Sstephh 	} else {
110644743693Sstephh 		(void) printf("\n");
110744743693Sstephh 	}
110844743693Sstephh 	if (func1)
110944743693Sstephh 		func1(list->status, padding);
111044743693Sstephh 	n = 1;
111144743693Sstephh 	j = 0;
111244743693Sstephh 	while ((list = list->next) != end) {
111344743693Sstephh 		if (limit == 0 || n < limit) {
1114e58a33b6SStephen Hanson 			print_name(list, padding, &n, pct, full);
111544743693Sstephh 			if (func1)
111644743693Sstephh 				func1(list->status, padding);
111744743693Sstephh 		} else
111844743693Sstephh 			j++;
111944743693Sstephh 	}
112044743693Sstephh 	if (j == 1) {
1121e58a33b6SStephen Hanson 		print_name(list->prev, padding, &n, pct, full);
112244743693Sstephh 	} else if (j > 1) {
112344743693Sstephh 		(void) printf("%s... %d %s\n", padding, j,
112444743693Sstephh 		    dgettext("FMD", "more entries suppressed,"
112544743693Sstephh 		    " use -v option for full list"));
112644743693Sstephh 	}
112744743693Sstephh 	free(padding);
112844743693Sstephh }
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate static int
asru_same_status(name_list_t * list)113144743693Sstephh asru_same_status(name_list_t *list)
11327c478bd9Sstevel@tonic-gate {
113344743693Sstephh 	name_list_t *end = list;
113444743693Sstephh 	int status = list->status;
113544743693Sstephh 
113644743693Sstephh 	while ((list = list->next) != end) {
113744743693Sstephh 		if (status == -1) {
113844743693Sstephh 			status = list->status;
113944743693Sstephh 			continue;
114044743693Sstephh 		}
114144743693Sstephh 		if (list->status != -1 && status != list->status) {
114244743693Sstephh 			status = -1;
114344743693Sstephh 			break;
114444743693Sstephh 		}
11457c478bd9Sstevel@tonic-gate 	}
114644743693Sstephh 	return (status);
114744743693Sstephh }
114844743693Sstephh 
114944743693Sstephh static int
serial_in_fru(name_list_t * fru,name_list_t * serial)115044743693Sstephh serial_in_fru(name_list_t *fru, name_list_t *serial)
115144743693Sstephh {
115244743693Sstephh 	name_list_t *sp = serial;
115344743693Sstephh 	name_list_t *fp;
115444743693Sstephh 	int nserial = 0;
115544743693Sstephh 	int found = 0;
115644743693Sstephh 	char buf[128];
11577c478bd9Sstevel@tonic-gate 
115844743693Sstephh 	while (sp) {
115944743693Sstephh 		fp = fru;
116044743693Sstephh 		nserial++;
116144743693Sstephh 		(void) snprintf(buf, sizeof (buf), "serial=%s", sp->name);
116244743693Sstephh 		buf[sizeof (buf) - 1] = 0;
116344743693Sstephh 		while (fp) {
116444743693Sstephh 			if (strstr(fp->name, buf) != NULL) {
116544743693Sstephh 				found++;
116644743693Sstephh 				break;
116744743693Sstephh 			}
116844743693Sstephh 			fp = fp->next;
116944743693Sstephh 			if (fp == fru)
117044743693Sstephh 				break;
117144743693Sstephh 		}
117244743693Sstephh 		sp = sp->next;
117344743693Sstephh 		if (sp == serial)
117444743693Sstephh 			break;
117544743693Sstephh 	}
117644743693Sstephh 	return (found == nserial ? 1 : 0);
117744743693Sstephh }
117844743693Sstephh 
117944743693Sstephh static void
print_sup_record(status_record_t * srp,int opt_i,int full)118044743693Sstephh print_sup_record(status_record_t *srp, int opt_i, int full)
118144743693Sstephh {
118244743693Sstephh 	char buf[32];
118344743693Sstephh 	uurec_t *uurp = srp->uurec;
118444743693Sstephh 	int n, j, k, max;
118544743693Sstephh 	int status;
118644743693Sstephh 	ari_list_t *ari_list;
118744743693Sstephh 
118844743693Sstephh 	n = 0;
118944743693Sstephh 	max = max_fault;
119044743693Sstephh 	if (max < 0) {
119144743693Sstephh 		max = 0;
119244743693Sstephh 	}
119344743693Sstephh 	j = max / 2;
119444743693Sstephh 	max -= j;
119544743693Sstephh 	k = srp->nrecs - max;
119644743693Sstephh 	while ((uurp = uurp->next) != NULL) {
119744743693Sstephh 		if (full || n < j || n >= k || max_fault == 0 ||
119844743693Sstephh 		    srp->nrecs == max_fault+1) {
119944743693Sstephh 			if (opt_i) {
120044743693Sstephh 				ari_list = uurp->ari_uuid_list;
120144743693Sstephh 				while (ari_list) {
120244743693Sstephh 					(void) printf("%-15s %s\n",
120344743693Sstephh 					    format_date(buf, sizeof (buf),
120444743693Sstephh 					    uurp->sec), ari_list->ari_uuid);
120544743693Sstephh 					ari_list = ari_list->next;
120644743693Sstephh 				}
120744743693Sstephh 			} else {
120844743693Sstephh 				(void) printf("%-15s %s\n",
120944743693Sstephh 				    format_date(buf, sizeof (buf), uurp->sec),
121044743693Sstephh 				    uurp->uuid);
121144743693Sstephh 			}
121244743693Sstephh 		} else if (n == j)
121344743693Sstephh 			(void) printf("... %d %s\n", srp->nrecs - max_fault,
121444743693Sstephh 			    dgettext("FMD", "more entries suppressed"));
121544743693Sstephh 		n++;
121644743693Sstephh 	}
121744743693Sstephh 	(void) printf("\n");
1218*7adb68a6SHans Rosenfeld 	if (srp->host) {
1219*7adb68a6SHans Rosenfeld 		(void) printf("%s %s", dgettext("FMD", "Host        :"),
1220*7adb68a6SHans Rosenfeld 		    srp->host->server);
1221*7adb68a6SHans Rosenfeld 		if (srp->host->domain)
1222*7adb68a6SHans Rosenfeld 			(void) printf("\t%s %s", dgettext("FMD",
1223*7adb68a6SHans Rosenfeld 			    "Domain      :"), srp->host->domain);
1224*7adb68a6SHans Rosenfeld 		(void) printf("\n%s %s", dgettext("FMD", "Platform    :"),
1225*7adb68a6SHans Rosenfeld 		    srp->host->platform);
1226*7adb68a6SHans Rosenfeld 		(void) printf("\t%s %s", dgettext("FMD", "Chassis_id  :"),
1227*7adb68a6SHans Rosenfeld 		    srp->host->chassis ? srp->host->chassis : "");
1228*7adb68a6SHans Rosenfeld 		(void) printf("\n%s %s\n\n", dgettext("FMD", "Product_sn  :"),
1229*7adb68a6SHans Rosenfeld 		    srp->host->product_sn ? srp->host->product_sn : "");
1230*7adb68a6SHans Rosenfeld 	}
123144743693Sstephh 	if (srp->class)
123244743693Sstephh 		print_name_list(srp->class,
1233e58a33b6SStephen Hanson 		    dgettext("FMD", "Fault class :"), 0, srp->class->pct,
123444743693Sstephh 		    NULL, full);
123544743693Sstephh 	if (srp->asru) {
123644743693Sstephh 		status = asru_same_status(srp->asru);
123744743693Sstephh 		if (status != -1) {
123844743693Sstephh 			print_name_list(srp->asru,
1239e58a33b6SStephen Hanson 			    dgettext("FMD", "Affects     :"),
124044743693Sstephh 			    full ? 0 : max_display, 0, NULL, full);
124144743693Sstephh 			print_asru_status(status, "             ");
124244743693Sstephh 		} else
124344743693Sstephh 			print_name_list(srp->asru,
1244e58a33b6SStephen Hanson 			    dgettext("FMD", "Affects     :"),
124544743693Sstephh 			    full ? 0 : max_display, 0, print_asru_status, full);
124644743693Sstephh 	}
1247cbf75e67SStephen Hanson 	if (full || srp->fru == NULL || srp->asru == NULL) {
124844743693Sstephh 		if (srp->resource) {
12495750ef5cSStephen Hanson 			status = asru_same_status(srp->resource);
12505750ef5cSStephen Hanson 			if (status != -1) {
12515750ef5cSStephen Hanson 				print_name_list(srp->resource,
1252e58a33b6SStephen Hanson 				    dgettext("FMD", "Problem in  :"),
12535750ef5cSStephen Hanson 				    full ? 0 : max_display, 0, NULL, full);
12545750ef5cSStephen Hanson 				print_rsrc_status(status, "             ");
12555750ef5cSStephen Hanson 			} else
12565750ef5cSStephen Hanson 				print_name_list(srp->resource,
12575750ef5cSStephen Hanson 				    dgettext("FMD", "Problem in  :"),
1258e58a33b6SStephen Hanson 				    full ? 0 : max_display, 0,
12595750ef5cSStephen Hanson 				    print_rsrc_status, full);
126044743693Sstephh 		}
126144743693Sstephh 	}
126244743693Sstephh 	if (srp->fru) {
1263567cc2e6Sstephh 		status = asru_same_status(srp->fru);
1264567cc2e6Sstephh 		if (status != -1) {
1265567cc2e6Sstephh 			print_name_list(srp->fru, dgettext("FMD",
1266e58a33b6SStephen Hanson 			    "FRU         :"), 0,
1267567cc2e6Sstephh 			    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
1268567cc2e6Sstephh 			    NULL, full);
1269567cc2e6Sstephh 			print_fru_status(status, "             ");
1270567cc2e6Sstephh 		} else
1271567cc2e6Sstephh 			print_name_list(srp->fru, dgettext("FMD",
1272e58a33b6SStephen Hanson 			    "FRU         :"), 0,
1273567cc2e6Sstephh 			    srp->fru->pct == 100 ? 100 : srp->fru->max_pct,
1274567cc2e6Sstephh 			    print_fru_status, full);
127544743693Sstephh 	}
127644743693Sstephh 	if (srp->serial && !serial_in_fru(srp->fru, srp->serial) &&
127744743693Sstephh 	    !serial_in_fru(srp->asru, srp->serial)) {
127844743693Sstephh 		print_name_list(srp->serial, dgettext("FMD", "Serial ID.  :"),
1279e58a33b6SStephen Hanson 		    0, 0, NULL, full);
128044743693Sstephh 	}
128188045cffSRobert Johnston 	print_dict_info(srp->uurec->event);
128244743693Sstephh 	(void) printf("\n");
128344743693Sstephh }
128444743693Sstephh 
128544743693Sstephh static void
print_status_record(status_record_t * srp,int summary,int opt_i,int full)128644743693Sstephh print_status_record(status_record_t *srp, int summary, int opt_i, int full)
128744743693Sstephh {
128844743693Sstephh 	char buf[32];
128944743693Sstephh 	uurec_t *uurp = srp->uurec;
129044743693Sstephh 	static int header = 0;
129144743693Sstephh 	char *head;
129244743693Sstephh 	ari_list_t *ari_list;
129344743693Sstephh 
129444743693Sstephh 	if (!summary || !header) {
129544743693Sstephh 		if (opt_i) {
129644743693Sstephh 			head = "--------------- "
129744743693Sstephh 			    "------------------------------------  "
129844743693Sstephh 			    "-------------- ---------\n"
129944743693Sstephh 			    "TIME            CACHE-ID"
130044743693Sstephh 			    "                              MSG-ID"
130144743693Sstephh 			    "         SEVERITY\n--------------- "
130244743693Sstephh 			    "------------------------------------ "
130344743693Sstephh 			    " -------------- ---------";
130444743693Sstephh 		} else {
130544743693Sstephh 			head = "--------------- "
130644743693Sstephh 			    "------------------------------------  "
130744743693Sstephh 			    "-------------- ---------\n"
130844743693Sstephh 			    "TIME            EVENT-ID"
130944743693Sstephh 			    "                              MSG-ID"
131044743693Sstephh 			    "         SEVERITY\n--------------- "
131144743693Sstephh 			    "------------------------------------ "
131244743693Sstephh 			    " -------------- ---------";
131344743693Sstephh 		}
131444743693Sstephh 		(void) printf("%s\n", dgettext("FMD", head));
131544743693Sstephh 		header = 1;
131644743693Sstephh 	}
131744743693Sstephh 	if (opt_i) {
131844743693Sstephh 		ari_list = uurp->ari_uuid_list;
131944743693Sstephh 		while (ari_list) {
1320540db9a9SStephen Hanson 			(void) printf("%-15s %-37s %-14s %-9s %s\n",
132144743693Sstephh 			    format_date(buf, sizeof (buf), uurp->sec),
1322540db9a9SStephen Hanson 			    ari_list->ari_uuid, srp->msgid, srp->severity,
1323540db9a9SStephen Hanson 			    srp->injected ? dgettext("FMD", "injected") : "");
132444743693Sstephh 			ari_list = ari_list->next;
132544743693Sstephh 		}
132644743693Sstephh 	} else {
1327540db9a9SStephen Hanson 		(void) printf("%-15s %-37s %-14s %-9s %s\n",
132844743693Sstephh 		    format_date(buf, sizeof (buf), uurp->sec),
1329540db9a9SStephen Hanson 		    uurp->uuid, srp->msgid, srp->severity,
1330540db9a9SStephen Hanson 		    srp->injected ? dgettext("FMD", "injected") : "");
133144743693Sstephh 	}
133244743693Sstephh 
133344743693Sstephh 	if (!summary)
133444743693Sstephh 		print_sup_record(srp, opt_i, full);
133544743693Sstephh }
133644743693Sstephh 
133744743693Sstephh static void
print_catalog(int summary,int opt_a,int full,int opt_i,int page_feed)133844743693Sstephh print_catalog(int summary, int opt_a, int full, int opt_i, int page_feed)
133944743693Sstephh {
134044743693Sstephh 	status_record_t *srp;
134144743693Sstephh 	sr_list_t *slp;
134244743693Sstephh 
134344743693Sstephh 	slp = status_rec_list;
134444743693Sstephh 	if (slp) {
134544743693Sstephh 		for (;;) {
134644743693Sstephh 			srp = slp->status_record;
134744743693Sstephh 			if (opt_a || srp->not_suppressed) {
134844743693Sstephh 				if (page_feed)
134944743693Sstephh 					(void) printf("\f\n");
135044743693Sstephh 				print_status_record(srp, summary, opt_i, full);
135144743693Sstephh 			}
135244743693Sstephh 			if (slp->next == status_rec_list)
135344743693Sstephh 				break;
135444743693Sstephh 			slp = slp->next;
135544743693Sstephh 		}
135644743693Sstephh 	}
135744743693Sstephh }
135844743693Sstephh 
135944743693Sstephh static name_list_t *
find_fru(status_record_t * srp,char * resource)136044743693Sstephh find_fru(status_record_t *srp, char *resource)
136144743693Sstephh {
136244743693Sstephh 	name_list_t *rt = NULL;
136344743693Sstephh 	name_list_t *fru = srp->fru;
136444743693Sstephh 
136544743693Sstephh 	while (fru) {
136644743693Sstephh 		if (strcmp(resource, fru->name) == 0) {
136744743693Sstephh 			rt = fru;
136844743693Sstephh 			break;
136944743693Sstephh 		}
137044743693Sstephh 		fru = fru->next;
137144743693Sstephh 		if (fru == srp->fru)
137244743693Sstephh 			break;
137344743693Sstephh 	}
137444743693Sstephh 	return (rt);
137544743693Sstephh }
137644743693Sstephh 
137744743693Sstephh static void
print_fru_line(name_list_t * fru,char * uuid)137844743693Sstephh print_fru_line(name_list_t *fru, char *uuid)
137944743693Sstephh {
138044743693Sstephh 	if (fru->pct == 100) {
138144743693Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
138244743693Sstephh 		    dgettext("FMD", "suspects in this FRU total certainty"),
138344743693Sstephh 		    100);
138444743693Sstephh 	} else {
138544743693Sstephh 		(void) printf("%s %d %s %d%%\n", uuid, fru->count,
138644743693Sstephh 		    dgettext("FMD", "suspects in this FRU max certainty"),
138744743693Sstephh 		    fru->max_pct);
138844743693Sstephh 	}
138944743693Sstephh }
139044743693Sstephh 
139144743693Sstephh static void
print_fru(int summary,int opt_a,int opt_i,int page_feed)139244743693Sstephh print_fru(int summary, int opt_a, int opt_i, int page_feed)
139344743693Sstephh {
139444743693Sstephh 	resource_list_t *tp = status_fru_list;
139544743693Sstephh 	status_record_t *srp;
139644743693Sstephh 	sr_list_t *slp, *end;
139744743693Sstephh 	uurec_t *uurp;
139844743693Sstephh 	name_list_t *fru;
1399567cc2e6Sstephh 	int status;
140044743693Sstephh 	ari_list_t *ari_list;
140144743693Sstephh 
140244743693Sstephh 	while (tp) {
140344743693Sstephh 		if (opt_a || tp->not_suppressed) {
140444743693Sstephh 			if (page_feed)
140544743693Sstephh 				(void) printf("\f\n");
140644743693Sstephh 			if (!summary)
140744743693Sstephh 				(void) printf("-----------------------------"
140844743693Sstephh 				    "---------------------------------------"
140944743693Sstephh 				    "----------\n");
1410d4c0a8c5Sstephh 			slp = tp->status_rec_list;
1411d4c0a8c5Sstephh 			end = slp;
1412d4c0a8c5Sstephh 			do {
1413d4c0a8c5Sstephh 				srp = slp->status_record;
1414705e9f42SStephen Hanson 				if (!srp->not_suppressed) {
1415705e9f42SStephen Hanson 					slp = slp->next;
1416705e9f42SStephen Hanson 					continue;
1417705e9f42SStephen Hanson 				}
1418d4c0a8c5Sstephh 				fru = find_fru(srp, tp->resource);
1419d4c0a8c5Sstephh 				if (fru) {
1420d4c0a8c5Sstephh 					if (fru->label)
1421567cc2e6Sstephh 						(void) printf("\"%s\" (%s) ",
1422d4c0a8c5Sstephh 						    fru->label, fru->name);
1423e58a33b6SStephen Hanson 					else
1424567cc2e6Sstephh 						(void) printf("%s ",
1425d4c0a8c5Sstephh 						    fru->name);
1426d4c0a8c5Sstephh 					break;
1427d4c0a8c5Sstephh 				}
1428d4c0a8c5Sstephh 				slp = slp->next;
1429d4c0a8c5Sstephh 			} while (slp != end);
1430d4c0a8c5Sstephh 
1431567cc2e6Sstephh 			slp = tp->status_rec_list;
1432567cc2e6Sstephh 			end = slp;
1433567cc2e6Sstephh 			status = 0;
1434567cc2e6Sstephh 			do {
1435567cc2e6Sstephh 				srp = slp->status_record;
1436705e9f42SStephen Hanson 				if (!srp->not_suppressed) {
1437705e9f42SStephen Hanson 					slp = slp->next;
1438705e9f42SStephen Hanson 					continue;
1439705e9f42SStephen Hanson 				}
1440567cc2e6Sstephh 				fru = srp->fru;
1441567cc2e6Sstephh 				while (fru) {
1442567cc2e6Sstephh 					if (strcmp(tp->resource,
1443567cc2e6Sstephh 					    fru->name) == 0)
1444567cc2e6Sstephh 						status |= fru->status;
1445567cc2e6Sstephh 					fru = fru->next;
1446567cc2e6Sstephh 					if (fru == srp->fru)
1447567cc2e6Sstephh 						break;
1448567cc2e6Sstephh 				}
1449567cc2e6Sstephh 				slp = slp->next;
1450567cc2e6Sstephh 			} while (slp != end);
1451567cc2e6Sstephh 			if (status & FM_SUSPECT_NOT_PRESENT)
1452540db9a9SStephen Hanson 				(void) printf(dgettext("FMD", "not present"));
1453567cc2e6Sstephh 			else if (status & FM_SUSPECT_FAULTY)
1454540db9a9SStephen Hanson 				(void) printf(dgettext("FMD", "faulty"));
145525c6ff4bSstephh 			else if (status & FM_SUSPECT_REPLACED)
1456540db9a9SStephen Hanson 				(void) printf(dgettext("FMD", "replaced"));
145725c6ff4bSstephh 			else if (status & FM_SUSPECT_REPAIRED)
145825c6ff4bSstephh 				(void) printf(dgettext("FMD",
1459540db9a9SStephen Hanson 				    "repair attempted"));
146025c6ff4bSstephh 			else if (status & FM_SUSPECT_ACQUITTED)
1461540db9a9SStephen Hanson 				(void) printf(dgettext("FMD", "acquitted"));
1462567cc2e6Sstephh 			else
1463540db9a9SStephen Hanson 				(void) printf(dgettext("FMD", "removed"));
1464540db9a9SStephen Hanson 
1465540db9a9SStephen Hanson 			if (tp->injected)
1466540db9a9SStephen Hanson 				(void) printf(dgettext("FMD", " injected\n"));
1467540db9a9SStephen Hanson 			else
1468540db9a9SStephen Hanson 				(void) printf(dgettext("FMD", "\n"));
1469567cc2e6Sstephh 
147044743693Sstephh 			slp = tp->status_rec_list;
147144743693Sstephh 			end = slp;
147244743693Sstephh 			do {
147344743693Sstephh 				srp = slp->status_record;
1474705e9f42SStephen Hanson 				if (!srp->not_suppressed) {
1475705e9f42SStephen Hanson 					slp = slp->next;
1476705e9f42SStephen Hanson 					continue;
1477705e9f42SStephen Hanson 				}
147844743693Sstephh 				uurp = srp->uurec;
147944743693Sstephh 				fru = find_fru(srp, tp->resource);
148044743693Sstephh 				if (fru) {
148144743693Sstephh 					if (opt_i) {
148244743693Sstephh 						ari_list = uurp->ari_uuid_list;
148344743693Sstephh 						while (ari_list) {
148444743693Sstephh 							print_fru_line(fru,
148544743693Sstephh 							    ari_list->ari_uuid);
148644743693Sstephh 							ari_list =
148744743693Sstephh 							    ari_list->next;
148844743693Sstephh 						}
148944743693Sstephh 					} else {
149044743693Sstephh 						print_fru_line(fru, uurp->uuid);
149144743693Sstephh 					}
149244743693Sstephh 				}
149344743693Sstephh 				slp = slp->next;
149444743693Sstephh 			} while (slp != end);
149544743693Sstephh 			if (!summary) {
149644743693Sstephh 				slp = tp->status_rec_list;
149744743693Sstephh 				end = slp;
149844743693Sstephh 				do {
1499705e9f42SStephen Hanson 					srp = slp->status_record;
1500705e9f42SStephen Hanson 					if (!srp->not_suppressed) {
1501705e9f42SStephen Hanson 						slp = slp->next;
1502705e9f42SStephen Hanson 						continue;
1503705e9f42SStephen Hanson 					}
1504705e9f42SStephen Hanson 					if (srp->serial &&
1505705e9f42SStephen Hanson 					    !serial_in_fru(srp->fru,
1506705e9f42SStephen Hanson 					    srp->serial)) {
1507705e9f42SStephen Hanson 						print_name_list(srp->serial,
1508705e9f42SStephen Hanson 						    dgettext("FMD",
1509705e9f42SStephen Hanson 						    "Serial ID.  :"),
1510e58a33b6SStephen Hanson 						    0, 0, NULL, 1);
1511705e9f42SStephen Hanson 						break;
151244743693Sstephh 					}
151344743693Sstephh 					slp = slp->next;
151444743693Sstephh 				} while (slp != end);
151544743693Sstephh 			}
151644743693Sstephh 		}
151744743693Sstephh 		tp = tp->next;
151844743693Sstephh 		if (tp == status_fru_list)
151944743693Sstephh 			break;
152044743693Sstephh 	}
152144743693Sstephh }
152244743693Sstephh 
152344743693Sstephh static void
print_asru(int opt_a)152444743693Sstephh print_asru(int opt_a)
152544743693Sstephh {
152644743693Sstephh 	resource_list_t *tp = status_asru_list;
152744743693Sstephh 	status_record_t *srp;
152844743693Sstephh 	sr_list_t *slp, *end;
152944743693Sstephh 	char *msg;
153044743693Sstephh 	int status;
153144743693Sstephh 	name_list_t *asru;
153244743693Sstephh 
153344743693Sstephh 	while (tp) {
153444743693Sstephh 		if (opt_a || tp->not_suppressed) {
153544743693Sstephh 			status = 0;
153644743693Sstephh 			slp = tp->status_rec_list;
153744743693Sstephh 			end = slp;
153844743693Sstephh 			do {
153944743693Sstephh 				srp = slp->status_record;
1540705e9f42SStephen Hanson 				if (!srp->not_suppressed) {
1541705e9f42SStephen Hanson 					slp = slp->next;
1542705e9f42SStephen Hanson 					continue;
1543705e9f42SStephen Hanson 				}
154444743693Sstephh 				asru = srp->asru;
154544743693Sstephh 				while (asru) {
154644743693Sstephh 					if (strcmp(tp->resource,
154744743693Sstephh 					    asru->name) == 0)
154844743693Sstephh 						status |= asru->status;
154944743693Sstephh 					asru = asru->next;
155044743693Sstephh 					if (asru == srp->asru)
155144743693Sstephh 						break;
155244743693Sstephh 				}
155344743693Sstephh 				slp = slp->next;
155444743693Sstephh 			} while (slp != end);
155544743693Sstephh 			switch (status) {
155644743693Sstephh 			case 0:
155744743693Sstephh 				msg = dgettext("FMD", "ok");
155844743693Sstephh 				break;
155925c6ff4bSstephh 			case FM_SUSPECT_DEGRADED:
156025c6ff4bSstephh 				msg = dgettext("FMD", "degraded");
156125c6ff4bSstephh 				break;
156225c6ff4bSstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED:
156325c6ff4bSstephh 				msg = dgettext("FMD", "degraded");
156425c6ff4bSstephh 				break;
156544743693Sstephh 			case FM_SUSPECT_FAULTY:
156644743693Sstephh 				msg = dgettext("FMD", "degraded");
156744743693Sstephh 				break;
156844743693Sstephh 			case FM_SUSPECT_UNUSABLE:
156944743693Sstephh 				msg = dgettext("FMD", "unknown");
157044743693Sstephh 				break;
157144743693Sstephh 			case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE:
157244743693Sstephh 				msg = dgettext("FMD", "faulted");
157344743693Sstephh 				break;
157444743693Sstephh 			default:
157544743693Sstephh 				msg = "";
157644743693Sstephh 				break;
157744743693Sstephh 			}
1578540db9a9SStephen Hanson 			(void) printf("%-69s %s", tp->resource, msg);
1579540db9a9SStephen Hanson 			if (tp->injected)
1580540db9a9SStephen Hanson 				(void) printf(dgettext("FMD", " injected\n"));
1581540db9a9SStephen Hanson 			else
1582540db9a9SStephen Hanson 				(void) printf(dgettext("FMD", "\n"));
158344743693Sstephh 		}
158444743693Sstephh 		tp = tp->next;
158544743693Sstephh 		if (tp == status_asru_list)
158644743693Sstephh 			break;
158744743693Sstephh 	}
158844743693Sstephh }
158944743693Sstephh 
159044743693Sstephh static int
uuid_in_list(char * uuid,uurec_select_t * uurecp)159144743693Sstephh uuid_in_list(char *uuid, uurec_select_t *uurecp)
159244743693Sstephh {
159344743693Sstephh 	while (uurecp) {
159444743693Sstephh 		if (strcmp(uuid, uurecp->uuid) == 0)
159544743693Sstephh 			return (1);
159644743693Sstephh 		uurecp = uurecp->next;
159744743693Sstephh 	}
15987c478bd9Sstevel@tonic-gate 	return (0);
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate static int
dfault_rec(const fmd_adm_caseinfo_t * acp,void * arg)160244743693Sstephh dfault_rec(const fmd_adm_caseinfo_t *acp, void *arg)
16037c478bd9Sstevel@tonic-gate {
160444743693Sstephh 	int64_t *diag_time;
160544743693Sstephh 	uint_t nelem;
160644743693Sstephh 	int rt = 0;
160744743693Sstephh 	char *uuid = "-";
160844743693Sstephh 	uurec_select_t *uurecp = (uurec_select_t *)arg;
160944743693Sstephh 
161044743693Sstephh 	if (nvlist_lookup_int64_array(acp->aci_event, FM_SUSPECT_DIAG_TIME,
161144743693Sstephh 	    &diag_time, &nelem) == 0 && nelem >= 2) {
161244743693Sstephh 		(void) nvlist_lookup_string(acp->aci_event, FM_SUSPECT_UUID,
161344743693Sstephh 		    &uuid);
161444743693Sstephh 		if (uurecp == NULL || uuid_in_list(uuid, uurecp))
161544743693Sstephh 			add_fault_record_to_catalog(acp->aci_event, *diag_time,
1616b6955755SRobert Johnston 			    uuid);
161744743693Sstephh 	} else {
161844743693Sstephh 		rt = -1;
16197c478bd9Sstevel@tonic-gate 	}
162044743693Sstephh 	return (rt);
162144743693Sstephh }
16227c478bd9Sstevel@tonic-gate 
162344743693Sstephh /*ARGSUSED*/
162444743693Sstephh static int
dstatus_rec(const fmd_adm_rsrcinfo_t * ari,void * unused)162544743693Sstephh dstatus_rec(const fmd_adm_rsrcinfo_t *ari, void *unused)
162644743693Sstephh {
162744743693Sstephh 	update_asru_state_in_catalog(ari->ari_case, ari->ari_uuid);
16287c478bd9Sstevel@tonic-gate 	return (0);
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate 
163144743693Sstephh static int
get_cases_from_fmd(fmd_adm_t * adm,uurec_select_t * uurecp,int opt_i)163244743693Sstephh get_cases_from_fmd(fmd_adm_t *adm, uurec_select_t *uurecp, int opt_i)
163344743693Sstephh {
163444743693Sstephh 	int rt = FMADM_EXIT_SUCCESS;
163544743693Sstephh 
163644743693Sstephh 	/*
163788045cffSRobert Johnston 	 * These calls may fail with Protocol error if message payload is
163888045cffSRobert Johnston 	 * too big
163944743693Sstephh 	 */
164044743693Sstephh 	if (fmd_adm_case_iter(adm, NULL, dfault_rec, uurecp) != 0)
164144743693Sstephh 		die("failed to get case list from fmd");
164244743693Sstephh 	if (opt_i && fmd_adm_rsrc_iter(adm, 1, dstatus_rec, NULL) != 0)
164344743693Sstephh 		die("failed to get case status from fmd");
164444743693Sstephh 	return (rt);
164544743693Sstephh }
164644743693Sstephh 
164744743693Sstephh /*
164844743693Sstephh  * fmadm faulty command
164944743693Sstephh  *
165044743693Sstephh  *	-a		show hidden fault records
165144743693Sstephh  *	-f		show faulty fru's
165244743693Sstephh  *	-g		force grouping of similar faults on the same fru
165344743693Sstephh  *	-n		number of fault records to display
165444743693Sstephh  *	-p		pipe output through pager
165544743693Sstephh  *	-r		show faulty asru's
165644743693Sstephh  *	-s		print summary of first fault
165744743693Sstephh  *	-u		print listed uuid's only
165844743693Sstephh  *	-v		full output
165944743693Sstephh  */
166044743693Sstephh 
16617c478bd9Sstevel@tonic-gate int
cmd_faulty(fmd_adm_t * adm,int argc,char * argv[])16627c478bd9Sstevel@tonic-gate cmd_faulty(fmd_adm_t *adm, int argc, char *argv[])
16637c478bd9Sstevel@tonic-gate {
166444743693Sstephh 	int opt_a = 0, opt_v = 0, opt_p = 0, opt_s = 0, opt_r = 0, opt_f = 0;
166544743693Sstephh 	int opt_i = 0;
166644743693Sstephh 	char *pager;
166744743693Sstephh 	FILE *fp;
166844743693Sstephh 	int rt, c, stat;
166944743693Sstephh 	uurec_select_t *tp;
167044743693Sstephh 	uurec_select_t *uurecp = NULL;
16717c478bd9Sstevel@tonic-gate 
167244743693Sstephh 	while ((c = getopt(argc, argv, "afgin:prsu:v")) != EOF) {
16737c478bd9Sstevel@tonic-gate 		switch (c) {
16747c478bd9Sstevel@tonic-gate 		case 'a':
16757c478bd9Sstevel@tonic-gate 			opt_a++;
16767c478bd9Sstevel@tonic-gate 			break;
167744743693Sstephh 		case 'f':
167844743693Sstephh 			opt_f++;
167944743693Sstephh 			break;
168044743693Sstephh 		case 'g':
168144743693Sstephh 			opt_g++;
168244743693Sstephh 			break;
16837c478bd9Sstevel@tonic-gate 		case 'i':
168444743693Sstephh 			opt_i++;
168544743693Sstephh 			break;
168644743693Sstephh 		case 'n':
168744743693Sstephh 			max_fault = atoi(optarg);
168844743693Sstephh 			break;
168944743693Sstephh 		case 'p':
169044743693Sstephh 			opt_p++;
169144743693Sstephh 			break;
169244743693Sstephh 		case 'r':
169344743693Sstephh 			opt_r++;
169444743693Sstephh 			break;
169544743693Sstephh 		case 's':
169644743693Sstephh 			opt_s++;
169744743693Sstephh 			break;
169844743693Sstephh 		case 'u':
169944743693Sstephh 			tp = (uurec_select_t *)malloc(sizeof (uurec_select_t));
170044743693Sstephh 			tp->uuid = optarg;
170144743693Sstephh 			tp->next = uurecp;
170244743693Sstephh 			uurecp = tp;
170344743693Sstephh 			opt_a = 1;
170444743693Sstephh 			break;
170544743693Sstephh 		case 'v':
170644743693Sstephh 			opt_v++;
17077c478bd9Sstevel@tonic-gate 			break;
17087c478bd9Sstevel@tonic-gate 		default:
17097c478bd9Sstevel@tonic-gate 			return (FMADM_EXIT_USAGE);
17107c478bd9Sstevel@tonic-gate 		}
17117c478bd9Sstevel@tonic-gate 	}
17127c478bd9Sstevel@tonic-gate 	if (optind < argc)
17137c478bd9Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
17147c478bd9Sstevel@tonic-gate 
1715b6955755SRobert Johnston 	if ((fmadm_msghdl = fmd_msg_init(NULL, FMD_MSG_VERSION)) == NULL)
1716b6955755SRobert Johnston 		return (FMADM_EXIT_ERROR);
171744743693Sstephh 	rt = get_cases_from_fmd(adm, uurecp, opt_i);
171844743693Sstephh 	if (opt_p) {
171944743693Sstephh 		if ((pager = getenv("PAGER")) == NULL)
172044743693Sstephh 			pager = "/usr/bin/more";
172144743693Sstephh 		fp = popen(pager, "w");
172244743693Sstephh 		if (fp == NULL) {
172344743693Sstephh 			rt = FMADM_EXIT_ERROR;
172444743693Sstephh 			opt_p = 0;
172544743693Sstephh 		} else {
1726888e0559SRobert Johnston 			(void) dup2(fileno(fp), 1);
172744743693Sstephh 			setbuf(stdout, NULL);
172844743693Sstephh 			(void) fclose(fp);
172944743693Sstephh 		}
173044743693Sstephh 	}
173144743693Sstephh 	max_display = max_fault;
173244743693Sstephh 	if (opt_f)
173344743693Sstephh 		print_fru(opt_s, opt_a, opt_i, opt_p && !opt_s);
173444743693Sstephh 	if (opt_r)
173544743693Sstephh 		print_asru(opt_a);
173644743693Sstephh 	if (opt_f == 0 && opt_r == 0)
173744743693Sstephh 		print_catalog(opt_s, opt_a, opt_v, opt_i, opt_p && !opt_s);
1738b6955755SRobert Johnston 	fmd_msg_fini(fmadm_msghdl);
1739e58a33b6SStephen Hanson 	if (topo_handle)
1740e58a33b6SStephen Hanson 		topo_close(topo_handle);
174144743693Sstephh 	if (opt_p) {
174244743693Sstephh 		(void) fclose(stdout);
174344743693Sstephh 		(void) wait(&stat);
174444743693Sstephh 	}
174544743693Sstephh 	return (rt);
17467c478bd9Sstevel@tonic-gate }
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate int
cmd_flush(fmd_adm_t * adm,int argc,char * argv[])17497c478bd9Sstevel@tonic-gate cmd_flush(fmd_adm_t *adm, int argc, char *argv[])
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate 	int i, status = FMADM_EXIT_SUCCESS;
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	if (argc < 2 || (i = getopt(argc, argv, "")) != EOF)
17547c478bd9Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	for (i = 1; i < argc; i++) {
17577c478bd9Sstevel@tonic-gate 		if (fmd_adm_rsrc_flush(adm, argv[i]) != 0) {
17587c478bd9Sstevel@tonic-gate 			warn("failed to flush %s", argv[i]);
17597c478bd9Sstevel@tonic-gate 			status = FMADM_EXIT_ERROR;
17607c478bd9Sstevel@tonic-gate 		} else
17617c478bd9Sstevel@tonic-gate 			note("flushed resource history for %s\n", argv[i]);
17627c478bd9Sstevel@tonic-gate 	}
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	return (status);
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate int
cmd_repair(fmd_adm_t * adm,int argc,char * argv[])17687c478bd9Sstevel@tonic-gate cmd_repair(fmd_adm_t *adm, int argc, char *argv[])
17697c478bd9Sstevel@tonic-gate {
17707c478bd9Sstevel@tonic-gate 	int err;
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 	if (getopt(argc, argv, "") != EOF)
17737c478bd9Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 	if (argc - optind != 1)
17767c478bd9Sstevel@tonic-gate 		return (FMADM_EXIT_USAGE);
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate 	/*
177925c6ff4bSstephh 	 * argument could be a uuid, an fmri (asru, fru or resource)
1780567cc2e6Sstephh 	 * or a label. Try uuid first, If that fails try the others.
17817c478bd9Sstevel@tonic-gate 	 */
1782567cc2e6Sstephh 	err = fmd_adm_case_repair(adm, argv[optind]);
1783567cc2e6Sstephh 	if (err != 0)
178425c6ff4bSstephh 		err = fmd_adm_rsrc_repaired(adm, argv[optind]);
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 	if (err != 0)
17877c478bd9Sstevel@tonic-gate 		die("failed to record repair to %s", argv[optind]);
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 	note("recorded repair to %s\n", argv[optind]);
17907c478bd9Sstevel@tonic-gate 	return (FMADM_EXIT_SUCCESS);
17917c478bd9Sstevel@tonic-gate }
179225c6ff4bSstephh 
179325c6ff4bSstephh int
cmd_repaired(fmd_adm_t * adm,int argc,char * argv[])179425c6ff4bSstephh cmd_repaired(fmd_adm_t *adm, int argc, char *argv[])
179525c6ff4bSstephh {
179625c6ff4bSstephh 	int err;
179725c6ff4bSstephh 
179825c6ff4bSstephh 	if (getopt(argc, argv, "") != EOF)
179925c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
180025c6ff4bSstephh 
180125c6ff4bSstephh 	if (argc - optind != 1)
180225c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
180325c6ff4bSstephh 
180425c6ff4bSstephh 	/*
180525c6ff4bSstephh 	 * argument could be an fmri (asru, fru or resource) or a label.
180625c6ff4bSstephh 	 */
180725c6ff4bSstephh 	err = fmd_adm_rsrc_repaired(adm, argv[optind]);
180825c6ff4bSstephh 	if (err != 0)
180925c6ff4bSstephh 		die("failed to record repair to %s", argv[optind]);
181025c6ff4bSstephh 
181125c6ff4bSstephh 	note("recorded repair to of %s\n", argv[optind]);
181225c6ff4bSstephh 	return (FMADM_EXIT_SUCCESS);
181325c6ff4bSstephh }
181425c6ff4bSstephh 
181525c6ff4bSstephh int
cmd_replaced(fmd_adm_t * adm,int argc,char * argv[])181625c6ff4bSstephh cmd_replaced(fmd_adm_t *adm, int argc, char *argv[])
181725c6ff4bSstephh {
181825c6ff4bSstephh 	int err;
181925c6ff4bSstephh 
182025c6ff4bSstephh 	if (getopt(argc, argv, "") != EOF)
182125c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
182225c6ff4bSstephh 
182325c6ff4bSstephh 	if (argc - optind != 1)
182425c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
182525c6ff4bSstephh 
182625c6ff4bSstephh 	/*
182725c6ff4bSstephh 	 * argument could be an fmri (asru, fru or resource) or a label.
182825c6ff4bSstephh 	 */
182925c6ff4bSstephh 	err = fmd_adm_rsrc_replaced(adm, argv[optind]);
183025c6ff4bSstephh 	if (err != 0)
183125c6ff4bSstephh 		die("failed to record replacement of %s", argv[optind]);
183225c6ff4bSstephh 
183325c6ff4bSstephh 	note("recorded replacement of %s\n", argv[optind]);
183425c6ff4bSstephh 	return (FMADM_EXIT_SUCCESS);
183525c6ff4bSstephh }
183625c6ff4bSstephh 
183725c6ff4bSstephh int
cmd_acquit(fmd_adm_t * adm,int argc,char * argv[])183825c6ff4bSstephh cmd_acquit(fmd_adm_t *adm, int argc, char *argv[])
183925c6ff4bSstephh {
184025c6ff4bSstephh 	int err;
184125c6ff4bSstephh 
184225c6ff4bSstephh 	if (getopt(argc, argv, "") != EOF)
184325c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
184425c6ff4bSstephh 
184525c6ff4bSstephh 	if (argc - optind != 1 && argc - optind != 2)
184625c6ff4bSstephh 		return (FMADM_EXIT_USAGE);
184725c6ff4bSstephh 
184825c6ff4bSstephh 	/*
184925c6ff4bSstephh 	 * argument could be a uuid, an fmri (asru, fru or resource)
185025c6ff4bSstephh 	 * or a label. Or it could be a uuid and an fmri or label.
185125c6ff4bSstephh 	 */
185225c6ff4bSstephh 	if (argc - optind == 2) {
185325c6ff4bSstephh 		err = fmd_adm_rsrc_acquit(adm, argv[optind], argv[optind + 1]);
185425c6ff4bSstephh 		if (err != 0)
185525c6ff4bSstephh 			err = fmd_adm_rsrc_acquit(adm, argv[optind + 1],
185625c6ff4bSstephh 			    argv[optind]);
185725c6ff4bSstephh 	} else {
185825c6ff4bSstephh 		err = fmd_adm_case_acquit(adm, argv[optind]);
185925c6ff4bSstephh 		if (err != 0)
186025c6ff4bSstephh 			err = fmd_adm_rsrc_acquit(adm, argv[optind], "");
186125c6ff4bSstephh 	}
186225c6ff4bSstephh 
186325c6ff4bSstephh 	if (err != 0)
186425c6ff4bSstephh 		die("failed to record acquital of %s", argv[optind]);
186525c6ff4bSstephh 
186625c6ff4bSstephh 	note("recorded acquital of %s\n", argv[optind]);
186725c6ff4bSstephh 	return (FMADM_EXIT_SUCCESS);
186825c6ff4bSstephh }
1869