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 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25 #include <alloca.h>
26
27 #include "libfmnotify.h"
28
29 /*ARGSUSED*/
30 void
31 nd_cleanup(nd_hdl_t *nhdl)
32 {
33 nd_debug(nhdl, "Cleaning up ...");
34 if (nhdl->nh_evhdl)
35 (void) fmev_shdl_fini(nhdl->nh_evhdl);
36
37 if (nhdl->nh_msghdl)
38 fmd_msg_fini(nhdl->nh_msghdl);
39
40 nhdl->nh_keep_running = B_FALSE;
41 (void) fclose(nhdl->nh_log_fd);
42 }
43
44 static void
241 scf_property_get_value(prop, value) == -1 ||
242 scf_value_get_boolean(value, val) == -1) {
243 nd_error(nhdl, "Failed to retrieve %s prop (%s)", propname,
244 scf_strerror(scf_error()));
245 goto bool_done;
246 }
247 ret = 0;
248
249 bool_done:
250 scf_value_destroy(value);
251 scf_property_destroy(prop);
252 scf_pg_destroy(pg);
253 scf_handle_destroy(handle);
254
255 return (ret);
256 }
257
258 char *
259 nd_get_event_fmri(nd_hdl_t *nhdl, fmev_t ev)
260 {
261 nvlist_t *ev_nvl, *attr_nvl;
262 char *svcname;
263
264 if ((ev_nvl = fmev_attr_list(ev)) == NULL) {
265 nd_error(nhdl, "Failed to lookup event attr nvlist");
266 return (NULL);
267 }
268 if (nvlist_lookup_nvlist(ev_nvl, "attr", &attr_nvl) ||
269 nvlist_lookup_string(attr_nvl, "svc-string", &svcname)) {
270 nd_error(nhdl, "Malformed event 0x%p", (void *)ev_nvl);
271 return (NULL);
272 }
273
274 return (strdup((const char *)svcname));
275 }
276
277 int
278 nd_get_notify_prefs(nd_hdl_t *nhdl, const char *mech, fmev_t ev,
279 nvlist_t ***pref_nvl, uint_t *nprefs)
280 {
281 nvlist_t *ev_nvl, *top_nvl, **np_nvlarr, *mech_nvl;
282 int ret = 1;
283 uint_t nelem;
284
285 if ((ev_nvl = fmev_attr_list(ev)) == NULL) {
286 nd_error(nhdl, "Failed to lookup event attr nvlist");
287 return (-1);
288 }
289
290 if ((ret = smf_notify_get_params(&top_nvl, ev_nvl)) != SCF_SUCCESS) {
291 ret = scf_error();
292 if (ret == SCF_ERROR_NOT_FOUND) {
293 nd_debug(nhdl, "No notification preferences specified "
294 "for this event");
494 nd_error(nhdl, "fm_dc_key2code failed for %s", key[0]);
495 ret = -1;
496 }
497 fm_dc_closedict(dhp);
498 return (ret);
499 }
500
501 /*
502 * This function takes an event and extracts the bits of the event payload that
503 * are of interest to notification daemons and conveniently tucks them into a
504 * single struct.
505 *
506 * The caller is responsible for freeing ev_info and any contained strings and
507 * nvlists. A convenience function, nd_free_event_info(), is provided for this
508 * purpose.
509 */
510 int
511 nd_get_event_info(nd_hdl_t *nhdl, const char *class, fmev_t ev,
512 nd_ev_info_t **ev_info)
513 {
514 nvlist_t *ev_nvl, *attr_nvl;
515 nd_ev_info_t *evi;
516 char *code, *uuid, *fmri, *from_state, *to_state, *reason;
517
518 if ((evi = calloc(1, sizeof (nd_ev_info_t))) == NULL) {
519 nd_error(nhdl, "Failed to allocate memory");
520 return (-1);
521 }
522
523 /*
524 * Hold event; class and payload will be valid for as long as
525 * we hold the event.
526 */
527 fmev_hold(ev);
528 evi->ei_ev = ev;
529 ev_nvl = fmev_attr_list(ev);
530
531 /*
532 * Lookup the MSGID, event description and severity and KA URL
533 *
534 * For FMA list.* events we just pull it out of the the event nvlist.
535 * For all other events we call a utility function that computes the
536 * diagcode using the dict name and class.
537 */
538 evi->ei_diagcode = calloc(32, sizeof (char));
539 if ((nvlist_lookup_string(ev_nvl, FM_SUSPECT_DIAG_CODE, &code) == 0 &&
540 strcpy(evi->ei_diagcode, code)) ||
541 nd_get_diagcode(nhdl, "SMF", class, evi->ei_diagcode, 32)
542 == 0) {
543 evi->ei_severity = fmd_msg_getitem_id(nhdl->nh_msghdl,
544 NULL, evi->ei_diagcode, FMD_MSG_ITEM_SEVERITY);
545 evi->ei_descr = fmd_msg_getitem_id(nhdl->nh_msghdl,
546 NULL, evi->ei_diagcode, FMD_MSG_ITEM_DESC);
547 evi->ei_url = fmd_msg_getitem_id(nhdl->nh_msghdl,
548 NULL, evi->ei_diagcode, FMD_MSG_ITEM_URL);
549 } else
550 (void) strcpy(evi->ei_diagcode, ND_UNKNOWN);
551
552 if (!evi->ei_severity)
553 evi->ei_severity = strdup(ND_UNKNOWN);
554 if (!evi->ei_descr)
555 evi->ei_descr = strdup(ND_UNKNOWN);
556 if (!evi->ei_url)
557 evi->ei_url = strdup(ND_UNKNOWN);
558
559 evi->ei_payload = ev_nvl;
560 evi->ei_class = fmev_class(ev);
561 if (nvlist_lookup_string(ev_nvl, FM_SUSPECT_UUID, &uuid) == 0)
562 evi->ei_uuid = strdup(uuid);
563 else {
564 nd_error(nhdl, "Malformed event");
565 nd_dump_nvlist(nhdl, evi->ei_payload);
566 nd_free_event_info(evi);
567 return (-1);
568 }
569
570 if (strncmp(class, "ireport.os.smf", 14) == 0) {
571 if ((fmri = nd_get_event_fmri(nhdl, ev)) == NULL) {
572 nd_error(nhdl, "Failed to get fmri from event payload");
573 nd_free_event_info(evi);
574 return (-1);
575 }
576 if (nvlist_lookup_nvlist(evi->ei_payload, "attr", &attr_nvl) ||
577 nvlist_lookup_string(attr_nvl, "from-state", &from_state) ||
578 nvlist_lookup_string(attr_nvl, "to-state", &to_state) ||
579 nvlist_lookup_string(attr_nvl, "reason-long", &reason)) {
580 nd_error(nhdl, "Malformed event");
581 nd_dump_nvlist(nhdl, evi->ei_payload);
582 nd_free_event_info(evi);
583 free(fmri);
584 return (-1);
585 }
586 evi->ei_fmri = fmri;
587 evi->ei_to_state = strdup(to_state);
588 evi->ei_from_state = strdup(from_state);
589 evi->ei_reason = strdup(reason);
590 }
591 *ev_info = evi;
592 return (0);
593 }
594
595 static void
596 condfree(void *buf)
597 {
598 if (buf != NULL)
599 free(buf);
600 }
601
602 void
603 nd_free_event_info(nd_ev_info_t *ev_info)
604 {
605 condfree(ev_info->ei_severity);
606 condfree(ev_info->ei_descr);
|
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 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Copyright 2018 Nexenta Systems, Inc.
28 */
29
30 #include <fm/libtopo.h>
31
32 #include <alloca.h>
33
34 #include "libfmnotify.h"
35
36 /*ARGSUSED*/
37 void
38 nd_cleanup(nd_hdl_t *nhdl)
39 {
40 nd_debug(nhdl, "Cleaning up ...");
41 if (nhdl->nh_evhdl)
42 (void) fmev_shdl_fini(nhdl->nh_evhdl);
43
44 if (nhdl->nh_msghdl)
45 fmd_msg_fini(nhdl->nh_msghdl);
46
47 nhdl->nh_keep_running = B_FALSE;
48 (void) fclose(nhdl->nh_log_fd);
49 }
50
51 static void
248 scf_property_get_value(prop, value) == -1 ||
249 scf_value_get_boolean(value, val) == -1) {
250 nd_error(nhdl, "Failed to retrieve %s prop (%s)", propname,
251 scf_strerror(scf_error()));
252 goto bool_done;
253 }
254 ret = 0;
255
256 bool_done:
257 scf_value_destroy(value);
258 scf_property_destroy(prop);
259 scf_pg_destroy(pg);
260 scf_handle_destroy(handle);
261
262 return (ret);
263 }
264
265 char *
266 nd_get_event_fmri(nd_hdl_t *nhdl, fmev_t ev)
267 {
268 nvlist_t *ev_nvl, *snvl;
269 nvlist_t **fnvl;
270 uint_t nnvl;
271 char *svcname;
272
273 if ((ev_nvl = fmev_attr_list(ev)) == NULL) {
274 nd_error(nhdl, "failed to lookup event nvlist");
275 return (NULL);
276 }
277
278 /* If this is an ireport, simply lookup svc-string */
279 if (nvlist_lookup_nvlist(ev_nvl, "attr", &snvl) == 0 &&
280 nvlist_lookup_string(snvl, "svc-string", &svcname) == 0)
281 return (strdup((const char *)svcname));
282
283 /* Otherwise extract the fault-list and use the first element */
284 if (nvlist_lookup_nvlist_array(ev_nvl, FM_SUSPECT_FAULT_LIST,
285 &fnvl, &nnvl) != 0 || nnvl != 1)
286 return (NULL);
287
288 /*
289 * NOTE: this should match the logic in libfmd_snmp.
290 *
291 * Use the following order of nested nvlists to make up FMRI:
292 * - FRU
293 * - ASRU
294 * - resource
295 */
296 if (nvlist_lookup_nvlist(fnvl[0], FM_FAULT_FRU, &snvl) == 0 ||
297 nvlist_lookup_nvlist(fnvl[0], FM_FAULT_ASRU, &snvl) == 0 ||
298 nvlist_lookup_nvlist(fnvl[0], FM_FAULT_RESOURCE, &snvl) == 0) {
299 topo_hdl_t *thp;
300 int topoerr;
301 char *fmri, *ret = NULL;
302
303 thp = topo_open(TOPO_VERSION, NULL, &topoerr);
304 if (thp == NULL)
305 return (NULL);
306
307 if (topo_fmri_nvl2str(thp, snvl, &fmri, &topoerr) == 0) {
308 ret = strdup(fmri);
309 topo_hdl_strfree(thp, fmri);
310 }
311
312 topo_close(thp);
313 return (ret);
314 }
315
316 return (NULL);
317 }
318
319 int
320 nd_get_notify_prefs(nd_hdl_t *nhdl, const char *mech, fmev_t ev,
321 nvlist_t ***pref_nvl, uint_t *nprefs)
322 {
323 nvlist_t *ev_nvl, *top_nvl, **np_nvlarr, *mech_nvl;
324 int ret = 1;
325 uint_t nelem;
326
327 if ((ev_nvl = fmev_attr_list(ev)) == NULL) {
328 nd_error(nhdl, "Failed to lookup event attr nvlist");
329 return (-1);
330 }
331
332 if ((ret = smf_notify_get_params(&top_nvl, ev_nvl)) != SCF_SUCCESS) {
333 ret = scf_error();
334 if (ret == SCF_ERROR_NOT_FOUND) {
335 nd_debug(nhdl, "No notification preferences specified "
336 "for this event");
536 nd_error(nhdl, "fm_dc_key2code failed for %s", key[0]);
537 ret = -1;
538 }
539 fm_dc_closedict(dhp);
540 return (ret);
541 }
542
543 /*
544 * This function takes an event and extracts the bits of the event payload that
545 * are of interest to notification daemons and conveniently tucks them into a
546 * single struct.
547 *
548 * The caller is responsible for freeing ev_info and any contained strings and
549 * nvlists. A convenience function, nd_free_event_info(), is provided for this
550 * purpose.
551 */
552 int
553 nd_get_event_info(nd_hdl_t *nhdl, const char *class, fmev_t ev,
554 nd_ev_info_t **ev_info)
555 {
556 nvlist_t *attr_nvl;
557 nd_ev_info_t *evi;
558 char *code, *uuid, *from_state, *to_state, *reason;
559
560 if ((evi = calloc(1, sizeof (nd_ev_info_t))) == NULL) {
561 nd_error(nhdl, "Failed to allocate memory");
562 return (-1);
563 }
564
565 /*
566 * Hold event; class and payload will be valid for as long as
567 * we hold the event.
568 */
569 fmev_hold(ev);
570
571 evi->ei_ev = ev;
572 evi->ei_class = fmev_class(ev);
573 evi->ei_payload = fmev_attr_list(ev);
574
575 if (nvlist_lookup_string(evi->ei_payload, FM_SUSPECT_UUID,
576 &uuid) == 0) {
577 evi->ei_uuid = strdup(uuid);
578 } else {
579 nd_error(nhdl, "Malformed event");
580 nd_dump_nvlist(nhdl, evi->ei_payload);
581 nd_free_event_info(evi);
582 return (-1);
583 }
584
585 /*
586 * Lookup the MSGID, type, severity, description, and KA URL.
587 *
588 * For FMA list.* events we just pull it out of the the event nvlist.
589 * For all other events we call a utility function that computes the
590 * diagcode using the dict name and class.
591 */
592 evi->ei_diagcode = calloc(32, sizeof (char));
593 if ((nvlist_lookup_string(evi->ei_payload, FM_SUSPECT_DIAG_CODE,
594 &code) == 0 && strcpy(evi->ei_diagcode, code) != NULL) ||
595 nd_get_diagcode(nhdl, "SMF", class, evi->ei_diagcode, 32) == 0) {
596 evi->ei_type = fmd_msg_getitem_id(nhdl->nh_msghdl,
597 NULL, evi->ei_diagcode, FMD_MSG_ITEM_TYPE);
598 evi->ei_severity = fmd_msg_getitem_id(nhdl->nh_msghdl,
599 NULL, evi->ei_diagcode, FMD_MSG_ITEM_SEVERITY);
600 evi->ei_descr = fmd_msg_getitem_id(nhdl->nh_msghdl,
601 NULL, evi->ei_diagcode, FMD_MSG_ITEM_DESC);
602 evi->ei_url = fmd_msg_getitem_id(nhdl->nh_msghdl,
603 NULL, evi->ei_diagcode, FMD_MSG_ITEM_URL);
604 } else
605 (void) strcpy(evi->ei_diagcode, ND_UNKNOWN);
606
607 if (evi->ei_type == NULL)
608 evi->ei_type = strdup(ND_UNKNOWN);
609 if (evi->ei_severity == NULL)
610 evi->ei_severity = strdup(ND_UNKNOWN);
611 if (evi->ei_descr == NULL)
612 evi->ei_descr = strdup(ND_UNKNOWN);
613 if (evi->ei_url == NULL)
614 evi->ei_url = strdup(ND_UNKNOWN);
615
616 if ((evi->ei_fmri = nd_get_event_fmri(nhdl, ev)) == NULL)
617 evi->ei_fmri = strdup(ND_UNKNOWN);
618
619 if (strncmp(class, "ireport.os.smf", 14) == 0) {
620 if (nvlist_lookup_nvlist(evi->ei_payload, "attr",
621 &attr_nvl) != 0 ||
622 nvlist_lookup_string(attr_nvl, "from-state",
623 &from_state) != 0 ||
624 nvlist_lookup_string(attr_nvl, "to-state",
625 &to_state) != 0 ||
626 nvlist_lookup_string(attr_nvl, "reason-long",
627 &reason) != 0) {
628 nd_error(nhdl, "Malformed event");
629 nd_dump_nvlist(nhdl, evi->ei_payload);
630 nd_free_event_info(evi);
631 return (-1);
632 }
633 evi->ei_to_state = strdup(to_state);
634 evi->ei_from_state = strdup(from_state);
635 evi->ei_reason = strdup(reason);
636 }
637 *ev_info = evi;
638 return (0);
639 }
640
641 static void
642 condfree(void *buf)
643 {
644 if (buf != NULL)
645 free(buf);
646 }
647
648 void
649 nd_free_event_info(nd_ev_info_t *ev_info)
650 {
651 condfree(ev_info->ei_severity);
652 condfree(ev_info->ei_descr);
|