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