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

--- 41 unchanged lines hidden ---
1910}
1911
1912int
1913cmd_flush(fmd_adm_t *adm, int argc, char *argv[])
1914{
1915 int i, status = FMADM_EXIT_SUCCESS;
1916
1917 if (argc < 2 || (i = getopt(argc, argv, "")) != EOF)

--- 41 unchanged lines hidden ---