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