1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2020 Joyent, Inc. 24 */ 25 26 #include <sys/types.h> 27 #include <fmadm.h> 28 #include <errno.h> 29 #include <limits.h> 30 #include <strings.h> 31 #include <stdio.h> 32 #include <unistd.h> 33 #include <sys/wait.h> 34 #include <sys/stat.h> 35 #include <fcntl.h> 36 #include <fm/fmd_log.h> 37 #include <sys/fm/protocol.h> 38 #include <fm/libtopo.h> 39 #include <fm/fmd_adm.h> 40 #include <fm/fmd_msg.h> 41 #include <dlfcn.h> 42 #include <sys/systeminfo.h> 43 #include <sys/utsname.h> 44 #include <libintl.h> 45 #include <locale.h> 46 #include <sys/smbios.h> 47 #include <libdevinfo.h> 48 #include <stdlib.h> 49 #include <stddef.h> 50 51 /* 52 * Fault records are added to catalog by calling add_fault_record_to_catalog() 53 * records are stored in order of importance to the system. 54 * If -g flag is set or not_suppressed is not set and the class fru, fault, 55 * type are the same then details are merged into an existing record, with uuid 56 * records are stored in time order. 57 * For each record information is extracted from nvlist and merged into linked 58 * list each is checked for identical records for which percentage certainty are 59 * added together. 60 * print_catalog() is called to print out catalog and release external resources 61 * 62 * /---------------\ 63 * status_rec_list -> | | -| 64 * \---------------/ 65 * \/ 66 * /---------------\ /-------\ /-------\ 67 * status_fru_list | status_record | -> | uurec | -> | uurec | -| 68 * \/ | | |- | | <- | | 69 * /-------------\ | | \-------/ \-------/ 70 * | | -> | | \/ \/ 71 * \-------------/ | | /-------\ /-------\ 72 * \/ | | -> | asru | -> | asru | 73 * --- | | | | <- | | 74 * | | \-------/ \-------/ 75 * status_asru_list | class | 76 * \/ | resource | /-------\ /-------\ 77 * /-------------\ | fru | -> | list | -> | list | 78 * | | -> | serial | | | <- | | 79 * \-------------/ | | \-------/ \-------/ 80 * \/ \---------------/ 81 * --- \/ /\ 82 * /---------------\ 83 * | status_record | 84 * \---------------/ 85 * 86 * Fmadm faulty takes a number of options which affect the format of the 87 * output displayed. By default, the display reports the FRU and ASRU along 88 * with other information on per-case basis as in the example below. 89 * 90 * --------------- ------------------------------------ -------------- ------- 91 * TIME EVENT-ID MSG-ID SEVERITY 92 * --------------- ------------------------------------ -------------- ------- 93 * Sep 21 10:01:36 d482f935-5c8f-e9ab-9f25-d0aaafec1e6c AMD-8000-2F Major 94 * 95 * Fault class : fault.memory.dimm_sb 96 * Affects : mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0 97 * faulted but still in service 98 * FRU : "CPU 0 DIMM 0" (hc://.../memory-controller=0/dimm=0) 99 * faulty 100 * 101 * Description : The number of errors associated with this memory module has 102 * exceeded acceptable levels. Refer to 103 * http://illumos.org/msg/AMD-8000-2F for more information. 104 * 105 * Response : Pages of memory associated with this memory module are being 106 * removed from service as errors are reported. 107 * 108 * Impact : Total system memory capacity will be reduced as pages are 109 * retired. 110 * 111 * Action : Schedule a repair procedure to replace the affected memory 112 * module. Use fmdump -v -u <EVENT_ID> to identify the module. 113 * 114 * The -v flag is similar, but adds some additonal information such as the 115 * resource. The -s flag is also similar but just gives the top line summary. 116 * All these options (ie without the -f or -r flags) use the print_catalog() 117 * function to do the display. 118 * 119 * The -f flag changes the output so that it appears sorted on a per-fru basis. 120 * The output is somewhat cut down compared to the default output. If -f is 121 * used, then print_fru() is used to print the output. 122 * 123 * ----------------------------------------------------------------------------- 124 * "SLOT 2" (hc://.../hostbridge=3/pciexrc=3/pciexbus=4/pciexdev=0) faulty 125 * 5ca4aeb3-36...f6be-c2e8166dc484 2 suspects in this FRU total certainty 100% 126 * 127 * Description : A problem was detected for a PCI device. 128 * Refer to http://illumos.org/msg/PCI-8000-7J 129 * for more information. 130 * 131 * Response : One or more device instances may be disabled 132 * 133 * Impact : Possible loss of services provided by the device instances 134 * associated with this fault 135 * 136 * Action : Schedule a repair procedure to replace the affected device. 137 * Use fmdump -v -u <EVENT_ID> to identify the device or contact 138 * Sun for support. 139 * 140 * The -r flag changes the output so that it appears sorted on a per-asru basis. 141 * The output is very much cut down compared to the default output, just giving 142 * the asru fmri and state. Here print_asru() is used to print the output. 143 * 144 * mem:///motherboard=0/chip=0/memory-controller=0/dimm=0/rank=0 degraded 145 * 146 * For all fmadm faulty options, the sequence of events is 147 * 148 * 1) Walk through all the cases in the system using fmd_adm_case_iter() and 149 * for each case call dfault_rec(). This will call add_fault_record_to_catalog() 150 * This will extract the data from the nvlist and call catalog_new_record() to 151 * save the data away in various linked lists in the catalogue. 152 * 153 * 2) Once this is done, the data can be supplemented by using 154 * fmd_adm_rsrc_iter(). However this is now only necessary for the -i option. 155 * 156 * 3) Finally print_catalog(), print_fru() or print_asru() are called as 157 * appropriate to display the information from the catalogue sorted in the 158 * requested way. 159 * 160 */ 161 162 typedef struct name_list { 163 struct name_list *next; 164 struct name_list *prev; 165 char *name; 166 uint8_t pct; 167 uint8_t max_pct; 168 ushort_t count; 169 int status; 170 char *label; 171 } name_list_t; 172 173 typedef struct ari_list { 174 char *ari_uuid; 175 struct ari_list *next; 176 } ari_list_t; 177 178 typedef struct uurec { 179 struct uurec *next; 180 struct uurec *prev; 181 char *uuid; 182 ari_list_t *ari_uuid_list; 183 name_list_t *asru; 184 uint64_t sec; 185 nvlist_t *event; 186 } uurec_t; 187 188 typedef struct uurec_select { 189 struct uurec_select *next; 190 char *uuid; 191 } uurec_select_t; 192 193 typedef struct host_id { 194 char *chassis; 195 char *server; 196 char *platform; 197 char *domain; 198 char *product_sn; 199 } hostid_t; 200 201 typedef struct host_id_list { 202 hostid_t hostid; 203 struct host_id_list *next; 204 } host_id_list_t; 205 206 typedef struct status_record { 207 hostid_t *host; 208 int nrecs; 209 uurec_t *uurec; 210 char *severity; /* in C locale */ 211 char *msgid; 212 name_list_t *class; 213 name_list_t *resource; 214 name_list_t *asru; 215 name_list_t *fru; 216 name_list_t *serial; 217 uint8_t not_suppressed; 218 uint8_t injected; 219 } status_record_t; 220 221 typedef struct sr_list { 222 struct sr_list *next; 223 struct sr_list *prev; 224 struct status_record *status_record; 225 } sr_list_t; 226 227 typedef struct resource_list { 228 struct resource_list *next; 229 struct resource_list *prev; 230 sr_list_t *status_rec_list; 231 char *resource; 232 uint8_t not_suppressed; 233 uint8_t injected; 234 uint8_t max_pct; 235 } resource_list_t; 236 237 sr_list_t *status_rec_list; 238 resource_list_t *status_fru_list; 239 resource_list_t *status_asru_list; 240 241 static int max_display; 242 static int max_fault = 0; 243 static topo_hdl_t *topo_handle; 244 static host_id_list_t *host_list; 245 static int n_server; 246 static int opt_g; 247 static fmd_msg_hdl_t *fmadm_msghdl = NULL; /* handle for libfmd_msg calls */ 248 249 static char * 250 format_date(char *buf, size_t len, uint64_t sec) 251 { 252 if (sec > LONG_MAX) { 253 (void) fprintf(stderr, 254 "record time is too large for 32-bit utility\n"); 255 (void) snprintf(buf, len, "0x%llx", sec); 256 } else { 257 time_t tod = (time_t)sec; 258 time_t now = time(NULL); 259 if (tod > now+60 || 260 tod < now - 6L*30L*24L*60L*60L) { /* 6 months ago */ 261 (void) strftime(buf, len, "%b %d %Y ", 262 localtime(&tod)); 263 } else { 264 (void) strftime(buf, len, "%b %d %T", localtime(&tod)); 265 } 266 } 267 268 return (buf); 269 } 270 271 static hostid_t * 272 find_hostid_in_list(char *platform, char *chassis, char *server, char *domain, 273 char *product_sn) 274 { 275 hostid_t *rt = NULL; 276 host_id_list_t *hostp; 277 278 if (platform == NULL) 279 platform = "-"; 280 if (server == NULL) 281 server = "-"; 282 hostp = host_list; 283 while (hostp) { 284 if (hostp->hostid.platform && 285 strcmp(hostp->hostid.platform, platform) == 0 && 286 hostp->hostid.server && 287 strcmp(hostp->hostid.server, server) == 0 && 288 (chassis == NULL || hostp->hostid.chassis == NULL || 289 strcmp(chassis, hostp->hostid.chassis) == 0) && 290 (product_sn == NULL || hostp->hostid.product_sn == NULL || 291 strcmp(product_sn, hostp->hostid.product_sn) == 0) && 292 (domain == NULL || hostp->hostid.domain == NULL || 293 strcmp(domain, hostp->hostid.domain) == 0)) { 294 rt = &hostp->hostid; 295 break; 296 } 297 hostp = hostp->next; 298 } 299 if (rt == NULL) { 300 hostp = malloc(sizeof (host_id_list_t)); 301 hostp->hostid.platform = strdup(platform); 302 hostp->hostid.product_sn = 303 product_sn ? strdup(product_sn) : NULL; 304 hostp->hostid.server = strdup(server); 305 hostp->hostid.chassis = chassis ? strdup(chassis) : NULL; 306 hostp->hostid.domain = domain ? strdup(domain) : NULL; 307 hostp->next = host_list; 308 host_list = hostp; 309 rt = &hostp->hostid; 310 n_server++; 311 } 312 return (rt); 313 } 314 315 static hostid_t * 316 find_hostid(nvlist_t *nvl) 317 { 318 char *platform = NULL, *chassis = NULL, *server = NULL, *domain = NULL; 319 char *product_sn = NULL; 320 nvlist_t *auth, *fmri; 321 hostid_t *rt = NULL; 322 323 if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &fmri) == 0 && 324 nvlist_lookup_nvlist(fmri, FM_FMRI_AUTHORITY, &auth) == 0) { 325 (void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, 326 &platform); 327 (void) nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, 328 &product_sn); 329 (void) nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server); 330 (void) nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, 331 &chassis); 332 (void) nvlist_lookup_string(auth, FM_FMRI_AUTH_DOMAIN, &domain); 333 rt = find_hostid_in_list(platform, chassis, server, 334 domain, product_sn); 335 } 336 return (rt); 337 } 338 339 static char * 340 get_nvl2str_topo(nvlist_t *nvl) 341 { 342 char *name = NULL; 343 char *tname; 344 int err; 345 char *scheme = NULL; 346 char *mod_name = NULL; 347 char buf[128]; 348 349 if (topo_handle == NULL) 350 topo_handle = topo_open(TOPO_VERSION, 0, &err); 351 if (topo_fmri_nvl2str(topo_handle, nvl, &tname, &err) == 0) { 352 name = strdup(tname); 353 topo_hdl_strfree(topo_handle, tname); 354 } else { 355 (void) nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme); 356 (void) nvlist_lookup_string(nvl, FM_FMRI_MOD_NAME, &mod_name); 357 if (scheme && strcmp(scheme, FM_FMRI_SCHEME_FMD) == 0 && 358 mod_name) { 359 (void) snprintf(buf, sizeof (buf), "%s:///module/%s", 360 scheme, mod_name); 361 name = strdup(buf); 362 } 363 } 364 return (name); 365 } 366 367 static int 368 set_priority(char *s) 369 { 370 int rt = 0; 371 372 if (s) { 373 if (strcmp(s, "Minor") == 0) 374 rt = 1; 375 else if (strcmp(s, "Major") == 0) 376 rt = 10; 377 else if (strcmp(s, "Critical") == 0) 378 rt = 100; 379 } 380 return (rt); 381 } 382 383 static int 384 cmp_priority(char *s1, char *s2, uint64_t t1, uint64_t t2, uint8_t p1, 385 uint8_t p2) 386 { 387 int r1, r2; 388 int rt; 389 390 r1 = set_priority(s1); 391 r2 = set_priority(s2); 392 rt = r1 - r2; 393 if (rt == 0) { 394 if (t1 > t2) 395 rt = 1; 396 else if (t1 < t2) 397 rt = -1; 398 else 399 rt = p1 - p2; 400 } 401 return (rt); 402 } 403 404 /* 405 * merge two lists into one, by comparing enties in new and moving into list if 406 * name is not there or free off memory for names which are already there 407 * add_pct indicates if pct is the sum or highest pct 408 */ 409 static name_list_t * 410 merge_name_list(name_list_t **list, name_list_t *new, int add_pct) 411 { 412 name_list_t *lp, *np, *sp, *rt = NULL; 413 int max_pct; 414 415 rt = *list; 416 np = new; 417 while (np) { 418 lp = *list; 419 while (lp) { 420 if (strcmp(lp->name, np->name) == 0) 421 break; 422 lp = lp->next; 423 if (lp == *list) 424 lp = NULL; 425 } 426 if (np->next == new) 427 sp = NULL; 428 else 429 sp = np->next; 430 if (lp) { 431 lp->status |= (np->status & FM_SUSPECT_FAULTY); 432 if (add_pct) { 433 lp->pct += np->pct; 434 lp->count += np->count; 435 } else if (np->pct > lp->pct) { 436 lp->pct = np->pct; 437 } 438 max_pct = np->max_pct; 439 if (np->label) 440 free(np->label); 441 free(np->name); 442 free(np); 443 np = NULL; 444 if (max_pct > lp->max_pct) { 445 lp->max_pct = max_pct; 446 if (lp->max_pct > lp->prev->max_pct && 447 lp != *list) { 448 lp->prev->next = lp->next; 449 lp->next->prev = lp->prev; 450 np = lp; 451 } 452 } 453 } 454 if (np) { 455 lp = *list; 456 if (lp) { 457 if (np->max_pct > lp->max_pct) { 458 np->next = lp; 459 np->prev = lp->prev; 460 lp->prev->next = np; 461 lp->prev = np; 462 *list = np; 463 rt = np; 464 } else { 465 lp = lp->next; 466 while (lp != *list && 467 np->max_pct < lp->max_pct) { 468 lp = lp->next; 469 } 470 np->next = lp; 471 np->prev = lp->prev; 472 lp->prev->next = np; 473 lp->prev = np; 474 } 475 } else { 476 *list = np; 477 np->next = np; 478 np->prev = np; 479 rt = np; 480 } 481 } 482 np = sp; 483 } 484 return (rt); 485 } 486 487 static name_list_t * 488 alloc_name_list(char *name, uint8_t pct) 489 { 490 name_list_t *nlp; 491 492 nlp = malloc(sizeof (*nlp)); 493 nlp->name = strdup(name); 494 nlp->pct = pct; 495 nlp->max_pct = pct; 496 nlp->count = 1; 497 nlp->next = nlp; 498 nlp->prev = nlp; 499 nlp->status = 0; 500 nlp->label = NULL; 501 return (nlp); 502 } 503 504 static status_record_t * 505 new_record_init(uurec_t *uurec_p, char *msgid, name_list_t *class, 506 name_list_t *fru, name_list_t *asru, name_list_t *resource, 507 name_list_t *serial, boolean_t not_suppressed, 508 hostid_t *hostid, boolean_t injected) 509 { 510 status_record_t *status_rec_p; 511 512 status_rec_p = (status_record_t *)malloc(sizeof (status_record_t)); 513 status_rec_p->nrecs = 1; 514 status_rec_p->host = hostid; 515 status_rec_p->uurec = uurec_p; 516 uurec_p->next = NULL; 517 uurec_p->prev = NULL; 518 uurec_p->asru = asru; 519 if ((status_rec_p->severity = fmd_msg_getitem_id(fmadm_msghdl, NULL, 520 msgid, FMD_MSG_ITEM_SEVERITY)) == NULL) 521 status_rec_p->severity = strdup("unknown"); 522 status_rec_p->class = class; 523 status_rec_p->fru = fru; 524 status_rec_p->asru = asru; 525 status_rec_p->resource = resource; 526 status_rec_p->serial = serial; 527 status_rec_p->msgid = strdup(msgid); 528 status_rec_p->not_suppressed = not_suppressed; 529 status_rec_p->injected = injected; 530 return (status_rec_p); 531 } 532 533 /* 534 * add record to given list maintaining order higher priority first. 535 */ 536 static void 537 add_rec_list(status_record_t *status_rec_p, sr_list_t **list_pp) 538 { 539 sr_list_t *tp, *np, *sp; 540 int order; 541 uint64_t sec; 542 543 np = malloc(sizeof (sr_list_t)); 544 np->status_record = status_rec_p; 545 sec = status_rec_p->uurec->sec; 546 if ((sp = *list_pp) == NULL) { 547 *list_pp = np; 548 np->next = np; 549 np->prev = np; 550 } else { 551 /* insert new record in front of lower priority */ 552 tp = sp; 553 order = cmp_priority(status_rec_p->severity, 554 sp->status_record->severity, sec, 555 tp->status_record->uurec->sec, 0, 0); 556 if (order > 0) { 557 *list_pp = np; 558 } else { 559 tp = sp->next; 560 while (tp != sp && 561 cmp_priority(status_rec_p->severity, 562 tp->status_record->severity, sec, 563 tp->status_record->uurec->sec, 0, 0)) { 564 tp = tp->next; 565 } 566 } 567 np->next = tp; 568 np->prev = tp->prev; 569 tp->prev->next = np; 570 tp->prev = np; 571 } 572 } 573 574 static void 575 add_resource(status_record_t *status_rec_p, resource_list_t **rp, 576 resource_list_t *np) 577 { 578 int order; 579 uint64_t sec; 580 resource_list_t *sp, *tp; 581 status_record_t *srp; 582 char *severity = status_rec_p->severity; 583 584 add_rec_list(status_rec_p, &np->status_rec_list); 585 if ((sp = *rp) == NULL) { 586 np->next = np; 587 np->prev = np; 588 *rp = np; 589 } else { 590 /* 591 * insert new record in front of lower priority 592 */ 593 tp = sp->next; 594 srp = sp->status_rec_list->status_record; 595 sec = status_rec_p->uurec->sec; 596 order = cmp_priority(severity, srp->severity, sec, 597 srp->uurec->sec, np->max_pct, sp->max_pct); 598 if (order > 0) { 599 *rp = np; 600 } else { 601 srp = tp->status_rec_list->status_record; 602 while (tp != sp && 603 cmp_priority(severity, srp->severity, sec, 604 srp->uurec->sec, np->max_pct, sp->max_pct) < 0) { 605 tp = tp->next; 606 srp = tp->status_rec_list->status_record; 607 } 608 } 609 np->next = tp; 610 np->prev = tp->prev; 611 tp->prev->next = np; 612 tp->prev = np; 613 } 614 } 615 616 static void 617 add_resource_list(status_record_t *status_rec_p, name_list_t *fp, 618 resource_list_t **rpp) 619 { 620 int order; 621 resource_list_t *np, *end; 622 status_record_t *srp; 623 624 np = *rpp; 625 end = np; 626 while (np) { 627 if (strcmp(fp->name, np->resource) == 0) { 628 np->not_suppressed |= status_rec_p->not_suppressed; 629 np->injected |= status_rec_p->injected; 630 srp = np->status_rec_list->status_record; 631 order = cmp_priority(status_rec_p->severity, 632 srp->severity, status_rec_p->uurec->sec, 633 srp->uurec->sec, fp->max_pct, np->max_pct); 634 if (order > 0 && np != end) { 635 /* 636 * remove from list and add again using 637 * new priority 638 */ 639 np->prev->next = np->next; 640 np->next->prev = np->prev; 641 add_resource(status_rec_p, 642 rpp, np); 643 } else { 644 add_rec_list(status_rec_p, 645 &np->status_rec_list); 646 } 647 break; 648 } 649 np = np->next; 650 if (np == end) { 651 np = NULL; 652 break; 653 } 654 } 655 if (np == NULL) { 656 np = malloc(sizeof (resource_list_t)); 657 np->resource = fp->name; 658 np->not_suppressed = status_rec_p->not_suppressed; 659 np->injected = status_rec_p->injected; 660 np->status_rec_list = NULL; 661 np->max_pct = fp->max_pct; 662 add_resource(status_rec_p, rpp, np); 663 } 664 } 665 666 static void 667 add_list(status_record_t *status_rec_p, name_list_t *listp, 668 resource_list_t **glistp) 669 { 670 name_list_t *fp, *end; 671 672 fp = listp; 673 end = fp; 674 while (fp) { 675 add_resource_list(status_rec_p, fp, glistp); 676 fp = fp->next; 677 if (fp == end) 678 break; 679 } 680 } 681 682 /* 683 * add record to rec, fru and asru lists. 684 */ 685 static void 686 catalog_new_record(uurec_t *uurec_p, char *msgid, name_list_t *class, 687 name_list_t *fru, name_list_t *asru, name_list_t *resource, 688 name_list_t *serial, boolean_t not_suppressed, 689 hostid_t *hostid, boolean_t injected, boolean_t dummy_fru) 690 { 691 status_record_t *status_rec_p; 692 693 status_rec_p = new_record_init(uurec_p, msgid, class, fru, asru, 694 resource, serial, not_suppressed, hostid, injected); 695 add_rec_list(status_rec_p, &status_rec_list); 696 if (status_rec_p->fru && !dummy_fru) 697 add_list(status_rec_p, status_rec_p->fru, &status_fru_list); 698 if (status_rec_p->asru) 699 add_list(status_rec_p, status_rec_p->asru, &status_asru_list); 700 } 701 702 static void 703 get_serial_no(nvlist_t *nvl, name_list_t **serial_p, uint8_t pct) 704 { 705 char *name; 706 char *serial = NULL; 707 char **lserial = NULL; 708 uint64_t serint; 709 name_list_t *nlp; 710 int j; 711 uint_t nelem; 712 char buf[64]; 713 714 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) == 0) { 715 if (strcmp(name, FM_FMRI_SCHEME_CPU) == 0) { 716 if (nvlist_lookup_uint64(nvl, FM_FMRI_CPU_SERIAL_ID, 717 &serint) == 0) { 718 (void) snprintf(buf, sizeof (buf), "%llX", 719 serint); 720 nlp = alloc_name_list(buf, pct); 721 (void) merge_name_list(serial_p, nlp, 1); 722 } 723 } else if (strcmp(name, FM_FMRI_SCHEME_MEM) == 0) { 724 if (nvlist_lookup_string_array(nvl, 725 FM_FMRI_MEM_SERIAL_ID, &lserial, &nelem) == 0) { 726 nlp = alloc_name_list(lserial[0], pct); 727 for (j = 1; j < nelem; j++) { 728 name_list_t *n1lp; 729 n1lp = alloc_name_list(lserial[j], pct); 730 (void) merge_name_list(&nlp, n1lp, 1); 731 } 732 (void) merge_name_list(serial_p, nlp, 1); 733 } 734 } else if (strcmp(name, FM_FMRI_SCHEME_HC) == 0) { 735 if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, 736 &serial) == 0) { 737 nlp = alloc_name_list(serial, pct); 738 (void) merge_name_list(serial_p, nlp, 1); 739 } 740 } 741 } 742 } 743 744 static void 745 extract_record_info(nvlist_t *nvl, name_list_t **class_p, 746 name_list_t **fru_p, name_list_t **serial_p, name_list_t **resource_p, 747 name_list_t **asru_p, boolean_t *dummy_fru, uint8_t status) 748 { 749 nvlist_t *lfru, *lasru, *rsrc; 750 name_list_t *nlp; 751 char *name; 752 uint8_t lpct = 0; 753 char *lclass = NULL; 754 char *label; 755 756 (void) nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &lpct); 757 if (nvlist_lookup_string(nvl, FM_CLASS, &lclass) == 0) { 758 nlp = alloc_name_list(lclass, lpct); 759 (void) merge_name_list(class_p, nlp, 1); 760 } 761 if (nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &lfru) == 0) { 762 name = get_nvl2str_topo(lfru); 763 if (name != NULL) { 764 nlp = alloc_name_list(name, lpct); 765 nlp->status = status & ~(FM_SUSPECT_UNUSABLE | 766 FM_SUSPECT_DEGRADED); 767 free(name); 768 if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION, 769 &label) == 0) 770 nlp->label = strdup(label); 771 (void) merge_name_list(fru_p, nlp, 1); 772 } 773 get_serial_no(lfru, serial_p, lpct); 774 } else if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) != 0) { 775 /* 776 * No FRU or resource. But we want to display the repair status 777 * somehow, so create a dummy FRU field. 778 */ 779 *dummy_fru = 1; 780 nlp = alloc_name_list(dgettext("FMD", "None"), lpct); 781 nlp->status = status & ~(FM_SUSPECT_UNUSABLE | 782 FM_SUSPECT_DEGRADED); 783 (void) merge_name_list(fru_p, nlp, 1); 784 } 785 if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &lasru) == 0) { 786 name = get_nvl2str_topo(lasru); 787 if (name != NULL) { 788 nlp = alloc_name_list(name, lpct); 789 nlp->status = status & ~(FM_SUSPECT_NOT_PRESENT | 790 FM_SUSPECT_REPAIRED | FM_SUSPECT_REPLACED | 791 FM_SUSPECT_ACQUITTED); 792 free(name); 793 (void) merge_name_list(asru_p, nlp, 1); 794 } 795 get_serial_no(lasru, serial_p, lpct); 796 } 797 if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) { 798 name = get_nvl2str_topo(rsrc); 799 if (name != NULL) { 800 nlp = alloc_name_list(name, lpct); 801 nlp->status = status; 802 free(name); 803 if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION, 804 &label) == 0) 805 nlp->label = strdup(label); 806 (void) merge_name_list(resource_p, nlp, 1); 807 } 808 } 809 } 810 811 static void 812 add_fault_record_to_catalog(nvlist_t *nvl, uint64_t sec, char *uuid) 813 { 814 char *msgid = "-"; 815 uint_t i, size = 0; 816 name_list_t *class = NULL, *resource = NULL; 817 name_list_t *asru = NULL, *fru = NULL, *serial = NULL; 818 nvlist_t **nva; 819 uint8_t *ba; 820 uurec_t *uurec_p; 821 hostid_t *host; 822 boolean_t not_suppressed = 1; 823 boolean_t any_present = 0; 824 boolean_t injected = 0; 825 boolean_t dummy_fru = 0; 826 827 (void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &msgid); 828 (void) nvlist_lookup_uint32(nvl, FM_SUSPECT_FAULT_SZ, &size); 829 (void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_MESSAGE, 830 ¬_suppressed); 831 (void) nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED, &injected); 832 833 if (size != 0) { 834 (void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, 835 &nva, &size); 836 (void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS, 837 &ba, &size); 838 for (i = 0; i < size; i++) { 839 extract_record_info(nva[i], &class, &fru, &serial, 840 &resource, &asru, &dummy_fru, ba[i]); 841 if (!(ba[i] & FM_SUSPECT_NOT_PRESENT) && 842 (ba[i] & FM_SUSPECT_FAULTY)) 843 any_present = 1; 844 } 845 /* 846 * also suppress if no resources present 847 */ 848 if (any_present == 0) 849 not_suppressed = 0; 850 } 851 852 uurec_p = (uurec_t *)malloc(sizeof (uurec_t)); 853 uurec_p->uuid = strdup(uuid); 854 uurec_p->sec = sec; 855 uurec_p->ari_uuid_list = NULL; 856 uurec_p->event = NULL; 857 (void) nvlist_dup(nvl, &uurec_p->event, 0); 858 host = find_hostid(nvl); 859 catalog_new_record(uurec_p, msgid, class, fru, asru, 860 resource, serial, not_suppressed, host, injected, dummy_fru); 861 } 862 863 static void 864 update_asru_state_in_catalog(const char *uuid, const char *ari_uuid) 865 { 866 sr_list_t *srp; 867 uurec_t *uurp; 868 ari_list_t *ari_list; 869 870 srp = status_rec_list; 871 if (srp) { 872 for (;;) { 873 uurp = srp->status_record->uurec; 874 while (uurp) { 875 if (strcmp(uuid, uurp->uuid) == 0) { 876 ari_list = (ari_list_t *) 877 malloc(sizeof (ari_list_t)); 878 ari_list->ari_uuid = strdup(ari_uuid); 879 ari_list->next = uurp->ari_uuid_list; 880 uurp->ari_uuid_list = ari_list; 881 return; 882 } 883 uurp = uurp->next; 884 } 885 if (srp->next == status_rec_list) 886 break; 887 srp = srp->next; 888 } 889 } 890 } 891 892 static void 893 print_line(char *label, char *buf) 894 { 895 char *cp, *ep, *wp; 896 char c; 897 int i; 898 int lsz; 899 char *padding; 900 901 lsz = strlen(label); 902 padding = malloc(lsz + 1); 903 for (i = 0; i < lsz; i++) 904 padding[i] = ' '; 905 padding[i] = 0; 906 cp = buf; 907 ep = buf; 908 c = *ep; 909 (void) printf("\n"); 910 while (c) { 911 i = lsz; 912 wp = NULL; 913 while ((c = *ep) != '\0' && (wp == NULL || i < 80)) { 914 if (c == ' ') 915 wp = ep; 916 else if (c == '\n') { 917 i = 0; 918 *ep = 0; 919 do { 920 ep++; 921 } while ((c = *ep) != '\0' && c == ' '); 922 break; 923 } 924 ep++; 925 i++; 926 } 927 if (i >= 80 && wp) { 928 *wp = 0; 929 ep = wp + 1; 930 c = *ep; 931 } 932 (void) printf("%s%s\n", label, cp); 933 cp = ep; 934 label = padding; 935 } 936 free(padding); 937 } 938 939 static void 940 print_dict_info_line(nvlist_t *e, fmd_msg_item_t what, const char *linehdr) 941 { 942 char *cp = fmd_msg_getitem_nv(fmadm_msghdl, NULL, e, what); 943 944 if (cp) { 945 print_line(dgettext("FMD", linehdr), cp); 946 free(cp); 947 } 948 } 949 950 static void 951 print_dict_info(nvlist_t *nvl) 952 { 953 print_dict_info_line(nvl, FMD_MSG_ITEM_DESC, "Description : "); 954 print_dict_info_line(nvl, FMD_MSG_ITEM_RESPONSE, "Response : "); 955 print_dict_info_line(nvl, FMD_MSG_ITEM_IMPACT, "Impact : "); 956 print_dict_info_line(nvl, FMD_MSG_ITEM_ACTION, "Action : "); 957 } 958 959 static void 960 print_name(name_list_t *list, char *padding, int *np, int pct, int full) 961 { 962 char *name; 963 964 name = list->name; 965 if (list->label) { 966 (void) printf("%s \"%s\" (%s)", padding, list->label, name); 967 *np += 1; 968 } else { 969 (void) printf("%s %s", padding, name); 970 *np += 1; 971 } 972 if (list->pct && pct > 0 && pct < 100) { 973 if (list->count > 1) { 974 if (full) { 975 (void) printf(" %d @ %s %d%%\n", list->count, 976 dgettext("FMD", "max"), 977 list->max_pct); 978 } else { 979 (void) printf(" %s %d%%\n", 980 dgettext("FMD", "max"), 981 list->max_pct); 982 } 983 } else { 984 (void) printf(" %d%%\n", list->pct); 985 } 986 } else { 987 (void) printf("\n"); 988 } 989 } 990 991 static void 992 print_asru_status(int status, char *label) 993 { 994 char *msg = NULL; 995 996 switch (status) { 997 case 0: 998 msg = dgettext("FMD", "ok and in service"); 999 break; 1000 case FM_SUSPECT_DEGRADED: 1001 msg = dgettext("FMD", "service degraded, " 1002 "but associated components no longer faulty"); 1003 break; 1004 case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED: 1005 msg = dgettext("FMD", "faulted but still " 1006 "providing degraded service"); 1007 break; 1008 case FM_SUSPECT_FAULTY: 1009 msg = dgettext("FMD", "faulted but still in service"); 1010 break; 1011 case FM_SUSPECT_UNUSABLE: 1012 msg = dgettext("FMD", "out of service, " 1013 "but associated components no longer faulty"); 1014 break; 1015 case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE: 1016 msg = dgettext("FMD", "faulted and taken out of service"); 1017 break; 1018 default: 1019 break; 1020 } 1021 if (msg) { 1022 (void) printf("%s %s\n", label, msg); 1023 } 1024 } 1025 1026 static void 1027 print_fru_status(int status, char *label) 1028 { 1029 char *msg = NULL; 1030 1031 if (status & FM_SUSPECT_NOT_PRESENT) 1032 msg = dgettext("FMD", "not present"); 1033 else if (status & FM_SUSPECT_FAULTY) 1034 msg = dgettext("FMD", "faulty"); 1035 else if (status & FM_SUSPECT_REPLACED) 1036 msg = dgettext("FMD", "replaced"); 1037 else if (status & FM_SUSPECT_REPAIRED) 1038 msg = dgettext("FMD", "repair attempted"); 1039 else if (status & FM_SUSPECT_ACQUITTED) 1040 msg = dgettext("FMD", "acquitted"); 1041 else 1042 msg = dgettext("FMD", "removed"); 1043 (void) printf("%s %s\n", label, msg); 1044 } 1045 1046 static void 1047 print_rsrc_status(int status, char *label) 1048 { 1049 char *msg = ""; 1050 1051 if (status & FM_SUSPECT_NOT_PRESENT) 1052 msg = dgettext("FMD", "not present"); 1053 else if (status & FM_SUSPECT_FAULTY) { 1054 if (status & FM_SUSPECT_DEGRADED) 1055 msg = dgettext("FMD", 1056 "faulted but still providing degraded service"); 1057 else if (status & FM_SUSPECT_UNUSABLE) 1058 msg = dgettext("FMD", 1059 "faulted and taken out of service"); 1060 else 1061 msg = dgettext("FMD", "faulted but still in service"); 1062 } else if (status & FM_SUSPECT_REPLACED) 1063 msg = dgettext("FMD", "replaced"); 1064 else if (status & FM_SUSPECT_REPAIRED) 1065 msg = dgettext("FMD", "repair attempted"); 1066 else if (status & FM_SUSPECT_ACQUITTED) 1067 msg = dgettext("FMD", "acquitted"); 1068 else 1069 msg = dgettext("FMD", "removed"); 1070 (void) printf("%s %s\n", label, msg); 1071 } 1072 1073 static void 1074 print_name_list(name_list_t *list, char *label, 1075 int limit, int pct, void (func1)(int, char *), int full) 1076 { 1077 char *name; 1078 char *padding; 1079 int i, j, l, n; 1080 name_list_t *end = list; 1081 1082 l = strlen(label); 1083 padding = malloc(l + 1); 1084 for (i = 0; i < l; i++) 1085 padding[i] = ' '; 1086 padding[l] = 0; 1087 (void) printf("%s", label); 1088 name = list->name; 1089 if (list->label) 1090 (void) printf(" \"%s\" (%s)", list->label, name); 1091 else 1092 (void) printf(" %s", name); 1093 if (list->pct && pct > 0 && pct < 100) { 1094 if (list->count > 1) { 1095 if (full) { 1096 (void) printf(" %d @ %s %d%%\n", list->count, 1097 dgettext("FMD", "max"), list->max_pct); 1098 } else { 1099 (void) printf(" %s %d%%\n", 1100 dgettext("FMD", "max"), list->max_pct); 1101 } 1102 } else { 1103 (void) printf(" %d%%\n", list->pct); 1104 } 1105 } else { 1106 (void) printf("\n"); 1107 } 1108 if (func1) 1109 func1(list->status, padding); 1110 n = 1; 1111 j = 0; 1112 while ((list = list->next) != end) { 1113 if (limit == 0 || n < limit) { 1114 print_name(list, padding, &n, pct, full); 1115 if (func1) 1116 func1(list->status, padding); 1117 } else 1118 j++; 1119 } 1120 if (j == 1) { 1121 print_name(list->prev, padding, &n, pct, full); 1122 } else if (j > 1) { 1123 (void) printf("%s... %d %s\n", padding, j, 1124 dgettext("FMD", "more entries suppressed," 1125 " use -v option for full list")); 1126 } 1127 free(padding); 1128 } 1129 1130 static int 1131 asru_same_status(name_list_t *list) 1132 { 1133 name_list_t *end = list; 1134 int status = list->status; 1135 1136 while ((list = list->next) != end) { 1137 if (status == -1) { 1138 status = list->status; 1139 continue; 1140 } 1141 if (list->status != -1 && status != list->status) { 1142 status = -1; 1143 break; 1144 } 1145 } 1146 return (status); 1147 } 1148 1149 static int 1150 serial_in_fru(name_list_t *fru, name_list_t *serial) 1151 { 1152 name_list_t *sp = serial; 1153 name_list_t *fp; 1154 int nserial = 0; 1155 int found = 0; 1156 char buf[128]; 1157 1158 while (sp) { 1159 fp = fru; 1160 nserial++; 1161 (void) snprintf(buf, sizeof (buf), "serial=%s", sp->name); 1162 buf[sizeof (buf) - 1] = 0; 1163 while (fp) { 1164 if (strstr(fp->name, buf) != NULL) { 1165 found++; 1166 break; 1167 } 1168 fp = fp->next; 1169 if (fp == fru) 1170 break; 1171 } 1172 sp = sp->next; 1173 if (sp == serial) 1174 break; 1175 } 1176 return (found == nserial ? 1 : 0); 1177 } 1178 1179 static void 1180 print_sup_record(status_record_t *srp, int opt_i, int full) 1181 { 1182 char buf[32]; 1183 uurec_t *uurp = srp->uurec; 1184 int n, j, k, max; 1185 int status; 1186 ari_list_t *ari_list; 1187 1188 n = 0; 1189 max = max_fault; 1190 if (max < 0) { 1191 max = 0; 1192 } 1193 j = max / 2; 1194 max -= j; 1195 k = srp->nrecs - max; 1196 while ((uurp = uurp->next) != NULL) { 1197 if (full || n < j || n >= k || max_fault == 0 || 1198 srp->nrecs == max_fault+1) { 1199 if (opt_i) { 1200 ari_list = uurp->ari_uuid_list; 1201 while (ari_list) { 1202 (void) printf("%-15s %s\n", 1203 format_date(buf, sizeof (buf), 1204 uurp->sec), ari_list->ari_uuid); 1205 ari_list = ari_list->next; 1206 } 1207 } else { 1208 (void) printf("%-15s %s\n", 1209 format_date(buf, sizeof (buf), uurp->sec), 1210 uurp->uuid); 1211 } 1212 } else if (n == j) 1213 (void) printf("... %d %s\n", srp->nrecs - max_fault, 1214 dgettext("FMD", "more entries suppressed")); 1215 n++; 1216 } 1217 (void) printf("\n"); 1218 if (srp->host) { 1219 (void) printf("%s %s", dgettext("FMD", "Host :"), 1220 srp->host->server); 1221 if (srp->host->domain) 1222 (void) printf("\t%s %s", dgettext("FMD", 1223 "Domain :"), srp->host->domain); 1224 (void) printf("\n%s %s", dgettext("FMD", "Platform :"), 1225 srp->host->platform); 1226 (void) printf("\t%s %s", dgettext("FMD", "Chassis_id :"), 1227 srp->host->chassis ? srp->host->chassis : ""); 1228 (void) printf("\n%s %s\n\n", dgettext("FMD", "Product_sn :"), 1229 srp->host->product_sn ? srp->host->product_sn : ""); 1230 } 1231 if (srp->class) 1232 print_name_list(srp->class, 1233 dgettext("FMD", "Fault class :"), 0, srp->class->pct, 1234 NULL, full); 1235 if (srp->asru) { 1236 status = asru_same_status(srp->asru); 1237 if (status != -1) { 1238 print_name_list(srp->asru, 1239 dgettext("FMD", "Affects :"), 1240 full ? 0 : max_display, 0, NULL, full); 1241 print_asru_status(status, " "); 1242 } else 1243 print_name_list(srp->asru, 1244 dgettext("FMD", "Affects :"), 1245 full ? 0 : max_display, 0, print_asru_status, full); 1246 } 1247 if (full || srp->fru == NULL || srp->asru == NULL) { 1248 if (srp->resource) { 1249 status = asru_same_status(srp->resource); 1250 if (status != -1) { 1251 print_name_list(srp->resource, 1252 dgettext("FMD", "Problem in :"), 1253 full ? 0 : max_display, 0, NULL, full); 1254 print_rsrc_status(status, " "); 1255 } else 1256 print_name_list(srp->resource, 1257 dgettext("FMD", "Problem in :"), 1258 full ? 0 : max_display, 0, 1259 print_rsrc_status, full); 1260 } 1261 } 1262 if (srp->fru) { 1263 status = asru_same_status(srp->fru); 1264 if (status != -1) { 1265 print_name_list(srp->fru, dgettext("FMD", 1266 "FRU :"), 0, 1267 srp->fru->pct == 100 ? 100 : srp->fru->max_pct, 1268 NULL, full); 1269 print_fru_status(status, " "); 1270 } else 1271 print_name_list(srp->fru, dgettext("FMD", 1272 "FRU :"), 0, 1273 srp->fru->pct == 100 ? 100 : srp->fru->max_pct, 1274 print_fru_status, full); 1275 } 1276 if (srp->serial && !serial_in_fru(srp->fru, srp->serial) && 1277 !serial_in_fru(srp->asru, srp->serial)) { 1278 print_name_list(srp->serial, dgettext("FMD", "Serial ID. :"), 1279 0, 0, NULL, full); 1280 } 1281 print_dict_info(srp->uurec->event); 1282 (void) printf("\n"); 1283 } 1284 1285 static void 1286 print_status_record(status_record_t *srp, int summary, int opt_i, int full) 1287 { 1288 char buf[32]; 1289 uurec_t *uurp = srp->uurec; 1290 static int header = 0; 1291 char *head; 1292 ari_list_t *ari_list; 1293 1294 if (!summary || !header) { 1295 if (opt_i) { 1296 head = "--------------- " 1297 "------------------------------------ " 1298 "-------------- ---------\n" 1299 "TIME CACHE-ID" 1300 " MSG-ID" 1301 " SEVERITY\n--------------- " 1302 "------------------------------------ " 1303 " -------------- ---------"; 1304 } else { 1305 head = "--------------- " 1306 "------------------------------------ " 1307 "-------------- ---------\n" 1308 "TIME EVENT-ID" 1309 " MSG-ID" 1310 " SEVERITY\n--------------- " 1311 "------------------------------------ " 1312 " -------------- ---------"; 1313 } 1314 (void) printf("%s\n", dgettext("FMD", head)); 1315 header = 1; 1316 } 1317 if (opt_i) { 1318 ari_list = uurp->ari_uuid_list; 1319 while (ari_list) { 1320 (void) printf("%-15s %-37s %-14s %-9s %s\n", 1321 format_date(buf, sizeof (buf), uurp->sec), 1322 ari_list->ari_uuid, srp->msgid, srp->severity, 1323 srp->injected ? dgettext("FMD", "injected") : ""); 1324 ari_list = ari_list->next; 1325 } 1326 } else { 1327 (void) printf("%-15s %-37s %-14s %-9s %s\n", 1328 format_date(buf, sizeof (buf), uurp->sec), 1329 uurp->uuid, srp->msgid, srp->severity, 1330 srp->injected ? dgettext("FMD", "injected") : ""); 1331 } 1332 1333 if (!summary) 1334 print_sup_record(srp, opt_i, full); 1335 } 1336 1337 static void 1338 print_catalog(int summary, int opt_a, int full, int opt_i, int page_feed) 1339 { 1340 status_record_t *srp; 1341 sr_list_t *slp; 1342 1343 slp = status_rec_list; 1344 if (slp) { 1345 for (;;) { 1346 srp = slp->status_record; 1347 if (opt_a || srp->not_suppressed) { 1348 if (page_feed) 1349 (void) printf("\f\n"); 1350 print_status_record(srp, summary, opt_i, full); 1351 } 1352 if (slp->next == status_rec_list) 1353 break; 1354 slp = slp->next; 1355 } 1356 } 1357 } 1358 1359 static name_list_t * 1360 find_fru(status_record_t *srp, char *resource) 1361 { 1362 name_list_t *rt = NULL; 1363 name_list_t *fru = srp->fru; 1364 1365 while (fru) { 1366 if (strcmp(resource, fru->name) == 0) { 1367 rt = fru; 1368 break; 1369 } 1370 fru = fru->next; 1371 if (fru == srp->fru) 1372 break; 1373 } 1374 return (rt); 1375 } 1376 1377 static void 1378 print_fru_line(name_list_t *fru, char *uuid) 1379 { 1380 if (fru->pct == 100) { 1381 (void) printf("%s %d %s %d%%\n", uuid, fru->count, 1382 dgettext("FMD", "suspects in this FRU total certainty"), 1383 100); 1384 } else { 1385 (void) printf("%s %d %s %d%%\n", uuid, fru->count, 1386 dgettext("FMD", "suspects in this FRU max certainty"), 1387 fru->max_pct); 1388 } 1389 } 1390 1391 static void 1392 print_fru(int summary, int opt_a, int opt_i, int page_feed) 1393 { 1394 resource_list_t *tp = status_fru_list; 1395 status_record_t *srp; 1396 sr_list_t *slp, *end; 1397 uurec_t *uurp; 1398 name_list_t *fru; 1399 int status; 1400 ari_list_t *ari_list; 1401 1402 while (tp) { 1403 if (opt_a || tp->not_suppressed) { 1404 if (page_feed) 1405 (void) printf("\f\n"); 1406 if (!summary) 1407 (void) printf("-----------------------------" 1408 "---------------------------------------" 1409 "----------\n"); 1410 slp = tp->status_rec_list; 1411 end = slp; 1412 do { 1413 srp = slp->status_record; 1414 if (!srp->not_suppressed) { 1415 slp = slp->next; 1416 continue; 1417 } 1418 fru = find_fru(srp, tp->resource); 1419 if (fru) { 1420 if (fru->label) 1421 (void) printf("\"%s\" (%s) ", 1422 fru->label, fru->name); 1423 else 1424 (void) printf("%s ", 1425 fru->name); 1426 break; 1427 } 1428 slp = slp->next; 1429 } while (slp != end); 1430 1431 slp = tp->status_rec_list; 1432 end = slp; 1433 status = 0; 1434 do { 1435 srp = slp->status_record; 1436 if (!srp->not_suppressed) { 1437 slp = slp->next; 1438 continue; 1439 } 1440 fru = srp->fru; 1441 while (fru) { 1442 if (strcmp(tp->resource, 1443 fru->name) == 0) 1444 status |= fru->status; 1445 fru = fru->next; 1446 if (fru == srp->fru) 1447 break; 1448 } 1449 slp = slp->next; 1450 } while (slp != end); 1451 if (status & FM_SUSPECT_NOT_PRESENT) 1452 (void) printf(dgettext("FMD", "not present")); 1453 else if (status & FM_SUSPECT_FAULTY) 1454 (void) printf(dgettext("FMD", "faulty")); 1455 else if (status & FM_SUSPECT_REPLACED) 1456 (void) printf(dgettext("FMD", "replaced")); 1457 else if (status & FM_SUSPECT_REPAIRED) 1458 (void) printf(dgettext("FMD", 1459 "repair attempted")); 1460 else if (status & FM_SUSPECT_ACQUITTED) 1461 (void) printf(dgettext("FMD", "acquitted")); 1462 else 1463 (void) printf(dgettext("FMD", "removed")); 1464 1465 if (tp->injected) 1466 (void) printf(dgettext("FMD", " injected\n")); 1467 else 1468 (void) printf(dgettext("FMD", "\n")); 1469 1470 slp = tp->status_rec_list; 1471 end = slp; 1472 do { 1473 srp = slp->status_record; 1474 if (!srp->not_suppressed) { 1475 slp = slp->next; 1476 continue; 1477 } 1478 uurp = srp->uurec; 1479 fru = find_fru(srp, tp->resource); 1480 if (fru) { 1481 if (opt_i) { 1482 ari_list = uurp->ari_uuid_list; 1483 while (ari_list) { 1484 print_fru_line(fru, 1485 ari_list->ari_uuid); 1486 ari_list = 1487 ari_list->next; 1488 } 1489 } else { 1490 print_fru_line(fru, uurp->uuid); 1491 } 1492 } 1493 slp = slp->next; 1494 } while (slp != end); 1495 if (!summary) { 1496 slp = tp->status_rec_list; 1497 end = slp; 1498 do { 1499 srp = slp->status_record; 1500 if (!srp->not_suppressed) { 1501 slp = slp->next; 1502 continue; 1503 } 1504 if (srp->serial && 1505 !serial_in_fru(srp->fru, 1506 srp->serial)) { 1507 print_name_list(srp->serial, 1508 dgettext("FMD", 1509 "Serial ID. :"), 1510 0, 0, NULL, 1); 1511 break; 1512 } 1513 slp = slp->next; 1514 } while (slp != end); 1515 } 1516 } 1517 tp = tp->next; 1518 if (tp == status_fru_list) 1519 break; 1520 } 1521 } 1522 1523 static void 1524 print_asru(int opt_a) 1525 { 1526 resource_list_t *tp = status_asru_list; 1527 status_record_t *srp; 1528 sr_list_t *slp, *end; 1529 char *msg; 1530 int status; 1531 name_list_t *asru; 1532 1533 while (tp) { 1534 if (opt_a || tp->not_suppressed) { 1535 status = 0; 1536 slp = tp->status_rec_list; 1537 end = slp; 1538 do { 1539 srp = slp->status_record; 1540 if (!srp->not_suppressed) { 1541 slp = slp->next; 1542 continue; 1543 } 1544 asru = srp->asru; 1545 while (asru) { 1546 if (strcmp(tp->resource, 1547 asru->name) == 0) 1548 status |= asru->status; 1549 asru = asru->next; 1550 if (asru == srp->asru) 1551 break; 1552 } 1553 slp = slp->next; 1554 } while (slp != end); 1555 switch (status) { 1556 case 0: 1557 msg = dgettext("FMD", "ok"); 1558 break; 1559 case FM_SUSPECT_DEGRADED: 1560 msg = dgettext("FMD", "degraded"); 1561 break; 1562 case FM_SUSPECT_FAULTY | FM_SUSPECT_DEGRADED: 1563 msg = dgettext("FMD", "degraded"); 1564 break; 1565 case FM_SUSPECT_FAULTY: 1566 msg = dgettext("FMD", "degraded"); 1567 break; 1568 case FM_SUSPECT_UNUSABLE: 1569 msg = dgettext("FMD", "unknown"); 1570 break; 1571 case FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE: 1572 msg = dgettext("FMD", "faulted"); 1573 break; 1574 default: 1575 msg = ""; 1576 break; 1577 } 1578 (void) printf("%-69s %s", tp->resource, msg); 1579 if (tp->injected) 1580 (void) printf(dgettext("FMD", " injected\n")); 1581 else 1582 (void) printf(dgettext("FMD", "\n")); 1583 } 1584 tp = tp->next; 1585 if (tp == status_asru_list) 1586 break; 1587 } 1588 } 1589 1590 static int 1591 uuid_in_list(char *uuid, uurec_select_t *uurecp) 1592 { 1593 while (uurecp) { 1594 if (strcmp(uuid, uurecp->uuid) == 0) 1595 return (1); 1596 uurecp = uurecp->next; 1597 } 1598 return (0); 1599 } 1600 1601 static int 1602 dfault_rec(const fmd_adm_caseinfo_t *acp, void *arg) 1603 { 1604 int64_t *diag_time; 1605 uint_t nelem; 1606 int rt = 0; 1607 char *uuid = "-"; 1608 uurec_select_t *uurecp = (uurec_select_t *)arg; 1609 1610 if (nvlist_lookup_int64_array(acp->aci_event, FM_SUSPECT_DIAG_TIME, 1611 &diag_time, &nelem) == 0 && nelem >= 2) { 1612 (void) nvlist_lookup_string(acp->aci_event, FM_SUSPECT_UUID, 1613 &uuid); 1614 if (uurecp == NULL || uuid_in_list(uuid, uurecp)) 1615 add_fault_record_to_catalog(acp->aci_event, *diag_time, 1616 uuid); 1617 } else { 1618 rt = -1; 1619 } 1620 return (rt); 1621 } 1622 1623 /*ARGSUSED*/ 1624 static int 1625 dstatus_rec(const fmd_adm_rsrcinfo_t *ari, void *unused) 1626 { 1627 update_asru_state_in_catalog(ari->ari_case, ari->ari_uuid); 1628 return (0); 1629 } 1630 1631 static int 1632 get_cases_from_fmd(fmd_adm_t *adm, uurec_select_t *uurecp, int opt_i) 1633 { 1634 int rt = FMADM_EXIT_SUCCESS; 1635 1636 /* 1637 * These calls may fail with Protocol error if message payload is 1638 * too big 1639 */ 1640 if (fmd_adm_case_iter(adm, NULL, dfault_rec, uurecp) != 0) 1641 die("failed to get case list from fmd"); 1642 if (opt_i && fmd_adm_rsrc_iter(adm, 1, dstatus_rec, NULL) != 0) 1643 die("failed to get case status from fmd"); 1644 return (rt); 1645 } 1646 1647 /* 1648 * fmadm faulty command 1649 * 1650 * -a show hidden fault records 1651 * -f show faulty fru's 1652 * -g force grouping of similar faults on the same fru 1653 * -n number of fault records to display 1654 * -p pipe output through pager 1655 * -r show faulty asru's 1656 * -s print summary of first fault 1657 * -u print listed uuid's only 1658 * -v full output 1659 */ 1660 1661 int 1662 cmd_faulty(fmd_adm_t *adm, int argc, char *argv[]) 1663 { 1664 int opt_a = 0, opt_v = 0, opt_p = 0, opt_s = 0, opt_r = 0, opt_f = 0; 1665 int opt_i = 0; 1666 char *pager; 1667 FILE *fp; 1668 int rt, c, stat; 1669 uurec_select_t *tp; 1670 uurec_select_t *uurecp = NULL; 1671 1672 while ((c = getopt(argc, argv, "afgin:prsu:v")) != EOF) { 1673 switch (c) { 1674 case 'a': 1675 opt_a++; 1676 break; 1677 case 'f': 1678 opt_f++; 1679 break; 1680 case 'g': 1681 opt_g++; 1682 break; 1683 case 'i': 1684 opt_i++; 1685 break; 1686 case 'n': 1687 max_fault = atoi(optarg); 1688 break; 1689 case 'p': 1690 opt_p++; 1691 break; 1692 case 'r': 1693 opt_r++; 1694 break; 1695 case 's': 1696 opt_s++; 1697 break; 1698 case 'u': 1699 tp = (uurec_select_t *)malloc(sizeof (uurec_select_t)); 1700 tp->uuid = optarg; 1701 tp->next = uurecp; 1702 uurecp = tp; 1703 opt_a = 1; 1704 break; 1705 case 'v': 1706 opt_v++; 1707 break; 1708 default: 1709 return (FMADM_EXIT_USAGE); 1710 } 1711 } 1712 if (optind < argc) 1713 return (FMADM_EXIT_USAGE); 1714 1715 if ((fmadm_msghdl = fmd_msg_init(NULL, FMD_MSG_VERSION)) == NULL) 1716 return (FMADM_EXIT_ERROR); 1717 rt = get_cases_from_fmd(adm, uurecp, opt_i); 1718 if (opt_p) { 1719 if ((pager = getenv("PAGER")) == NULL) 1720 pager = "/usr/bin/more"; 1721 fp = popen(pager, "w"); 1722 if (fp == NULL) { 1723 rt = FMADM_EXIT_ERROR; 1724 opt_p = 0; 1725 } else { 1726 (void) dup2(fileno(fp), 1); 1727 setbuf(stdout, NULL); 1728 (void) fclose(fp); 1729 } 1730 } 1731 max_display = max_fault; 1732 if (opt_f) 1733 print_fru(opt_s, opt_a, opt_i, opt_p && !opt_s); 1734 if (opt_r) 1735 print_asru(opt_a); 1736 if (opt_f == 0 && opt_r == 0) 1737 print_catalog(opt_s, opt_a, opt_v, opt_i, opt_p && !opt_s); 1738 fmd_msg_fini(fmadm_msghdl); 1739 if (topo_handle) 1740 topo_close(topo_handle); 1741 if (opt_p) { 1742 (void) fclose(stdout); 1743 (void) wait(&stat); 1744 } 1745 return (rt); 1746 } 1747 1748 int 1749 cmd_flush(fmd_adm_t *adm, int argc, char *argv[]) 1750 { 1751 int i, status = FMADM_EXIT_SUCCESS; 1752 1753 if (argc < 2 || (i = getopt(argc, argv, "")) != EOF) 1754 return (FMADM_EXIT_USAGE); 1755 1756 for (i = 1; i < argc; i++) { 1757 if (fmd_adm_rsrc_flush(adm, argv[i]) != 0) { 1758 warn("failed to flush %s", argv[i]); 1759 status = FMADM_EXIT_ERROR; 1760 } else 1761 note("flushed resource history for %s\n", argv[i]); 1762 } 1763 1764 return (status); 1765 } 1766 1767 int 1768 cmd_repair(fmd_adm_t *adm, int argc, char *argv[]) 1769 { 1770 int err; 1771 1772 if (getopt(argc, argv, "") != EOF) 1773 return (FMADM_EXIT_USAGE); 1774 1775 if (argc - optind != 1) 1776 return (FMADM_EXIT_USAGE); 1777 1778 /* 1779 * argument could be a uuid, an fmri (asru, fru or resource) 1780 * or a label. Try uuid first, If that fails try the others. 1781 */ 1782 err = fmd_adm_case_repair(adm, argv[optind]); 1783 if (err != 0) 1784 err = fmd_adm_rsrc_repaired(adm, argv[optind]); 1785 1786 if (err != 0) 1787 die("failed to record repair to %s", argv[optind]); 1788 1789 note("recorded repair to %s\n", argv[optind]); 1790 return (FMADM_EXIT_SUCCESS); 1791 } 1792 1793 int 1794 cmd_repaired(fmd_adm_t *adm, int argc, char *argv[]) 1795 { 1796 int err; 1797 1798 if (getopt(argc, argv, "") != EOF) 1799 return (FMADM_EXIT_USAGE); 1800 1801 if (argc - optind != 1) 1802 return (FMADM_EXIT_USAGE); 1803 1804 /* 1805 * argument could be an fmri (asru, fru or resource) or a label. 1806 */ 1807 err = fmd_adm_rsrc_repaired(adm, argv[optind]); 1808 if (err != 0) 1809 die("failed to record repair to %s", argv[optind]); 1810 1811 note("recorded repair to of %s\n", argv[optind]); 1812 return (FMADM_EXIT_SUCCESS); 1813 } 1814 1815 int 1816 cmd_replaced(fmd_adm_t *adm, int argc, char *argv[]) 1817 { 1818 int err; 1819 1820 if (getopt(argc, argv, "") != EOF) 1821 return (FMADM_EXIT_USAGE); 1822 1823 if (argc - optind != 1) 1824 return (FMADM_EXIT_USAGE); 1825 1826 /* 1827 * argument could be an fmri (asru, fru or resource) or a label. 1828 */ 1829 err = fmd_adm_rsrc_replaced(adm, argv[optind]); 1830 if (err != 0) 1831 die("failed to record replacement of %s", argv[optind]); 1832 1833 note("recorded replacement of %s\n", argv[optind]); 1834 return (FMADM_EXIT_SUCCESS); 1835 } 1836 1837 int 1838 cmd_acquit(fmd_adm_t *adm, int argc, char *argv[]) 1839 { 1840 int err; 1841 1842 if (getopt(argc, argv, "") != EOF) 1843 return (FMADM_EXIT_USAGE); 1844 1845 if (argc - optind != 1 && argc - optind != 2) 1846 return (FMADM_EXIT_USAGE); 1847 1848 /* 1849 * argument could be a uuid, an fmri (asru, fru or resource) 1850 * or a label. Or it could be a uuid and an fmri or label. 1851 */ 1852 if (argc - optind == 2) { 1853 err = fmd_adm_rsrc_acquit(adm, argv[optind], argv[optind + 1]); 1854 if (err != 0) 1855 err = fmd_adm_rsrc_acquit(adm, argv[optind + 1], 1856 argv[optind]); 1857 } else { 1858 err = fmd_adm_case_acquit(adm, argv[optind]); 1859 if (err != 0) 1860 err = fmd_adm_rsrc_acquit(adm, argv[optind], ""); 1861 } 1862 1863 if (err != 0) 1864 die("failed to record acquital of %s", argv[optind]); 1865 1866 note("recorded acquital of %s\n", argv[optind]); 1867 return (FMADM_EXIT_SUCCESS); 1868 } 1869