Print this page
NEX-17829 libfmd_snmp and snmp-notify should provide FMRIs for all fault types
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-16536 SUN-IREPORT-MIB is broken
NEX-16537 enhance FM traps
NEX-16545 SMF dict should have obsolete entries removed
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>


   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);