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