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 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <sys/fm/protocol.h>
  28 #include <fm/fmd_adm.h>
  29 #include <fm/fmd_snmp.h>
  30 #include <net-snmp/net-snmp-config.h>
  31 #include <net-snmp/net-snmp-includes.h>
  32 #include <net-snmp/agent/net-snmp-agent-includes.h>
  33 #include <pthread.h>
  34 #include <stddef.h>
  35 #include <errno.h>
  36 #include <alloca.h>
  37 #include <locale.h>
  38 #include <libuutil.h>
  39 #include <libnvpair.h>
  40 #include "sunFM_impl.h"
  41 #include "problem.h"
  42 
  43 /*
  44  * We assume that the number of suspect fault events associated with a
  45  * particular case will generally be sufficiently small that the overhead
  46  * associated with indexing them in a tree would exceed the gain from
  47  * not traversing the fault list for each request.
  48  */
  49 static uu_avl_pool_t    *problem_uuid_avl_pool;
  50 static uu_avl_t         *problem_uuid_avl;
  51 
  52 #define VALID_AVL_STATE (problem_uuid_avl_pool != NULL &&       \
  53         problem_uuid_avl != NULL)
  54 
  55 #define UPDATE_WAIT_MILLIS      10      /* poll interval in milliseconds */
  56 
  57 /*
  58  * Update types.  Single-index and all are mutually exclusive.
  59  */
  60 #define UCT_INDEX       0x1
  61 #define UCT_ALL         0x2
  62 #define UCT_FLAGS       0x3
  63 
  64 /*
  65  * Locking strategy is described in module.c.
  66  */
  67 static int              valid_stamp;
  68 static pthread_mutex_t  update_lock;
  69 static pthread_cond_t   update_cv;
  70 static volatile enum { US_QUIET, US_NEEDED, US_INPROGRESS } update_status;
  71 
  72 static Netsnmp_Node_Handler     sunFmProblemTable_handler;
  73 static Netsnmp_Node_Handler     sunFmFaultEventTable_handler;
  74 
  75 static sunFmProblem_data_t *
  76 problem_key_build(const char *uuid)
  77 {
  78         static sunFmProblem_data_t      key;
  79 
  80         key.d_aci_uuid = uuid;
  81 
  82         return (&key);
  83 }
  84 
  85 static sunFmProblem_data_t *
  86 problem_lookup_uuid_exact(const char *uuid)
  87 {
  88         sunFmProblem_data_t     *key, *data;
  89 
  90         key = problem_key_build(uuid);
  91 
  92         DEBUGMSGTL((MODNAME_STR, "lookup_exact for uuid %s\n", uuid));
  93         data = uu_avl_find(problem_uuid_avl, key, NULL, NULL);
  94 
 
 123                 return (NULL);
 124 
 125         return (data->d_suspects[index - 1]);
 126 }
 127 
 128 static sunFmFaultStatus_data_t
 129 faultstatus_lookup_index_exact(sunFmProblem_data_t *data, ulong_t index)
 130 {
 131         if (index > data->d_nsuspects)
 132                 return (0);
 133 
 134         if (data->d_statuses == NULL)
 135                 return (0);
 136 
 137         if (data->d_valid != valid_stamp)
 138                 return (0);
 139 
 140         return (data->d_statuses[index - 1]);
 141 }
 142 
 143 /*ARGSUSED*/
 144 static int
 145 problem_update_one(const fmd_adm_caseinfo_t *acp, void *arg)
 146 {
 147         sunFmProblem_data_t             *data;
 148         nvlist_t                        *nvl;
 149         int64_t                         *diag_time;
 150         uint_t                          nelem;
 151         uint32_t                        nsusp;
 152         int                             err;
 153 
 154         DEBUGMSGTL((MODNAME_STR, "update_one\n"));
 155 
 156         ASSERT(acp->aci_uuid != NULL);
 157 
 158         if ((data = problem_lookup_uuid_exact(acp->aci_uuid)) == NULL) {
 159                 uu_avl_index_t idx;
 160 
 161                 DEBUGMSGTL((MODNAME_STR, "found new problem %s\n",
 162                     acp->aci_uuid));
 163                 if ((data = SNMP_MALLOC_TYPEDEF(sunFmProblem_data_t)) == NULL) {
 164                         (void) snmp_log(LOG_ERR, MODNAME_STR ": Out of memory "
 165                             "for new problem data at %s:%d\n", __FILE__,
 166                             __LINE__);
 167                         return (0);
 168                 }
 169                 if ((err = nvlist_dup(acp->aci_event, &data->d_aci_event, 0))
 170                     != 0) {
 171                         (void) snmp_log(LOG_ERR, MODNAME_STR ": Problem data "
 172                             "setup failed: %s\n", strerror(err));
 173                         SNMP_FREE(data);
 174                         return (0);
 175                 }
 176 
 177                 data->d_aci_uuid = data->d_aci_code = data->d_aci_url = "-";
 178                 (void) nvlist_lookup_string(data->d_aci_event, FM_SUSPECT_UUID,
 179                     (char **)&data->d_aci_uuid);
 180                 (void) nvlist_lookup_string(data->d_aci_event,
 181                     FM_SUSPECT_DIAG_CODE, (char **)&data->d_aci_code);
 182                 data->d_aci_url = strdup(acp->aci_url);
 183 
 184                 if (nvlist_lookup_nvlist(data->d_aci_event, FM_SUSPECT_DE,
 185                     &nvl) == 0)
 186                         if ((data->d_diag_engine = sunFm_nvl2str(nvl)) == NULL)
 187                                 data->d_diag_engine = "-";
 188 
 189                 if (nvlist_lookup_int64_array(data->d_aci_event,
 190                     FM_SUSPECT_DIAG_TIME, &diag_time, &nelem) == 0 &&
 191                     nelem >= 2) {
 192                         data->d_diag_time.tv_sec = (long)diag_time[0];
 193                         data->d_diag_time.tv_usec = (long)diag_time[1];
 194                 }
 195 
 196                 (void) nvlist_lookup_uint32(data->d_aci_event,
 197                     FM_SUSPECT_FAULT_SZ, &nsusp);
 198                 data->d_nsuspects = (ulong_t)nsusp;
 199 
 200                 (void) nvlist_lookup_nvlist_array(data->d_aci_event,
 201                     FM_SUSPECT_FAULT_LIST, &data->d_suspects, &nelem);
 202 
 203                 ASSERT(nelem == data->d_nsuspects);
 204 
 205                 (void) nvlist_lookup_uint8_array(data->d_aci_event,
 206                     FM_SUSPECT_FAULT_STATUS, &data->d_statuses, &nelem);
 207 
 208                 ASSERT(nelem == data->d_nsuspects);
 209 
 210                 uu_avl_node_init(data, &data->d_uuid_avl,
 211                     problem_uuid_avl_pool);
 212                 (void) uu_avl_find(problem_uuid_avl, data, NULL, &idx);
 213                 uu_avl_insert(problem_uuid_avl, data, idx);
 214 
 215                 data->d_valid = valid_stamp;
 216 
 217                 DEBUGMSGTL((MODNAME_STR, "completed new problem %s@%p\n",
 218                     data->d_aci_uuid, data));
 219         } else {
 220                 uint8_t *statuses;
 221                 int i;
 222 
 223                 (void) nvlist_lookup_uint8_array(acp->aci_event,
 224                     FM_SUSPECT_FAULT_STATUS, &statuses, &nelem);
 225 
 226                 ASSERT(nelem == data->d_nsuspects);
 227 
 228                 for (i = 0; i < nelem; i++)
 229                         data->d_statuses[i] = statuses[i];
 230 
 231                 data->d_valid = valid_stamp;
 232         }
 233 
 234         /*
 235          * We don't touch problems we've seen before; they shouldn't change
 236          * in any way we care about, since they've already been solved.  The
 237          * state, however, could change, and if we later expose that to the
 238          * client we need to update it here.
 239          */
 240 
 241         return (0);
 242 }
 243 
 244 static int
 245 problem_update(sunFmProblem_update_ctx_t *update_ctx)
 246 {
 247         fmd_adm_t *adm;
 248 
 249         ASSERT(update_ctx != NULL);
 250         ASSERT((update_ctx->uc_type & (UCT_INDEX|UCT_ALL)) !=
 251             (UCT_INDEX|UCT_ALL));
 252         ASSERT((update_ctx->uc_type & ~UCT_FLAGS) == 0);
 253         ASSERT(VALID_AVL_STATE);
 254 
 255         if ((adm = fmd_adm_open(update_ctx->uc_host, update_ctx->uc_prog,
 256             update_ctx->uc_version)) == NULL) {
 257                 (void) snmp_log(LOG_ERR, MODNAME_STR ": Communication with fmd "
 258                     "failed: %s\n", strerror(errno));
 259                 return (SNMP_ERR_RESOURCEUNAVAILABLE);
 260         }
 261 
 262         ++valid_stamp;
 263         if (fmd_adm_case_iter(adm, SNMP_URL_MSG, problem_update_one,
 264             update_ctx) != 0) {
 265                 (void) snmp_log(LOG_ERR, MODNAME_STR ": fmd case information "
 266                     "update failed: %s\n", fmd_adm_errmsg(adm));
 267                 fmd_adm_close(adm);
 268                 return (SNMP_ERR_RESOURCEUNAVAILABLE);
 269         }
 270 
 271         DEBUGMSGTL((MODNAME_STR, "case iteration completed\n"));
 272 
 273         fmd_adm_close(adm);
 274         return (SNMP_ERR_NOERROR);
 275 }
 276 
 277 /*ARGSUSED*/
 278 static void
 279 update_thread(void *arg)
 280 {
 281         /*
 282          * The current problem_update implementation offers minimal savings
 283          * for the use of index-only updates; therefore we always do a full
 284          * update.  If it becomes advantageous to limit updates to a single
 285          * index, the contexts can be queued by the handler instead.
 286          */
 287         sunFmProblem_update_ctx_t       uc;
 288 
 289         uc.uc_host = NULL;
 290         uc.uc_prog = FMD_ADM_PROGRAM;
 291         uc.uc_version = FMD_ADM_VERSION;
 292 
 293         uc.uc_index = NULL;
 294         uc.uc_type = UCT_ALL;
 295 
 296         for (;;) {
 297                 (void) pthread_mutex_lock(&update_lock);
 298                 update_status = US_QUIET;
 299                 while (update_status == US_QUIET)
 300                         (void) pthread_cond_wait(&update_cv, &update_lock);
 301                 update_status = US_INPROGRESS;
 302                 (void) pthread_mutex_unlock(&update_lock);
 303                 (void) problem_update(&uc);
 304         }
 305 }
 306 
 307 static void
 308 request_update(void)
 309 {
 310         (void) pthread_mutex_lock(&update_lock);
 311         if (update_status != US_QUIET) {
 312                 (void) pthread_mutex_unlock(&update_lock);
 313                 return;
 314         }
 315         update_status = US_NEEDED;
 316         (void) pthread_cond_signal(&update_cv);
 317         (void) pthread_mutex_unlock(&update_lock);
 318 }
 319 
 320 /*ARGSUSED*/
 321 static int
 322 problem_compare_uuid(const void *l, const void *r, void *private)
 323 {
 324         sunFmProblem_data_t     *l_data = (sunFmProblem_data_t *)l;
 325         sunFmProblem_data_t     *r_data = (sunFmProblem_data_t *)r;
 326 
 327         ASSERT(l_data != NULL && r_data != NULL);
 328 
 329         return (strcmp(l_data->d_aci_uuid, r_data->d_aci_uuid));
 330 }
 331 
 332 int
 333 sunFmProblemTable_init(void)
 334 {
 335         static oid sunFmProblemTable_oid[] = { SUNFMPROBLEMTABLE_OID };
 336         netsnmp_table_registration_info *table_info;
 337         netsnmp_handler_registration *handler;
 338         int err;
 339 
 340         if ((err = pthread_mutex_init(&update_lock, NULL)) != 0) {
 341                 (void) snmp_log(LOG_ERR, MODNAME_STR ": mutex_init failure: "
 342                     "%s\n", strerror(err));
 343                 return (MIB_REGISTRATION_FAILED);
 344         }
 345         if ((err = pthread_cond_init(&update_cv, NULL)) != 0) {
 346                 (void) snmp_log(LOG_ERR, MODNAME_STR ": cond_init failure: "
 347                     "%s\n", strerror(err));
 348                 return (MIB_REGISTRATION_FAILED);
 349         }
 350 
 351         if ((err = pthread_create(NULL, NULL, (void *(*)(void *))update_thread,
 352             NULL)) != 0) {
 353                 (void) snmp_log(LOG_ERR, MODNAME_STR ": error creating update "
 354                     "thread: %s\n", strerror(err));
 355                 return (MIB_REGISTRATION_FAILED);
 356         }
 357 
 358         if ((table_info =
 359             SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL)
 360                 return (MIB_REGISTRATION_FAILED);
 361 
 362         if ((handler = netsnmp_create_handler_registration("sunFmProblemTable",
 363             sunFmProblemTable_handler, sunFmProblemTable_oid,
 364             OID_LENGTH(sunFmProblemTable_oid), HANDLER_CAN_RONLY)) == NULL) {
 365                 SNMP_FREE(table_info);
 366                 return (MIB_REGISTRATION_FAILED);
 367         }
 368 
 369         /*
 370          * The Net-SNMP template uses add_indexes here, but that
 371          * function is unsafe because it does not check for failure.
 372          */
 373         if (netsnmp_table_helper_add_index(table_info, ASN_OCTET_STR) == NULL) {
 374                 SNMP_FREE(table_info);
 375                 SNMP_FREE(handler);
 376                 return (MIB_REGISTRATION_FAILED);
 377         }
 378 
 379         table_info->min_column = SUNFMPROBLEM_COLMIN;
 380         table_info->max_column = SUNFMPROBLEM_COLMAX;
 381 
 382         if ((problem_uuid_avl_pool = uu_avl_pool_create("problem_uuid",
 383             sizeof (sunFmProblem_data_t),
 384             offsetof(sunFmProblem_data_t, d_uuid_avl), problem_compare_uuid,
 385             UU_AVL_DEBUG)) == NULL) {
 386                 (void) snmp_log(LOG_ERR, MODNAME_STR ": problem_uuid avl pool "
 387                     "creation failed: %s\n", uu_strerror(uu_error()));
 388                 snmp_free_varbind(table_info->indexes);
 389                 SNMP_FREE(table_info);
 390                 SNMP_FREE(handler);
 391                 return (MIB_REGISTRATION_FAILED);
 392         }
 393 
 394         if ((problem_uuid_avl = uu_avl_create(problem_uuid_avl_pool, NULL,
 395             UU_AVL_DEBUG)) == NULL) {
 396                 (void) snmp_log(LOG_ERR, MODNAME_STR ": problem_uuid avl "
 397                     "creation failed: %s\n", uu_strerror(uu_error()));
 398                 snmp_free_varbind(table_info->indexes);
 399                 SNMP_FREE(table_info);
 400                 SNMP_FREE(handler);
 401                 uu_avl_pool_destroy(problem_uuid_avl_pool);
 402                 return (MIB_REGISTRATION_FAILED);
 403         }
 404 
 405         if ((err = netsnmp_register_table(handler, table_info)) !=
 406             MIB_REGISTERED_OK) {
 407                 snmp_free_varbind(table_info->indexes);
 408                 SNMP_FREE(table_info);
 409                 SNMP_FREE(handler);
 410                 uu_avl_destroy(problem_uuid_avl);
 411                 uu_avl_pool_destroy(problem_uuid_avl_pool);
 412                 return (err);
 413         }
 414 
 415         return (MIB_REGISTERED_OK);
 416 }
 417 
 418 int
 419 sunFmFaultEventTable_init(void)
 420 {
 421         static oid sunFmFaultEventTable_oid[] = { SUNFMFAULTEVENTTABLE_OID };
 422         netsnmp_table_registration_info *table_info;
 423         netsnmp_handler_registration *handler;
 424         int err;
 425 
 426         if ((table_info =
 427             SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL)
 428                 return (MIB_REGISTRATION_FAILED);
 429 
 430         if ((handler =
 431             netsnmp_create_handler_registration("sunFmFaultEventTable",
 432             sunFmFaultEventTable_handler, sunFmFaultEventTable_oid,
 433             OID_LENGTH(sunFmFaultEventTable_oid), HANDLER_CAN_RONLY)) == NULL) {
 434                 SNMP_FREE(table_info);
 435                 return (MIB_REGISTRATION_FAILED);
 436         }
 437 
 438         /*
 439          * The Net-SNMP template uses add_indexes here, but that
 440          * function is unsafe because it does not check for failure.
 441          */
 442         if (netsnmp_table_helper_add_index(table_info, ASN_OCTET_STR) == NULL) {
 443                 SNMP_FREE(table_info);
 444                 SNMP_FREE(handler);
 445                 return (MIB_REGISTRATION_FAILED);
 446         }
 447         if (netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED) == NULL) {
 448                 snmp_free_varbind(table_info->indexes);
 449                 SNMP_FREE(table_info);
 450                 SNMP_FREE(handler);
 451                 return (MIB_REGISTRATION_FAILED);
 452         }
 453 
 454         table_info->min_column = SUNFMFAULTEVENT_COLMIN;
 455         table_info->max_column = SUNFMFAULTEVENT_COLMAX;
 456 
 457         if ((err = netsnmp_register_table(handler, table_info)) !=
 458             MIB_REGISTERED_OK) {
 459                 snmp_free_varbind(table_info->indexes);
 460                 SNMP_FREE(table_info);
 461                 SNMP_FREE(handler);
 462                 return (err);
 463         }
 464 
 465         return (MIB_REGISTERED_OK);
 466 }
 467 
 468 /*
 469  * Returns the problem data for the problem whose uuid is next according
 470  * to ASN.1 lexical ordering after the request in table_info.  Indexes are
 471  * updated to reflect the OID of the value being returned.  This allows
 472  * us to implement GETNEXT.
 473  */
 474 static sunFmProblem_data_t *
 475 sunFmProblemTable_nextpr(netsnmp_handler_registration *reginfo,
 476     netsnmp_table_request_info *table_info)
 477 {
 478         sunFmProblem_data_t     *data;
 479         char                    *uuid = "";
 480 
 481         if (table_info->number_indexes < 1) {
 482                 oid tmpoid[MAX_OID_LEN];
 483 
 484                 DEBUGMSGTL((MODNAME_STR, "nextpr: no indexes given\n"));
 485 
 486                 snmp_free_varbind(table_info->indexes);
 487                 table_info->indexes =
 488                     SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
 489                 (void) snmp_set_var_typed_value(table_info->indexes,
 490                     ASN_OCTET_STR, (const uchar_t *)uuid, 0);
 491                 (void) memcpy(tmpoid, reginfo->rootoid,
 492                     reginfo->rootoid_len * sizeof (oid));
 493                 tmpoid[reginfo->rootoid_len] = 1;
 494                 tmpoid[reginfo->rootoid_len + 1] = table_info->colnum;
 495                 if (build_oid_segment(table_info->indexes) != SNMPERR_SUCCESS) {
 496                         snmp_free_varbind(table_info->indexes);
 497                         return (NULL);
 498                 }
 499                 table_info->number_indexes = 1;
 500                 table_info->index_oid_len = table_info->indexes->name_length;
 501                 (void) memcpy(table_info->index_oid, table_info->indexes->name,
 502                     table_info->indexes->name_length);
 503 
 504                 DEBUGMSGTL((MODNAME_STR, "nextpr: built fake index:\n"));
 505                 DEBUGMSGVAR((MODNAME_STR, table_info->indexes));
 506                 DEBUGMSG((MODNAME_STR, "\n"));
 507         } else {
 508                 /*
 509                  * Construct the next possible UUID to look for.  We can
 510                  * simply increment the least significant byte of the last
 511                  * UUID because (a) that preserves SNMP lex order and (b)
 512                  * the characters that may appear in a UUID do not include
 513                  * 127 nor 255.
 514                  */
 515                 uuid = alloca(table_info->indexes->val_len + 1);
 516                 (void) strlcpy(uuid,
 517                     (const char *)table_info->indexes->val.string,
 518                     table_info->indexes->val_len + 1);
 519                 ++uuid[table_info->indexes->val_len - 1];
 520 
 521                 DEBUGMSGTL((MODNAME_STR, "nextpr: received index:\n"));
 522                 DEBUGMSGVAR((MODNAME_STR, table_info->indexes));
 523                 DEBUGMSG((MODNAME_STR, "\n"));
 524         }
 
 632                                 DEBUGMSGVAR((MODNAME_STR, table_info->indexes));
 633                                 DEBUGMSG((MODNAME_STR, "\n"));
 634                                 var =
 635                                     SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
 636                                 (void) snmp_set_var_typed_value(var,
 637                                     ASN_UNSIGNED, (uchar_t *)&index,
 638                                     sizeof (index));
 639                                 (void) memcpy(tmpoid, reginfo->rootoid,
 640                                     reginfo->rootoid_len * sizeof (oid));
 641                                 tmpoid[reginfo->rootoid_len] = 1;
 642                                 tmpoid[reginfo->rootoid_len + 1] =
 643                                     table_info->colnum;
 644                                 if (build_oid_segment(var) != SNMPERR_SUCCESS) {
 645                                         snmp_free_varbind(var);
 646                                         return (NULL);
 647                                 }
 648                                 snmp_free_varbind(
 649                                     table_info->indexes->next_variable);
 650                                 table_info->indexes->next_variable = var;
 651                                 table_info->number_indexes = 2;
 652                                 DEBUGMSGTL((MODNAME_STR, "nextfe: built fake "
 653                                     "index:\n"));
 654                                 DEBUGMSGVAR((MODNAME_STR, table_info->indexes));
 655                                 DEBUGMSG((MODNAME_STR, "\n"));
 656                                 DEBUGMSGVAR((MODNAME_STR,
 657                                     table_info->indexes->next_variable));
 658                                 DEBUGMSG((MODNAME_STR, "\n"));
 659                         } else {
 660                                 if (sunFmProblemTable_nextpr(reginfo,
 661                                     table_info) == NULL)
 662                                         return (NULL);
 663                         }
 664                         break;
 665                 case 0:
 666                         if (sunFmProblemTable_nextpr(reginfo, table_info) ==
 667                             NULL)
 668                                 return (NULL);
 669                         break;
 670                 }
 671         }
 672 }
 673 
 674 static sunFmFaultEvent_data_t *
 675 sunFmFaultEventTable_fe(netsnmp_handler_registration *reginfo,
 676     netsnmp_table_request_info *table_info, sunFmFaultStatus_data_t *statusp)
 677 {
 678         sunFmProblem_data_t     *data;
 679 
 680         ASSERT(table_info->number_indexes == 2);
 681 
 682         if ((data = sunFmProblemTable_pr(reginfo, table_info)) == NULL)
 683                 return (NULL);
 684 
 685         *statusp = faultstatus_lookup_index_exact(data,
 686             *(ulong_t *)table_info->indexes->next_variable->val.integer);
 687         if (*statusp == 0)
 688                 return (NULL);
 689         return (faultevent_lookup_index_exact(data,
 690             *(ulong_t *)table_info->indexes->next_variable->val.integer));
 691 }
 692 
 693 /*ARGSUSED*/
 694 static void
 695 sunFmProblemTable_return(unsigned int reg, void *arg)
 696 {
 697         netsnmp_delegated_cache         *cache = (netsnmp_delegated_cache *)arg;
 698         netsnmp_request_info            *request;
 699         netsnmp_agent_request_info      *reqinfo;
 700         netsnmp_handler_registration    *reginfo;
 701         netsnmp_table_request_info      *table_info;
 702         sunFmProblem_data_t             *data;
 703 
 704         ASSERT(netsnmp_handler_check_cache(cache) != NULL);
 705 
 706         (void) pthread_mutex_lock(&update_lock);
 707         if (update_status != US_QUIET) {
 708                 struct timeval                  tv;
 709 
 710                 tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 711                 tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
 712 
 713                 (void) snmp_alarm_register_hr(tv, 0, sunFmProblemTable_return,
 714                     cache);
 715                 (void) pthread_mutex_unlock(&update_lock);
 716                 return;
 717         }
 718 
 719         request = cache->requests;
 720         reqinfo = cache->reqinfo;
 721         reginfo = cache->reginfo;
 722 
 723         table_info = netsnmp_extract_table_info(request);
 724         request->delegated = 0;
 725 
 726         ASSERT(table_info->colnum >= SUNFMPROBLEM_COLMIN);
 727         ASSERT(table_info->colnum <= SUNFMPROBLEM_COLMAX);
 728 
 729         /*
 730          * table_info->colnum contains the column number requested.
 731          * table_info->indexes contains a linked list of snmp variable
 732          * bindings for the indexes of the table.  Values in the list
 733          * have been set corresponding to the indexes of the
 734          * request.  We have other guarantees as well:
 735          *
 736          * - The column number is always within range.
 737          * - If we have no index data, table_info->index_oid_len is 0.
 738          * - We will never receive requests outside our table nor
 739          *   those with the first subid anything other than 1 (Entry)
 740          *   nor those without a column number.  This is true even
 741          *   for GETNEXT requests.
 742          */
 743 
 744         switch (reqinfo->mode) {
 745         case MODE_GET:
 746                 if ((data = sunFmProblemTable_pr(reginfo, table_info)) ==
 747                     NULL) {
 748                         netsnmp_free_delegated_cache(cache);
 749                         (void) pthread_mutex_unlock(&update_lock);
 750                         return;
 751                 }
 752                 break;
 753         case MODE_GETNEXT:
 754         case MODE_GETBULK:
 755                 if ((data = sunFmProblemTable_nextpr(reginfo, table_info)) ==
 756                     NULL) {
 757                         netsnmp_free_delegated_cache(cache);
 758                         (void) pthread_mutex_unlock(&update_lock);
 759                         return;
 760                 }
 761                 break;
 762         default:
 763                 (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request "
 764                     "mode %d\n", reqinfo->mode);
 765                 netsnmp_free_delegated_cache(cache);
 766                 (void) pthread_mutex_unlock(&update_lock);
 767                 return;
 768         }
 769 
 770         switch (table_info->colnum) {
 771         case SUNFMPROBLEM_COL_UUID:
 772         {
 773                 (void) netsnmp_table_build_result(reginfo, request, table_info,
 774                     ASN_OCTET_STR, (uchar_t *)data->d_aci_uuid,
 775                     strlen(data->d_aci_uuid));
 776                 break;
 777         }
 778         case SUNFMPROBLEM_COL_CODE:
 779         {
 780                 (void) netsnmp_table_build_result(reginfo, request, table_info,
 781                     ASN_OCTET_STR, (uchar_t *)data->d_aci_code,
 782                     strlen(data->d_aci_code));
 783                 break;
 784         }
 785         case SUNFMPROBLEM_COL_URL:
 786         {
 787                 (void) netsnmp_table_build_result(reginfo, request, table_info,
 788                     ASN_OCTET_STR, (uchar_t *)data->d_aci_url,
 789                     strlen(data->d_aci_url));
 790                 break;
 791         }
 792         case SUNFMPROBLEM_COL_DIAGENGINE:
 793         {
 794                 (void) netsnmp_table_build_result(reginfo, request, table_info,
 795                     ASN_OCTET_STR, (uchar_t *)data->d_diag_engine,
 796                     strlen(data->d_diag_engine));
 797                 break;
 798         }
 799         case SUNFMPROBLEM_COL_DIAGTIME:
 800         {
 801                 /*
 802                  * The date_n_time function is not Y2038-safe; this may
 803                  * need to be updated when a suitable Y2038-safe Net-SNMP
 804                  * API is available.
 805                  */
 806                 size_t  dt_size;
 807                 time_t  dt_time = (time_t)data->d_diag_time.tv_sec;
 808                 uchar_t *dt = date_n_time(&dt_time, &dt_size);
 809 
 810                 (void) netsnmp_table_build_result(reginfo, request, table_info,
 811                     ASN_OCTET_STR, dt, dt_size);
 812                 break;
 813         }
 814         case SUNFMPROBLEM_COL_SUSPECTCOUNT:
 815         {
 816                 (void) netsnmp_table_build_result(reginfo, request, table_info,
 817                     ASN_UNSIGNED, (uchar_t *)&data->d_nsuspects,
 818                     sizeof (data->d_nsuspects));
 819                 break;
 820         }
 821         default:
 822                 break;
 823         }
 824 
 825         netsnmp_free_delegated_cache(cache);
 826         (void) pthread_mutex_unlock(&update_lock);
 827 }
 828 
 829 static int
 830 sunFmProblemTable_handler(netsnmp_mib_handler *handler,
 831     netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
 832     netsnmp_request_info *requests)
 833 {
 834         netsnmp_request_info            *request;
 835         struct timeval                  tv;
 836 
 837         tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 838         tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
 839 
 840         request_update();
 841 
 842         for (request = requests; request; request = request->next) {
 843                 if (request->processed != 0)
 844                         continue;
 845 
 846                 if (netsnmp_extract_table_info(request) == NULL)
 847                         continue;
 848 
 849                 request->delegated = 1;
 850                 (void) snmp_alarm_register_hr(tv, 0,
 851                     sunFmProblemTable_return,
 852                     (void *) netsnmp_create_delegated_cache(handler, reginfo,
 853                     reqinfo, request, NULL));
 854         }
 855 
 856         return (SNMP_ERR_NOERROR);
 857 }
 858 
 859 /*ARGSUSED*/
 860 static void
 861 sunFmFaultEventTable_return(unsigned int reg, void *arg)
 862 {
 863         netsnmp_delegated_cache         *cache = (netsnmp_delegated_cache *)arg;
 864         netsnmp_request_info            *request;
 865         netsnmp_agent_request_info      *reqinfo;
 866         netsnmp_handler_registration    *reginfo;
 867         netsnmp_table_request_info      *table_info;
 868         sunFmProblem_data_t             *pdata;
 869         sunFmFaultEvent_data_t          *data;
 870         sunFmFaultStatus_data_t         status;
 871 
 872         ASSERT(netsnmp_handler_check_cache(cache) != NULL);
 873 
 874         (void) pthread_mutex_lock(&update_lock);
 875         if (update_status != US_QUIET) {
 876                 struct timeval                  tv;
 877 
 878                 tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 879                 tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
 880 
 881                 (void) snmp_alarm_register_hr(tv, 0,
 882                     sunFmFaultEventTable_return, cache);
 883                 (void) pthread_mutex_unlock(&update_lock);
 884                 return;
 885         }
 886 
 887         request = cache->requests;
 888         reqinfo = cache->reqinfo;
 889         reginfo = cache->reginfo;
 890 
 891         table_info = netsnmp_extract_table_info(request);
 892         request->delegated = 0;
 893 
 894         ASSERT(table_info->colnum >= SUNFMFAULTEVENT_COLMIN);
 895         ASSERT(table_info->colnum <= SUNFMFAULTEVENT_COLMAX);
 896 
 897         /*
 898          * table_info->colnum contains the column number requested.
 899          * table_info->indexes contains a linked list of snmp variable
 900          * bindings for the indexes of the table.  Values in the list
 901          * have been set corresponding to the indexes of the
 902          * request.  We have other guarantees as well:
 903          *
 904          * - The column number is always within range.
 905          * - If we have no index data, table_info->index_oid_len is 0.
 906          * - We will never receive requests outside our table nor
 907          *   those with the first subid anything other than 1 (Entry)
 908          *   nor those without a column number.  This is true even
 909          *   for GETNEXT requests.
 910          */
 911 
 912         switch (reqinfo->mode) {
 913         case MODE_GET:
 914                 if ((data = sunFmFaultEventTable_fe(reginfo, table_info,
 915                     &status)) == NULL) {
 916                         netsnmp_free_delegated_cache(cache);
 917                         (void) pthread_mutex_unlock(&update_lock);
 918                         return;
 919                 }
 920                 break;
 921         case MODE_GETNEXT:
 922         case MODE_GETBULK:
 923                 if ((data = sunFmFaultEventTable_nextfe(reginfo, table_info,
 924                     &status)) == NULL) {
 925                         netsnmp_free_delegated_cache(cache);
 926                         (void) pthread_mutex_unlock(&update_lock);
 927                         return;
 928                 }
 929                 break;
 930         default:
 931                 (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request "
 932                     "mode %d\n", reqinfo->mode);
 933                 netsnmp_free_delegated_cache(cache);
 934                 (void) pthread_mutex_unlock(&update_lock);
 935                 return;
 936         }
 937 
 938         switch (table_info->colnum) {
 939         case SUNFMFAULTEVENT_COL_PROBLEMUUID:
 940         {
 941                 if ((pdata = sunFmProblemTable_pr(reginfo, table_info))
 942                     == NULL) {
 943                         (void) netsnmp_table_build_result(reginfo, request,
 944                             table_info, ASN_OCTET_STR, NULL, 0);
 945                         break;
 946                 }
 947                 (void) netsnmp_table_build_result(reginfo, request, table_info,
 948                     ASN_OCTET_STR, (uchar_t *)pdata->d_aci_uuid,
 949                     strlen(pdata->d_aci_uuid));
 950                 break;
 951         }
 952         case SUNFMFAULTEVENT_COL_CLASS:
 953         {
 954                 char    *class = "-";
 955 
 956                 (void) nvlist_lookup_string(data, FM_CLASS, &class);
 957                 (void) netsnmp_table_build_result(reginfo, request, table_info,
 958                     ASN_OCTET_STR, (uchar_t *)class, strlen(class));
 959                 break;
 960         }
 961         case SUNFMFAULTEVENT_COL_CERTAINTY:
 962         {
 963                 uint8_t pct = 0;
 964                 ulong_t pl;
 965 
 966                 (void) nvlist_lookup_uint8(data, FM_FAULT_CERTAINTY,
 967                     &pct);
 968                 pl = (ulong_t)pct;
 969                 (void) netsnmp_table_build_result(reginfo, request, table_info,
 970                     ASN_UNSIGNED, (uchar_t *)&pl, sizeof (pl));
 971                 break;
 972         }
 973         case SUNFMFAULTEVENT_COL_ASRU:
 974         {
 975                 nvlist_t        *asru = NULL;
 976                 char            *fmri, *str;
 977 
 978                 (void) nvlist_lookup_nvlist(data, FM_FAULT_ASRU, &asru);
 979                 if ((str = sunFm_nvl2str(asru)) == NULL)
 980                         fmri = "-";
 981                 else
 982                         fmri = str;
 983 
 984                 (void) netsnmp_table_build_result(reginfo, request, table_info,
 985                     ASN_OCTET_STR, (uchar_t *)fmri, strlen(fmri));
 986                 free(str);
 987                 break;
 988         }
 989         case SUNFMFAULTEVENT_COL_FRU:
 990         {
 991                 nvlist_t        *fru = NULL;
 992                 char            *fmri, *str;
 993 
 994                 (void) nvlist_lookup_nvlist(data, FM_FAULT_FRU, &fru);
 995                 if ((str = sunFm_nvl2str(fru)) == NULL)
 996                         fmri = "-";
 997                 else
 998                         fmri = str;
 999 
1000                 (void) netsnmp_table_build_result(reginfo, request, table_info,
1001                     ASN_OCTET_STR, (uchar_t *)fmri, strlen(fmri));
1002                 free(str);
1003                 break;
1004         }
1005         case SUNFMFAULTEVENT_COL_RESOURCE:
1006         {
1007                 nvlist_t        *rsrc = NULL;
1008                 char            *fmri, *str;
1009 
1010                 (void) nvlist_lookup_nvlist(data, FM_FAULT_RESOURCE, &rsrc);
1011                 if ((str = sunFm_nvl2str(rsrc)) == NULL)
1012                         fmri = "-";
1013                 else
1014                         fmri = str;
1015 
1016                 (void) netsnmp_table_build_result(reginfo, request, table_info,
1017                     ASN_OCTET_STR, (uchar_t *)fmri, strlen(fmri));
1018                 free(str);
1019                 break;
1020         }
1021         case SUNFMFAULTEVENT_COL_STATUS:
1022         {
1023                 ulong_t pl = SUNFMFAULTEVENT_STATE_OTHER;
1024 
1025                 if (status & FM_SUSPECT_FAULTY)
1026                         pl = SUNFMFAULTEVENT_STATE_FAULTY;
1027                 else if (status & FM_SUSPECT_NOT_PRESENT)
1028                         pl = SUNFMFAULTEVENT_STATE_REMOVED;
1029                 else if (status & FM_SUSPECT_REPLACED)
1030                         pl = SUNFMFAULTEVENT_STATE_REPLACED;
1031                 else if (status & FM_SUSPECT_REPAIRED)
1032                         pl = SUNFMFAULTEVENT_STATE_REPAIRED;
1033                 else if (status & FM_SUSPECT_ACQUITTED)
1034                         pl = SUNFMFAULTEVENT_STATE_ACQUITTED;
1035                 (void) netsnmp_table_build_result(reginfo, request, table_info,
1036                     ASN_INTEGER, (uchar_t *)&pl, sizeof (pl));
1037                 break;
1038         }
1039         case SUNFMFAULTEVENT_COL_LOCATION:
1040         {
1041                 char    *location = "-";
1042 
1043                 (void) nvlist_lookup_string(data, FM_FAULT_LOCATION, &location);
1044                 (void) netsnmp_table_build_result(reginfo, request, table_info,
1045                     ASN_OCTET_STR, (uchar_t *)location, strlen(location));
1046                 break;
1047         }
1048         default:
1049                 break;
1050         }
1051 
1052         netsnmp_free_delegated_cache(cache);
1053         (void) pthread_mutex_unlock(&update_lock);
1054 }
1055 
1056 static int
1057 sunFmFaultEventTable_handler(netsnmp_mib_handler *handler,
1058     netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
1059     netsnmp_request_info *requests)
1060 {
1061         netsnmp_request_info            *request;
1062         struct timeval                  tv;
1063 
1064         tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
1065         tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
1066 
1067         request_update();
1068 
1069         for (request = requests; request; request = request->next) {
1070                 if (request->processed != 0)
1071                         continue;
1072 
1073                 if (netsnmp_extract_table_info(request) == NULL)
1074                         continue;
1075 
1076                 request->delegated = 1;
1077                 (void) snmp_alarm_register_hr(tv, 0,
1078                     sunFmFaultEventTable_return,
1079                     (void *) netsnmp_create_delegated_cache(handler, reginfo,
1080                     reqinfo, request, NULL));
1081         }
1082 
1083         return (SNMP_ERR_NOERROR);
1084 }
 | 
 
 
   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 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2019 Nexenta Systems, Inc.
  29  */
  30 
  31 #include <sys/fm/protocol.h>
  32 
  33 #include <fm/fmd_adm.h>
  34 #include <fm/fmd_snmp.h>
  35 #include <fm/libfmevent.h>
  36 #include <fm/libtopo.h>
  37 
  38 #include <net-snmp/net-snmp-config.h>
  39 #include <net-snmp/net-snmp-includes.h>
  40 #include <net-snmp/agent/net-snmp-agent-includes.h>
  41 
  42 #include <alloca.h>
  43 #include <errno.h>
  44 #include <libnvpair.h>
  45 #include <libuutil.h>
  46 #include <locale.h>
  47 #include <netdb.h>
  48 #include <pthread.h>
  49 #include <stddef.h>
  50 
  51 #include "sunFM_impl.h"
  52 #include "problem.h"
  53 
  54 /*
  55  * We assume that the number of suspect fault events associated with a
  56  * particular case will generally be sufficiently small that the overhead
  57  * associated with indexing them in a tree would exceed the gain from
  58  * not traversing the fault list for each request.
  59  */
  60 static uu_avl_pool_t    *problem_uuid_avl_pool = NULL;
  61 static uu_avl_t         *problem_uuid_avl = NULL;
  62 
  63 #define VALID_AVL_STATE (problem_uuid_avl_pool != NULL &&       \
  64         problem_uuid_avl != NULL)
  65 
  66 static int              valid_stamp;
  67 static pthread_mutex_t  update_lock;
  68 static pthread_cond_t   update_cv;
  69 static fmev_shdl_t      evhdl;
  70 
  71 static Netsnmp_Node_Handler     sunFmProblemTable_handler;
  72 static Netsnmp_Node_Handler     sunFmFaultEventTable_handler;
  73 
  74 static char *
  75 nvl2fmri(nvlist_t *nvl)
  76 {
  77         topo_hdl_t *thp;
  78         int topoerr;
  79         char *fmri, *ret = NULL;
  80 
  81         thp = topo_open(TOPO_VERSION, NULL, &topoerr);
  82         if (thp == NULL)
  83                 return (NULL);
  84 
  85         if (topo_fmri_nvl2str(thp, nvl, &fmri, &topoerr) == 0) {
  86                 ret = strdup(fmri);
  87                 topo_hdl_strfree(thp, fmri);
  88         }
  89 
  90         topo_close(thp);
  91         return (ret);
  92 }
  93 
  94 static sunFmProblem_data_t *
  95 problem_key_build(const char *uuid)
  96 {
  97         static sunFmProblem_data_t      key;
  98 
  99         key.d_aci_uuid = uuid;
 100 
 101         return (&key);
 102 }
 103 
 104 static sunFmProblem_data_t *
 105 problem_lookup_uuid_exact(const char *uuid)
 106 {
 107         sunFmProblem_data_t     *key, *data;
 108 
 109         key = problem_key_build(uuid);
 110 
 111         DEBUGMSGTL((MODNAME_STR, "lookup_exact for uuid %s\n", uuid));
 112         data = uu_avl_find(problem_uuid_avl, key, NULL, NULL);
 113 
 
 142                 return (NULL);
 143 
 144         return (data->d_suspects[index - 1]);
 145 }
 146 
 147 static sunFmFaultStatus_data_t
 148 faultstatus_lookup_index_exact(sunFmProblem_data_t *data, ulong_t index)
 149 {
 150         if (index > data->d_nsuspects)
 151                 return (0);
 152 
 153         if (data->d_statuses == NULL)
 154                 return (0);
 155 
 156         if (data->d_valid != valid_stamp)
 157                 return (0);
 158 
 159         return (data->d_statuses[index - 1]);
 160 }
 161 
 162 #define FM_SUSPECT_SKIP \
 163         (FM_SUSPECT_NOT_PRESENT | FM_SUSPECT_REPAIRED | \
 164         FM_SUSPECT_REPLACED | FM_SUSPECT_ACQUITTED)
 165 
 166 /*ARGSUSED*/
 167 static int
 168 problem_update_one(const fmd_adm_caseinfo_t *acp, void *arg)
 169 {
 170         sunFmProblem_data_t             *data;
 171         nvlist_t                        *nvl;
 172         int64_t                         *diag_time;
 173         uint_t                          nelem;
 174         int                             err;
 175         int                             i;
 176         int                             cr = 0;
 177         uint8_t                         *statuses;
 178 
 179         ASSERT(acp->aci_uuid != NULL);
 180 
 181         if ((data = problem_lookup_uuid_exact(acp->aci_uuid)) == NULL) {
 182                 uu_avl_index_t idx;
 183                 nvlist_t **fnvl;
 184                 nvlist_t *snvl;
 185                 uint_t nnvl;
 186 
 187                 /* Lookup statuses early so we could skip resolved problems */
 188                 if (nvlist_lookup_uint8_array(acp->aci_event,
 189                     FM_SUSPECT_FAULT_STATUS, &statuses, &nelem) != 0)
 190                         return (0);
 191 
 192                 for (i = 0; i < nelem; i++) {
 193                         if (statuses[i] & FM_SUSPECT_SKIP)
 194                                 cr++;
 195                 }
 196                 if (cr == nelem) {
 197                         DEBUGMSGTL((MODNAME_STR,
 198                             "problem %s is resolved, skipping\n",
 199                             acp->aci_uuid));
 200                         return (0);
 201                 }
 202 
 203                 DEBUGMSGTL((MODNAME_STR, "found new problem %s\n",
 204                     acp->aci_uuid));
 205                 if ((data = SNMP_MALLOC_TYPEDEF(sunFmProblem_data_t)) == NULL) {
 206                         (void) snmp_log(LOG_ERR, MODNAME_STR
 207                             ": out of memory for new problem data\n");
 208                         return (0);
 209                 }
 210                 if ((err = nvlist_dup(acp->aci_event, &data->d_aci_event, 0))
 211                     != 0) {
 212                         (void) snmp_log(LOG_ERR, MODNAME_STR
 213                             ": problem data setup failed: %s\n", strerror(err));
 214                         SNMP_FREE(data);
 215                         return (0);
 216                 }
 217 
 218                 data->d_aci_uuid = data->d_aci_code = data->d_aci_type =
 219                     data->d_aci_severity = data->d_aci_url =
 220                     data->d_aci_desc = "-";
 221                 (void) nvlist_lookup_string(data->d_aci_event, FM_SUSPECT_UUID,
 222                     (char **)&data->d_aci_uuid);
 223                 (void) nvlist_lookup_string(data->d_aci_event,
 224                     FM_SUSPECT_DIAG_CODE, (char **)&data->d_aci_code);
 225                 (void) nvlist_lookup_string(data->d_aci_event,
 226                     FM_SUSPECT_TYPE, (char **)&data->d_aci_type);
 227                 (void) nvlist_lookup_string(data->d_aci_event,
 228                     FM_SUSPECT_SEVERITY, (char **)&data->d_aci_severity);
 229                 if (acp->aci_url != NULL)
 230                         data->d_aci_url = strdup(acp->aci_url);
 231                 (void) nvlist_lookup_string(data->d_aci_event,
 232                     FM_SUSPECT_DESC, (char **)&data->d_aci_desc);
 233 
 234                 /*
 235                  * NOTE: This should match the logic in libfmnotify.
 236                  *
 237                  * Extract the fault-list, and use the following order
 238                  * of nested nvlists from its first element to make up FMRI:
 239                  * - FRU
 240                  * - ASRU
 241                  * - resource
 242                  */
 243                 if (nvlist_lookup_nvlist_array(data->d_aci_event,
 244                     FM_SUSPECT_FAULT_LIST, &fnvl, &nnvl) == 0 && nnvl == 1 &&
 245                     (nvlist_lookup_nvlist(fnvl[0], FM_FAULT_FRU, &snvl) == 0 ||
 246                     nvlist_lookup_nvlist(fnvl[0], FM_FAULT_ASRU, &snvl) == 0 ||
 247                     nvlist_lookup_nvlist(fnvl[0], FM_FAULT_RESOURCE,
 248                     &snvl) == 0))
 249                         data->d_aci_fmri = nvl2fmri(snvl);
 250                 if (data->d_aci_fmri == NULL)
 251                         data->d_aci_fmri = "-";
 252 
 253                 if (nvlist_lookup_nvlist(data->d_aci_event, FM_SUSPECT_DE,
 254                     &nvl) == 0)
 255                         data->d_diag_engine = nvl2fmri(nvl);
 256                 if (data->d_diag_engine == NULL)
 257                         data->d_diag_engine = "-";
 258 
 259                 if (nvlist_lookup_int64_array(data->d_aci_event,
 260                     FM_SUSPECT_DIAG_TIME, &diag_time, &nelem) == 0 &&
 261                     nelem >= 2) {
 262                         data->d_diag_time.tv_sec = (long)diag_time[0];
 263                         data->d_diag_time.tv_usec = (long)diag_time[1];
 264                 }
 265 
 266                 (void) nvlist_lookup_uint32(data->d_aci_event,
 267                     FM_SUSPECT_FAULT_SZ, &data->d_nsuspects);
 268                 (void) nvlist_lookup_nvlist_array(data->d_aci_event,
 269                     FM_SUSPECT_FAULT_LIST, &data->d_suspects, &nelem);
 270                 (void) nvlist_lookup_uint8_array(data->d_aci_event,
 271                     FM_SUSPECT_FAULT_STATUS, &data->d_statuses, &nelem);
 272 
 273                 uu_avl_node_init(data, &data->d_uuid_avl,
 274                     problem_uuid_avl_pool);
 275                 (void) uu_avl_find(problem_uuid_avl, data, NULL, &idx);
 276                 uu_avl_insert(problem_uuid_avl, data, idx);
 277 
 278                 data->d_valid = valid_stamp;
 279 
 280                 DEBUGMSGTL((MODNAME_STR, "completed new problem %s@%p\n",
 281                     data->d_aci_uuid, data));
 282         } else {
 283                 if (nvlist_lookup_uint8_array(acp->aci_event,
 284                     FM_SUSPECT_FAULT_STATUS, &statuses, &nelem) != 0)
 285                         return (0);
 286 
 287                 if (nelem != data->d_nsuspects) {
 288                         DEBUGMSGTL((MODNAME_STR,
 289                             "problem %s is malformed; deleting\n",
 290                             data->d_aci_uuid));
 291                         goto delete;
 292                 }
 293 
 294                 for (i = 0; i < nelem; i++) {
 295                         if (statuses[i] & FM_SUSPECT_SKIP)
 296                                 cr++;
 297                         data->d_statuses[i] = statuses[i];
 298                 }
 299                 if (cr == nelem) {
 300                         DEBUGMSGTL((MODNAME_STR,
 301                             "problem %s is now resolved; deleting\n",
 302                             data->d_aci_uuid));
 303                         goto delete;
 304                 } else {
 305                         data->d_valid = valid_stamp;
 306                 }
 307         }
 308 
 309         return (0);
 310 
 311 delete:
 312         uu_avl_remove(problem_uuid_avl, data);
 313         uu_avl_node_fini(data, &data->d_uuid_avl,
 314             problem_uuid_avl_pool);
 315         nvlist_free(data->d_aci_event);
 316         SNMP_FREE(data);
 317         return (0);
 318 }
 319 
 320 /*ARGSUSED*/
 321 static void *
 322 update_thread(void *arg)
 323 {
 324         fmd_adm_t *adm;
 325         static struct timespec tv;
 326 
 327         /* Do a 1-minute checks for changes */
 328         tv.tv_sec = 60;
 329         tv.tv_nsec = 0;
 330 
 331         for (;;) {
 332                 ASSERT(VALID_AVL_STATE);
 333 
 334                 (void) pthread_mutex_lock(&update_lock);
 335                 /* We don't care if we were awaken explicitly or by timeout */
 336                 (void) pthread_cond_reltimedwait_np(&update_cv, &update_lock,
 337                     &tv);
 338                 if ((adm = fmd_adm_open(NULL, FMD_ADM_PROGRAM,
 339                     FMD_ADM_VERSION)) == NULL) {
 340                         (void) pthread_mutex_unlock(&update_lock);
 341                         (void) snmp_log(LOG_ERR, MODNAME_STR
 342                             ": communication with fmd failed: %s\n",
 343                             strerror(errno));
 344                         continue;
 345                 }
 346 
 347                 valid_stamp++;
 348 
 349                 DEBUGMSGTL((MODNAME_STR, "case iteration started\n"));
 350                 if (fmd_adm_case_iter(adm, SNMP_URL_MSG, problem_update_one,
 351                     NULL) != 0) {
 352                         (void) pthread_mutex_unlock(&update_lock);
 353                         (void) snmp_log(LOG_ERR, MODNAME_STR
 354                             ": fmd case information update failed: %s\n",
 355                             fmd_adm_errmsg(adm));
 356                         fmd_adm_close(adm);
 357                         continue;
 358                 }
 359 
 360                 fmd_adm_close(adm);
 361                 (void) pthread_mutex_unlock(&update_lock);
 362 
 363                 DEBUGMSGTL((MODNAME_STR, "case iteration completed\n"));
 364         }
 365 
 366         /*NOTREACHED*/
 367         return (NULL);
 368 }
 369 
 370 /*ARGSUSED*/
 371 static void
 372 event_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg)
 373 {
 374         (void) pthread_mutex_lock(&update_lock);
 375         (void) pthread_cond_signal(&update_cv);
 376         (void) pthread_mutex_unlock(&update_lock);
 377 }
 378 
 379 /*ARGSUSED*/
 380 static int
 381 problem_compare_uuid(const void *l, const void *r, void *private)
 382 {
 383         sunFmProblem_data_t     *l_data = (sunFmProblem_data_t *)l;
 384         sunFmProblem_data_t     *r_data = (sunFmProblem_data_t *)r;
 385 
 386         ASSERT(l_data != NULL && r_data != NULL);
 387 
 388         return (strcmp(l_data->d_aci_uuid, r_data->d_aci_uuid));
 389 }
 390 
 391 /* ARGSUSED */
 392 void *
 393 pid_thread(void *arg)
 394 {
 395         pid_t pid = getpid();
 396         int wait = 0;
 397 
 398         /*
 399          * Workaround the forking madness in net-snmp -- we need to
 400          * subscribe from the *forked* process so that event notifications
 401          * get our PID correctly.
 402          *
 403          * We also limit the wait to arbitrary long time of 10 seconds so that
 404          * we subscribe to event notifications when running with -f (don't fork)
 405          * specified.
 406          */
 407         for (;;) {
 408                 if (getpid() != pid || wait == 10) {
 409                         /* Subscribe to fault event notifications */
 410                         evhdl = fmev_shdl_init(LIBFMEVENT_VERSION_2, NULL, NULL,
 411                             NULL);
 412                         (void) fmev_shdl_subscribe(evhdl, "list.*", event_cb,
 413                             NULL);
 414                         break;
 415                 }
 416                 wait++;
 417                 (void) sleep(1);
 418         }
 419 
 420         return (NULL);
 421 }
 422 
 423 int
 424 sunFmProblemTable_init(void)
 425 {
 426         static oid sunFmFaultEventTable_oid[] = { SUNFMFAULTEVENTTABLE_OID };
 427         netsnmp_table_registration_info *ftinfo = NULL;
 428         netsnmp_handler_registration *fhandler = NULL;
 429         static oid sunFmProblemTable_oid[] = { SUNFMPROBLEMTABLE_OID };
 430         netsnmp_table_registration_info *ptinfo = NULL;
 431         netsnmp_handler_registration *phandler = NULL;
 432         pthread_t ptid;
 433         pthread_t utid;
 434         int ret = MIB_REGISTRATION_FAILED;
 435 
 436         /* Create fault event table and handler */
 437         if ((ftinfo =
 438             SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL ||
 439             netsnmp_table_helper_add_index(ftinfo, ASN_OCTET_STR) == NULL ||
 440             netsnmp_table_helper_add_index(ftinfo, ASN_UNSIGNED) == NULL ||
 441             (fhandler =
 442             netsnmp_create_handler_registration("sunFmFaultEventTable",
 443             sunFmFaultEventTable_handler, sunFmFaultEventTable_oid,
 444             OID_LENGTH(sunFmFaultEventTable_oid), HANDLER_CAN_RONLY)) == NULL)
 445                 goto fail;
 446 
 447         ftinfo->min_column = SUNFMFAULTEVENT_COLMIN;
 448         ftinfo->max_column = SUNFMFAULTEVENT_COLMAX;
 449 
 450         /* Register fault event handler */
 451         if ((ret = netsnmp_register_table(fhandler, ftinfo)) !=
 452             MIB_REGISTERED_OK)
 453                 goto fail;
 454 
 455         /* Create problem table, data pool, and handler */
 456         if ((problem_uuid_avl_pool = uu_avl_pool_create("problem_uuid",
 457             sizeof (sunFmProblem_data_t), offsetof(sunFmProblem_data_t,
 458             d_uuid_avl), problem_compare_uuid, UU_AVL_DEBUG)) == NULL ||
 459             (problem_uuid_avl = uu_avl_create(problem_uuid_avl_pool, NULL,
 460             UU_AVL_DEBUG)) == NULL ||
 461             (ptinfo =
 462             SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL ||
 463             netsnmp_table_helper_add_index(ptinfo, ASN_OCTET_STR) == NULL ||
 464             (phandler =
 465             netsnmp_create_handler_registration("sunFmProblemTable",
 466             sunFmProblemTable_handler, sunFmProblemTable_oid,
 467             OID_LENGTH(sunFmProblemTable_oid), HANDLER_CAN_RONLY)) == NULL)
 468                 goto fail;
 469 
 470         ptinfo->min_column = SUNFMPROBLEM_COLMIN;
 471         ptinfo->max_column = SUNFMPROBLEM_COLMAX;
 472 
 473         /* Register problem handler */
 474         if ((ret = netsnmp_register_table(phandler, ptinfo)) !=
 475             MIB_REGISTERED_OK)
 476                 goto fail;
 477 
 478         /* Create PID change waiter thread */
 479         if (pthread_create(&ptid, NULL, pid_thread, 0) != 0) {
 480                 (void) snmp_log(LOG_ERR, MODNAME_STR
 481                     ": failed to create pid thread: %s\n", strerror(ret));
 482                 goto fail;
 483         }
 484 
 485         /* Create update thread */
 486         if ((ret = pthread_mutex_init(&update_lock, NULL)) != 0 ||
 487             (ret = pthread_cond_init(&update_cv, NULL)) != 0 ||
 488             (ret = pthread_create(&utid, NULL, update_thread, 0)) != 0) {
 489                 (void) snmp_log(LOG_ERR, MODNAME_STR
 490                     ": failed to create update thread: %s\n", strerror(ret));
 491                 goto fail;
 492         }
 493 
 494         return (MIB_REGISTERED_OK);
 495 
 496 fail:
 497         (void) pthread_mutex_destroy(&update_lock);
 498         if (problem_uuid_avl != NULL)
 499                 uu_avl_destroy(problem_uuid_avl);
 500         if (problem_uuid_avl_pool != NULL)
 501                 uu_avl_pool_destroy(problem_uuid_avl_pool);
 502         if (ftinfo->indexes != NULL)
 503                 snmp_free_varbind(ftinfo->indexes);
 504         if (ftinfo != NULL)
 505                 SNMP_FREE(ftinfo);
 506         if (ptinfo->indexes != NULL)
 507                 snmp_free_varbind(ptinfo->indexes);
 508         if (ptinfo != NULL)
 509                 SNMP_FREE(ptinfo);
 510         if (fhandler != NULL)
 511                 SNMP_FREE(fhandler);
 512         if (phandler != NULL)
 513                 SNMP_FREE(phandler);
 514 
 515         return (ret);
 516 }
 517 
 518 /*
 519  * Returns the problem data for the problem whose uuid is next according
 520  * to ASN.1 lexical ordering after the request in table_info.  Indexes are
 521  * updated to reflect the OID of the value being returned.  This allows
 522  * us to implement GETNEXT.
 523  */
 524 static sunFmProblem_data_t *
 525 sunFmProblemTable_nextpr(netsnmp_handler_registration *reginfo,
 526     netsnmp_table_request_info *table_info)
 527 {
 528         sunFmProblem_data_t     *data;
 529         char                    *uuid = "";
 530 
 531         if (table_info->number_indexes < 1) {
 532                 oid tmpoid[MAX_OID_LEN];
 533 
 534                 DEBUGMSGTL((MODNAME_STR, "nextpr: no indexes given\n"));
 535 
 536                 snmp_free_varbind(table_info->indexes);
 537                 table_info->indexes =
 538                     SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
 539                 (void) snmp_set_var_typed_value(table_info->indexes,
 540                     ASN_OCTET_STR, (const uchar_t *)uuid, 0);
 541                 (void) memcpy(tmpoid, reginfo->rootoid,
 542                     reginfo->rootoid_len * sizeof (oid));
 543                 tmpoid[reginfo->rootoid_len] = 1;
 544                 tmpoid[reginfo->rootoid_len + 1] = table_info->colnum;
 545                 if (build_oid_segment(table_info->indexes) != SNMPERR_SUCCESS) {
 546                         snmp_free_varbind(table_info->indexes);
 547                         return (NULL);
 548                 }
 549                 table_info->number_indexes = 1;
 550                 table_info->index_oid_len = table_info->indexes->name_length;
 551                 (void) memcpy(table_info->index_oid, table_info->indexes->name,
 552                     table_info->indexes->name_length);
 553 
 554                 DEBUGMSGTL((MODNAME_STR, "nextpr: built fake index: "));
 555                 DEBUGMSGVAR((MODNAME_STR, table_info->indexes));
 556                 DEBUGMSG((MODNAME_STR, "\n"));
 557         } else {
 558                 /*
 559                  * Construct the next possible UUID to look for.  We can
 560                  * simply increment the least significant byte of the last
 561                  * UUID because (a) that preserves SNMP lex order and (b)
 562                  * the characters that may appear in a UUID do not include
 563                  * 127 nor 255.
 564                  */
 565                 uuid = alloca(table_info->indexes->val_len + 1);
 566                 (void) strlcpy(uuid,
 567                     (const char *)table_info->indexes->val.string,
 568                     table_info->indexes->val_len + 1);
 569                 ++uuid[table_info->indexes->val_len - 1];
 570 
 571                 DEBUGMSGTL((MODNAME_STR, "nextpr: received index:\n"));
 572                 DEBUGMSGVAR((MODNAME_STR, table_info->indexes));
 573                 DEBUGMSG((MODNAME_STR, "\n"));
 574         }
 
 682                                 DEBUGMSGVAR((MODNAME_STR, table_info->indexes));
 683                                 DEBUGMSG((MODNAME_STR, "\n"));
 684                                 var =
 685                                     SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
 686                                 (void) snmp_set_var_typed_value(var,
 687                                     ASN_UNSIGNED, (uchar_t *)&index,
 688                                     sizeof (index));
 689                                 (void) memcpy(tmpoid, reginfo->rootoid,
 690                                     reginfo->rootoid_len * sizeof (oid));
 691                                 tmpoid[reginfo->rootoid_len] = 1;
 692                                 tmpoid[reginfo->rootoid_len + 1] =
 693                                     table_info->colnum;
 694                                 if (build_oid_segment(var) != SNMPERR_SUCCESS) {
 695                                         snmp_free_varbind(var);
 696                                         return (NULL);
 697                                 }
 698                                 snmp_free_varbind(
 699                                     table_info->indexes->next_variable);
 700                                 table_info->indexes->next_variable = var;
 701                                 table_info->number_indexes = 2;
 702                                 DEBUGMSGTL((MODNAME_STR,
 703                                     "nextfe: built fake index: "));
 704                                 DEBUGMSGVAR((MODNAME_STR, table_info->indexes));
 705                                 DEBUGMSG((MODNAME_STR, "\n"));
 706                                 DEBUGMSGVAR((MODNAME_STR,
 707                                     table_info->indexes->next_variable));
 708                                 DEBUGMSG((MODNAME_STR, "\n"));
 709                         } else {
 710                                 if (sunFmProblemTable_nextpr(reginfo,
 711                                     table_info) == NULL)
 712                                         return (NULL);
 713                         }
 714                         break;
 715                 case 0:
 716                         if (sunFmProblemTable_nextpr(reginfo, table_info) ==
 717                             NULL)
 718                                 return (NULL);
 719                         break;
 720                 }
 721         }
 722 }
 723 
 724 static sunFmFaultEvent_data_t *
 725 sunFmFaultEventTable_fe(netsnmp_handler_registration *reginfo,
 726     netsnmp_table_request_info *table_info, sunFmFaultStatus_data_t *statusp)
 727 {
 728         sunFmProblem_data_t     *data;
 729 
 730         ASSERT(table_info->number_indexes == 2);
 731 
 732         if ((data = sunFmProblemTable_pr(reginfo, table_info)) == NULL)
 733                 return (NULL);
 734 
 735         *statusp = faultstatus_lookup_index_exact(data,
 736             *(ulong_t *)table_info->indexes->next_variable->val.integer);
 737         if (*statusp == 0)
 738                 return (NULL);
 739         return (faultevent_lookup_index_exact(data,
 740             *(ulong_t *)table_info->indexes->next_variable->val.integer));
 741 }
 742 
 743 /*ARGSUSED*/
 744 static int
 745 sunFmProblemTable_handler(netsnmp_mib_handler *handler,
 746     netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
 747     netsnmp_request_info *request)
 748 {
 749         netsnmp_table_request_info      *table_info;
 750         sunFmProblem_data_t             *data;
 751         int                             ret = SNMP_ERR_NOERROR;
 752 
 753         /*
 754          * We don't support MODE_GETBULK directly, so all bulk requests should
 755          * come through bulk_to_next helper.  Make sure it stays that way.
 756          */
 757         ASSERT(reqinfo->mode == MODE_GET || reqinfo->mode == MODE_GETNEXT);
 758 
 759         (void) pthread_mutex_lock(&update_lock);
 760 
 761         for (; request != NULL; request = request->next) {
 762                 table_info = netsnmp_extract_table_info(request);
 763                 if (table_info == NULL)
 764                         continue;
 765 
 766                 /*
 767                  * table_info->colnum contains the column number requested.
 768                  * table_info->indexes contains a linked list of snmp variable
 769                  * bindings for the indexes of the table.  Values in the list
 770                  * have been set corresponding to the indexes of the
 771                  * request.  We have other guarantees as well:
 772                  *
 773                  * - The column number is always within range.
 774                  * - If we have no index data, table_info->index_oid_len is 0.
 775                  * - We will never receive requests outside our table nor
 776                  *   those with the first subid anything other than 1 (Entry)
 777                  *   nor those without a column number.  This is true even
 778                  *   for GETNEXT requests.
 779                  */
 780                 switch (reqinfo->mode) {
 781                 case MODE_GET:
 782                         data = sunFmProblemTable_pr(reginfo, table_info);
 783                         if (data == NULL)
 784                                 goto out;
 785                         break;
 786                 case MODE_GETNEXT:
 787                         data = sunFmProblemTable_nextpr(reginfo, table_info);
 788                         if (data == NULL)
 789                                 goto out;
 790                         break;
 791                 default:
 792                         (void) snmp_log(LOG_ERR, MODNAME_STR
 793                             ": unsupported request mode: %d\n", reqinfo->mode);
 794                         ret = SNMP_ERR_GENERR;
 795                         goto out;
 796                 }
 797 
 798                 switch (table_info->colnum) {
 799                 case SUNFMPROBLEM_COL_UUID:
 800                         (void) netsnmp_table_build_result(reginfo, request,
 801                             table_info, ASN_OCTET_STR,
 802                             (uchar_t *)data->d_aci_uuid,
 803                             strlen(data->d_aci_uuid));
 804                         break;
 805                 case SUNFMPROBLEM_COL_HOSTNAME: {
 806                         char hostname[MAXHOSTNAMELEN+1];
 807 
 808                         (void) gethostname(hostname, sizeof (hostname) - 1);
 809                         (void) netsnmp_table_build_result(reginfo, request,
 810                             table_info, ASN_OCTET_STR, (uchar_t *)hostname,
 811                             strlen(hostname));
 812                         break;
 813                 }
 814                 case SUNFMPROBLEM_COL_CODE:
 815                         (void) netsnmp_table_build_result(reginfo, request,
 816                             table_info, ASN_OCTET_STR,
 817                             (uchar_t *)data->d_aci_code,
 818                             strlen(data->d_aci_code));
 819                         break;
 820                 case SUNFMPROBLEM_COL_TYPE:
 821                         (void) netsnmp_table_build_result(reginfo, request,
 822                             table_info, ASN_OCTET_STR,
 823                             (uchar_t *)data->d_aci_type,
 824                             strlen(data->d_aci_type));
 825                         break;
 826                 case SUNFMPROBLEM_COL_SEVERITY:
 827                         (void) netsnmp_table_build_result(reginfo, request,
 828                             table_info, ASN_OCTET_STR,
 829                             (uchar_t *)data->d_aci_severity,
 830                             strlen(data->d_aci_severity));
 831                         break;
 832                 case SUNFMPROBLEM_COL_URL:
 833                         (void) netsnmp_table_build_result(reginfo, request,
 834                             table_info, ASN_OCTET_STR,
 835                             (uchar_t *)data->d_aci_url,
 836                             strlen(data->d_aci_url));
 837                         break;
 838                 case SUNFMPROBLEM_COL_DESC:
 839                         (void) netsnmp_table_build_result(reginfo, request,
 840                             table_info, ASN_OCTET_STR,
 841                             (uchar_t *)data->d_aci_desc,
 842                             strlen(data->d_aci_desc));
 843                         break;
 844                 case SUNFMPROBLEM_COL_FMRI:
 845                         (void) netsnmp_table_build_result(reginfo, request,
 846                             table_info, ASN_OCTET_STR,
 847                             (uchar_t *)data->d_aci_fmri,
 848                             strlen(data->d_aci_fmri));
 849                         break;
 850                 case SUNFMPROBLEM_COL_DIAGENGINE:
 851                         (void) netsnmp_table_build_result(reginfo, request,
 852                             table_info, ASN_OCTET_STR,
 853                             (uchar_t *)data->d_diag_engine,
 854                             strlen(data->d_diag_engine));
 855                         break;
 856                 case SUNFMPROBLEM_COL_DIAGTIME: {
 857                         /*
 858                          * The date_n_time function is not Y2038-safe; this may
 859                          * need to be updated when a suitable Y2038-safe
 860                          * Net-SNMP API is available.
 861                          */
 862                         size_t  dt_size;
 863                         time_t  dt_time = (time_t)data->d_diag_time.tv_sec;
 864                         uchar_t *dt = date_n_time(&dt_time, &dt_size);
 865 
 866                         (void) netsnmp_table_build_result(reginfo, request,
 867                             table_info, ASN_OCTET_STR, dt, dt_size);
 868                         break;
 869                 }
 870                 case SUNFMPROBLEM_COL_SUSPECTCOUNT:
 871                         (void) netsnmp_table_build_result(reginfo, request,
 872                             table_info, ASN_UNSIGNED,
 873                             (uchar_t *)&data->d_nsuspects,
 874                             sizeof (data->d_nsuspects));
 875                         break;
 876                 default:
 877                         (void) netsnmp_table_build_result(reginfo, request,
 878                             table_info, ASN_OCTET_STR, (uchar_t *)"-",
 879                             strlen("-"));
 880                         break;
 881                 }
 882         }
 883 
 884 out:
 885         (void) pthread_mutex_unlock(&update_lock);
 886         return (ret);
 887 }
 888 
 889 /*ARGSUSED*/
 890 static int
 891 sunFmFaultEventTable_handler(netsnmp_mib_handler *handler,
 892     netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
 893     netsnmp_request_info *request)
 894 {
 895         netsnmp_table_request_info      *table_info;
 896         sunFmFaultEvent_data_t          *data;
 897         sunFmFaultStatus_data_t         status;
 898         sunFmProblem_data_t             *pdata;
 899         int                             ret = SNMP_ERR_NOERROR;
 900 
 901         /*
 902          * We don't support MODE_GETBULK directly, so all bulk requests should
 903          * come through bulk_to_next helper.  Make sure it stays that way.
 904          */
 905         ASSERT(reqinfo->mode == MODE_GET || reqinfo->mode == MODE_GETNEXT);
 906 
 907         (void) pthread_mutex_lock(&update_lock);
 908 
 909         for (; request != NULL; request = request->next) {
 910                 table_info = netsnmp_extract_table_info(request);
 911                 if (table_info == NULL)
 912                         continue;
 913 
 914                 ASSERT(table_info->colnum >= SUNFMFAULTEVENT_COLMIN);
 915                 ASSERT(table_info->colnum <= SUNFMFAULTEVENT_COLMAX);
 916 
 917                 /*
 918                  * table_info->colnum contains the column number requested.
 919                  * table_info->indexes contains a linked list of snmp variable
 920                  * bindings for the indexes of the table.  Values in the list
 921                  * have been set corresponding to the indexes of the
 922                  * request.  We have other guarantees as well:
 923                  *
 924                  * - The column number is always within range.
 925                  * - If we have no index data, table_info->index_oid_len is 0.
 926                  * - We will never receive requests outside our table nor
 927                  *   those with the first subid anything other than 1 (Entry)
 928                  *   nor those without a column number.  This is true even
 929                  *   for GETNEXT requests.
 930                  */
 931                 switch (reqinfo->mode) {
 932                 case MODE_GET:
 933                         data = sunFmFaultEventTable_fe(reginfo, table_info,
 934                             &status);
 935                         if (data == NULL)
 936                                 goto out;
 937                         break;
 938                 case MODE_GETNEXT:
 939                         data = sunFmFaultEventTable_nextfe(reginfo, table_info,
 940                             &status);
 941                         if (data == NULL)
 942                                 goto out;
 943                         break;
 944                 default:
 945                         (void) snmp_log(LOG_ERR, MODNAME_STR
 946                             ": unsupported request mode: %d\n", reqinfo->mode);
 947                         ret = SNMP_ERR_GENERR;
 948                         goto out;
 949                 }
 950 
 951                 switch (table_info->colnum) {
 952                 case SUNFMFAULTEVENT_COL_PROBLEMUUID:
 953                         if ((pdata = sunFmProblemTable_pr(reginfo, table_info))
 954                             == NULL) {
 955                                 (void) netsnmp_table_build_result(reginfo,
 956                                     request, table_info, ASN_OCTET_STR,
 957                                     NULL, 0);
 958                                 break;
 959                         }
 960                         (void) netsnmp_table_build_result(reginfo, request,
 961                             table_info, ASN_OCTET_STR,
 962                             (uchar_t *)pdata->d_aci_uuid,
 963                             strlen(pdata->d_aci_uuid));
 964                         break;
 965                 case SUNFMFAULTEVENT_COL_CLASS: {
 966                         char    *class = "-";
 967 
 968                         (void) nvlist_lookup_string(data, FM_CLASS, &class);
 969                         (void) netsnmp_table_build_result(reginfo, request,
 970                             table_info, ASN_OCTET_STR, (uchar_t *)class,
 971                             strlen(class));
 972                         break;
 973                 }
 974                 case SUNFMFAULTEVENT_COL_CERTAINTY: {
 975                         uint8_t pct = 0;
 976                         ulong_t pl;
 977 
 978                         (void) nvlist_lookup_uint8(data, FM_FAULT_CERTAINTY,
 979                             &pct);
 980                         pl = (ulong_t)pct;
 981                         (void) netsnmp_table_build_result(reginfo, request,
 982                             table_info, ASN_UNSIGNED, (uchar_t *)&pl,
 983                             sizeof (pl));
 984                         break;
 985                 }
 986                 case SUNFMFAULTEVENT_COL_ASRU: {
 987                         nvlist_t        *asru = NULL;
 988                         char            *fmri = "-", *str;
 989 
 990                         (void) nvlist_lookup_nvlist(data, FM_FAULT_ASRU, &asru);
 991                         if ((str = nvl2fmri(asru)) != NULL)
 992                                 fmri = str;
 993 
 994                         (void) netsnmp_table_build_result(reginfo, request,
 995                             table_info, ASN_OCTET_STR, (uchar_t *)fmri,
 996                             strlen(fmri));
 997                         free(str);
 998                         break;
 999                 }
1000                 case SUNFMFAULTEVENT_COL_FRU: {
1001                         nvlist_t        *fru = NULL;
1002                         char            *fmri = "-", *str;
1003 
1004                         (void) nvlist_lookup_nvlist(data, FM_FAULT_FRU, &fru);
1005                         if ((str = nvl2fmri(fru)) != NULL)
1006                                 fmri = str;
1007 
1008                         (void) netsnmp_table_build_result(reginfo, request,
1009                             table_info, ASN_OCTET_STR, (uchar_t *)fmri,
1010                             strlen(fmri));
1011                         free(str);
1012                         break;
1013                 }
1014                 case SUNFMFAULTEVENT_COL_RESOURCE: {
1015                         nvlist_t        *rsrc = NULL;
1016                         char            *fmri = "-", *str;
1017 
1018                         (void) nvlist_lookup_nvlist(data, FM_FAULT_RESOURCE,
1019                             &rsrc);
1020                         if ((str = nvl2fmri(rsrc)) != NULL)
1021                                 fmri = str;
1022 
1023                         (void) netsnmp_table_build_result(reginfo, request,
1024                             table_info, ASN_OCTET_STR, (uchar_t *)fmri,
1025                             strlen(fmri));
1026                         free(str);
1027                         break;
1028                 }
1029                 case SUNFMFAULTEVENT_COL_STATUS: {
1030                         ulong_t pl = SUNFMFAULTEVENT_STATE_OTHER;
1031 
1032                         if (status & FM_SUSPECT_FAULTY)
1033                                 pl = SUNFMFAULTEVENT_STATE_FAULTY;
1034                         else if (status & FM_SUSPECT_NOT_PRESENT)
1035                                 pl = SUNFMFAULTEVENT_STATE_REMOVED;
1036                         else if (status & FM_SUSPECT_REPLACED)
1037                                 pl = SUNFMFAULTEVENT_STATE_REPLACED;
1038                         else if (status & FM_SUSPECT_REPAIRED)
1039                                 pl = SUNFMFAULTEVENT_STATE_REPAIRED;
1040                         else if (status & FM_SUSPECT_ACQUITTED)
1041                                 pl = SUNFMFAULTEVENT_STATE_ACQUITTED;
1042                         (void) netsnmp_table_build_result(reginfo, request,
1043                             table_info, ASN_INTEGER, (uchar_t *)&pl,
1044                             sizeof (pl));
1045                         break;
1046                 }
1047                 case SUNFMFAULTEVENT_COL_LOCATION: {
1048                         char    *location = "-";
1049 
1050                         (void) nvlist_lookup_string(data, FM_FAULT_LOCATION,
1051                             &location);
1052                         (void) netsnmp_table_build_result(reginfo, request,
1053                             table_info, ASN_OCTET_STR, (uchar_t *)location,
1054                             strlen(location));
1055                         break;
1056                 }
1057                 default:
1058                         break;
1059                 }
1060         }
1061 
1062 out:
1063         (void) pthread_mutex_unlock(&update_lock);
1064         return (ret);
1065 }
 |