Print this page
NEX-18763 net-snmp service could go into maintenance, if there are hundreds of FMA cases (fix lint)
NEX-18763 net-snmp service could go into maintenance, if there are hundreds of FMA cases
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-18680 snmpd core dumped
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com>
NEX-18695 libfmd_snmp is unable to handle multiple OIDs in GET request
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-17796 libfmd_snmp performance is awful
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-17938 libfmd_snmp dumps core in problem_lookup_uuid_exact()
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
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-17777 snmptable produces bogus output for FM tables
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-17772 libfmd_snmp should learn about new FmProblem fields
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-3125 libfmd_snmp should compile with newer net-snmp
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/fm/libfmd_snmp/common/problem.c
          +++ new/usr/src/lib/fm/libfmd_snmp/common/problem.c
↓ open down ↓ 16 lines elided ↑ open up ↑
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   */
  26   26  
       27 +/*
       28 + * Copyright 2019 Nexenta Systems, Inc.
       29 + */
       30 +
  27   31  #include <sys/fm/protocol.h>
       32 +
  28   33  #include <fm/fmd_adm.h>
  29   34  #include <fm/fmd_snmp.h>
       35 +#include <fm/libfmevent.h>
       36 +#include <fm/libtopo.h>
       37 +
  30   38  #include <net-snmp/net-snmp-config.h>
  31   39  #include <net-snmp/net-snmp-includes.h>
  32   40  #include <net-snmp/agent/net-snmp-agent-includes.h>
  33      -#include <pthread.h>
  34      -#include <stddef.h>
  35      -#include <errno.h>
       41 +
  36   42  #include <alloca.h>
  37      -#include <locale.h>
  38      -#include <libuutil.h>
       43 +#include <errno.h>
  39   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 +
  40   51  #include "sunFM_impl.h"
  41   52  #include "problem.h"
  42   53  
  43   54  /*
  44   55   * We assume that the number of suspect fault events associated with a
  45   56   * particular case will generally be sufficiently small that the overhead
  46   57   * associated with indexing them in a tree would exceed the gain from
  47   58   * not traversing the fault list for each request.
  48   59   */
  49      -static uu_avl_pool_t    *problem_uuid_avl_pool;
  50      -static uu_avl_t         *problem_uuid_avl;
       60 +static uu_avl_pool_t    *problem_uuid_avl_pool = NULL;
       61 +static uu_avl_t         *problem_uuid_avl = NULL;
  51   62  
  52   63  #define VALID_AVL_STATE (problem_uuid_avl_pool != NULL &&       \
  53   64          problem_uuid_avl != NULL)
  54   65  
  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   66  static int              valid_stamp;
  68   67  static pthread_mutex_t  update_lock;
  69   68  static pthread_cond_t   update_cv;
  70      -static volatile enum { US_QUIET, US_NEEDED, US_INPROGRESS } update_status;
       69 +static fmev_shdl_t      evhdl;
  71   70  
  72   71  static Netsnmp_Node_Handler     sunFmProblemTable_handler;
  73   72  static Netsnmp_Node_Handler     sunFmFaultEventTable_handler;
  74   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 +
  75   94  static sunFmProblem_data_t *
  76   95  problem_key_build(const char *uuid)
  77   96  {
  78   97          static sunFmProblem_data_t      key;
  79   98  
  80   99          key.d_aci_uuid = uuid;
  81  100  
  82  101          return (&key);
  83  102  }
  84  103  
↓ open down ↓ 48 lines elided ↑ open up ↑
 133  152  
 134  153          if (data->d_statuses == NULL)
 135  154                  return (0);
 136  155  
 137  156          if (data->d_valid != valid_stamp)
 138  157                  return (0);
 139  158  
 140  159          return (data->d_statuses[index - 1]);
 141  160  }
 142  161  
      162 +#define FM_SUSPECT_SKIP \
      163 +        (FM_SUSPECT_NOT_PRESENT | FM_SUSPECT_REPAIRED | \
      164 +        FM_SUSPECT_REPLACED | FM_SUSPECT_ACQUITTED)
      165 +
 143  166  /*ARGSUSED*/
 144  167  static int
 145  168  problem_update_one(const fmd_adm_caseinfo_t *acp, void *arg)
 146  169  {
 147  170          sunFmProblem_data_t             *data;
 148  171          nvlist_t                        *nvl;
 149  172          int64_t                         *diag_time;
 150  173          uint_t                          nelem;
 151      -        uint32_t                        nsusp;
 152  174          int                             err;
      175 +        int                             i;
      176 +        int                             cr = 0;
      177 +        uint8_t                         *statuses;
 153  178  
 154      -        DEBUGMSGTL((MODNAME_STR, "update_one\n"));
 155      -
 156  179          ASSERT(acp->aci_uuid != NULL);
 157  180  
 158  181          if ((data = problem_lookup_uuid_exact(acp->aci_uuid)) == NULL) {
 159  182                  uu_avl_index_t idx;
      183 +                nvlist_t **fnvl;
      184 +                nvlist_t *snvl;
      185 +                uint_t nnvl;
 160  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 +
 161  203                  DEBUGMSGTL((MODNAME_STR, "found new problem %s\n",
 162  204                      acp->aci_uuid));
 163  205                  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__);
      206 +                        (void) snmp_log(LOG_ERR, MODNAME_STR
      207 +                            ": out of memory for new problem data\n");
 167  208                          return (0);
 168  209                  }
 169  210                  if ((err = nvlist_dup(acp->aci_event, &data->d_aci_event, 0))
 170  211                      != 0) {
 171      -                        (void) snmp_log(LOG_ERR, MODNAME_STR ": Problem data "
 172      -                            "setup failed: %s\n", strerror(err));
      212 +                        (void) snmp_log(LOG_ERR, MODNAME_STR
      213 +                            ": problem data setup failed: %s\n", strerror(err));
 173  214                          SNMP_FREE(data);
 174  215                          return (0);
 175  216                  }
 176  217  
 177      -                data->d_aci_uuid = data->d_aci_code = data->d_aci_url = "-";
      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 = "-";
 178  221                  (void) nvlist_lookup_string(data->d_aci_event, FM_SUSPECT_UUID,
 179  222                      (char **)&data->d_aci_uuid);
 180  223                  (void) nvlist_lookup_string(data->d_aci_event,
 181  224                      FM_SUSPECT_DIAG_CODE, (char **)&data->d_aci_code);
 182      -                data->d_aci_url = strdup(acp->aci_url);
      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);
 183  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 +
 184  253                  if (nvlist_lookup_nvlist(data->d_aci_event, FM_SUSPECT_DE,
 185  254                      &nvl) == 0)
 186      -                        if ((data->d_diag_engine = sunFm_nvl2str(nvl)) == NULL)
 187      -                                data->d_diag_engine = "-";
      255 +                        data->d_diag_engine = nvl2fmri(nvl);
      256 +                if (data->d_diag_engine == NULL)
      257 +                        data->d_diag_engine = "-";
 188  258  
 189  259                  if (nvlist_lookup_int64_array(data->d_aci_event,
 190  260                      FM_SUSPECT_DIAG_TIME, &diag_time, &nelem) == 0 &&
 191  261                      nelem >= 2) {
 192  262                          data->d_diag_time.tv_sec = (long)diag_time[0];
 193  263                          data->d_diag_time.tv_usec = (long)diag_time[1];
 194  264                  }
 195  265  
 196  266                  (void) nvlist_lookup_uint32(data->d_aci_event,
 197      -                    FM_SUSPECT_FAULT_SZ, &nsusp);
 198      -                data->d_nsuspects = (ulong_t)nsusp;
 199      -
      267 +                    FM_SUSPECT_FAULT_SZ, &data->d_nsuspects);
 200  268                  (void) nvlist_lookup_nvlist_array(data->d_aci_event,
 201  269                      FM_SUSPECT_FAULT_LIST, &data->d_suspects, &nelem);
 202      -
 203      -                ASSERT(nelem == data->d_nsuspects);
 204      -
 205  270                  (void) nvlist_lookup_uint8_array(data->d_aci_event,
 206  271                      FM_SUSPECT_FAULT_STATUS, &data->d_statuses, &nelem);
 207  272  
 208      -                ASSERT(nelem == data->d_nsuspects);
 209      -
 210  273                  uu_avl_node_init(data, &data->d_uuid_avl,
 211  274                      problem_uuid_avl_pool);
 212  275                  (void) uu_avl_find(problem_uuid_avl, data, NULL, &idx);
 213  276                  uu_avl_insert(problem_uuid_avl, data, idx);
 214  277  
 215  278                  data->d_valid = valid_stamp;
 216  279  
 217  280                  DEBUGMSGTL((MODNAME_STR, "completed new problem %s@%p\n",
 218  281                      data->d_aci_uuid, data));
 219  282          } else {
 220      -                uint8_t *statuses;
 221      -                int i;
      283 +                if (nvlist_lookup_uint8_array(acp->aci_event,
      284 +                    FM_SUSPECT_FAULT_STATUS, &statuses, &nelem) != 0)
      285 +                        return (0);
 222  286  
 223      -                (void) nvlist_lookup_uint8_array(acp->aci_event,
 224      -                    FM_SUSPECT_FAULT_STATUS, &statuses, &nelem);
      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 +                }
 225  293  
 226      -                ASSERT(nelem == data->d_nsuspects);
 227      -
 228      -                for (i = 0; i < nelem; i++)
      294 +                for (i = 0; i < nelem; i++) {
      295 +                        if (statuses[i] & FM_SUSPECT_SKIP)
      296 +                                cr++;
 229  297                          data->d_statuses[i] = statuses[i];
 230      -
 231      -                data->d_valid = valid_stamp;
      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 +                }
 232  307          }
 233  308  
 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      -         */
      309 +        return (0);
 240  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);
 241  317          return (0);
 242  318  }
 243  319  
 244      -static int
 245      -problem_update(sunFmProblem_update_ctx_t *update_ctx)
      320 +/*ARGSUSED*/
      321 +static void *
      322 +update_thread(void *arg)
 246  323  {
 247  324          fmd_adm_t *adm;
      325 +        static struct timespec tv;
 248  326  
 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);
      327 +        /* Do a 1-minute checks for changes */
      328 +        tv.tv_sec = 60;
      329 +        tv.tv_nsec = 0;
 254  330  
 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      -        }
      331 +        for (;;) {
      332 +                ASSERT(VALID_AVL_STATE);
 261  333  
 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      -        }
      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 +                }
 270  346  
 271      -        DEBUGMSGTL((MODNAME_STR, "case iteration completed\n"));
      347 +                valid_stamp++;
 272  348  
 273      -        fmd_adm_close(adm);
 274      -        return (SNMP_ERR_NOERROR);
 275      -}
      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 +                }
 276  359  
 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;
      360 +                fmd_adm_close(adm);
 302  361                  (void) pthread_mutex_unlock(&update_lock);
 303      -                (void) problem_update(&uc);
      362 +
      363 +                DEBUGMSGTL((MODNAME_STR, "case iteration completed\n"));
 304  364          }
      365 +
      366 +        /*NOTREACHED*/
      367 +        return (NULL);
 305  368  }
 306  369  
      370 +/*ARGSUSED*/
 307  371  static void
 308      -request_update(void)
      372 +event_cb(fmev_t ev, const char *class, nvlist_t *nvl, void *arg)
 309  373  {
 310  374          (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  375          (void) pthread_cond_signal(&update_cv);
 317  376          (void) pthread_mutex_unlock(&update_lock);
 318  377  }
 319  378  
 320  379  /*ARGSUSED*/
 321  380  static int
 322  381  problem_compare_uuid(const void *l, const void *r, void *private)
 323  382  {
 324  383          sunFmProblem_data_t     *l_data = (sunFmProblem_data_t *)l;
 325  384          sunFmProblem_data_t     *r_data = (sunFmProblem_data_t *)r;
 326  385  
 327  386          ASSERT(l_data != NULL && r_data != NULL);
 328  387  
 329  388          return (strcmp(l_data->d_aci_uuid, r_data->d_aci_uuid));
 330  389  }
 331  390  
 332      -int
 333      -sunFmProblemTable_init(void)
      391 +/* ARGSUSED */
      392 +void *
      393 +pid_thread(void *arg)
 334  394  {
 335      -        static oid sunFmProblemTable_oid[] = { SUNFMPROBLEMTABLE_OID };
 336      -        netsnmp_table_registration_info *table_info;
 337      -        netsnmp_handler_registration *handler;
 338      -        int err;
      395 +        pid_t pid = getpid();
      396 +        int wait = 0;
 339  397  
 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  398          /*
 370      -         * The Net-SNMP template uses add_indexes here, but that
 371      -         * function is unsafe because it does not check for failure.
      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.
 372  406           */
 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);
      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);
 377  418          }
 378  419  
 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);
      420 +        return (NULL);
 416  421  }
 417  422  
 418  423  int
 419      -sunFmFaultEventTable_init(void)
      424 +sunFmProblemTable_init(void)
 420  425  {
 421  426          static oid sunFmFaultEventTable_oid[] = { SUNFMFAULTEVENTTABLE_OID };
 422      -        netsnmp_table_registration_info *table_info;
 423      -        netsnmp_handler_registration *handler;
 424      -        int err;
      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;
 425  435  
 426      -        if ((table_info =
 427      -            SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL)
 428      -                return (MIB_REGISTRATION_FAILED);
 429      -
 430      -        if ((handler =
      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 =
 431  442              netsnmp_create_handler_registration("sunFmFaultEventTable",
 432  443              sunFmFaultEventTable_handler, sunFmFaultEventTable_oid,
 433      -            OID_LENGTH(sunFmFaultEventTable_oid), HANDLER_CAN_RONLY)) == NULL) {
 434      -                SNMP_FREE(table_info);
 435      -                return (MIB_REGISTRATION_FAILED);
 436      -        }
      444 +            OID_LENGTH(sunFmFaultEventTable_oid), HANDLER_CAN_RONLY)) == NULL)
      445 +                goto fail;
 437  446  
 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      -        }
      447 +        ftinfo->min_column = SUNFMFAULTEVENT_COLMIN;
      448 +        ftinfo->max_column = SUNFMFAULTEVENT_COLMAX;
 453  449  
 454      -        table_info->min_column = SUNFMFAULTEVENT_COLMIN;
 455      -        table_info->max_column = SUNFMFAULTEVENT_COLMAX;
      450 +        /* Register fault event handler */
      451 +        if ((ret = netsnmp_register_table(fhandler, ftinfo)) !=
      452 +            MIB_REGISTERED_OK)
      453 +                goto fail;
 456  454  
 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);
      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;
 463  483          }
 464  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 +
 465  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);
 466  516  }
 467  517  
 468  518  /*
 469  519   * Returns the problem data for the problem whose uuid is next according
 470  520   * to ASN.1 lexical ordering after the request in table_info.  Indexes are
 471  521   * updated to reflect the OID of the value being returned.  This allows
 472  522   * us to implement GETNEXT.
 473  523   */
 474  524  static sunFmProblem_data_t *
 475  525  sunFmProblemTable_nextpr(netsnmp_handler_registration *reginfo,
↓ open down ↓ 18 lines elided ↑ open up ↑
 494  544                  tmpoid[reginfo->rootoid_len + 1] = table_info->colnum;
 495  545                  if (build_oid_segment(table_info->indexes) != SNMPERR_SUCCESS) {
 496  546                          snmp_free_varbind(table_info->indexes);
 497  547                          return (NULL);
 498  548                  }
 499  549                  table_info->number_indexes = 1;
 500  550                  table_info->index_oid_len = table_info->indexes->name_length;
 501  551                  (void) memcpy(table_info->index_oid, table_info->indexes->name,
 502  552                      table_info->indexes->name_length);
 503  553  
 504      -                DEBUGMSGTL((MODNAME_STR, "nextpr: built fake index:\n"));
      554 +                DEBUGMSGTL((MODNAME_STR, "nextpr: built fake index: "));
 505  555                  DEBUGMSGVAR((MODNAME_STR, table_info->indexes));
 506  556                  DEBUGMSG((MODNAME_STR, "\n"));
 507  557          } else {
 508  558                  /*
 509  559                   * Construct the next possible UUID to look for.  We can
 510  560                   * simply increment the least significant byte of the last
 511  561                   * UUID because (a) that preserves SNMP lex order and (b)
 512  562                   * the characters that may appear in a UUID do not include
 513  563                   * 127 nor 255.
 514  564                   */
↓ open down ↓ 127 lines elided ↑ open up ↑
 642  692                                  tmpoid[reginfo->rootoid_len + 1] =
 643  693                                      table_info->colnum;
 644  694                                  if (build_oid_segment(var) != SNMPERR_SUCCESS) {
 645  695                                          snmp_free_varbind(var);
 646  696                                          return (NULL);
 647  697                                  }
 648  698                                  snmp_free_varbind(
 649  699                                      table_info->indexes->next_variable);
 650  700                                  table_info->indexes->next_variable = var;
 651  701                                  table_info->number_indexes = 2;
 652      -                                DEBUGMSGTL((MODNAME_STR, "nextfe: built fake "
 653      -                                    "index:\n"));
      702 +                                DEBUGMSGTL((MODNAME_STR,
      703 +                                    "nextfe: built fake index: "));
 654  704                                  DEBUGMSGVAR((MODNAME_STR, table_info->indexes));
 655  705                                  DEBUGMSG((MODNAME_STR, "\n"));
 656  706                                  DEBUGMSGVAR((MODNAME_STR,
 657  707                                      table_info->indexes->next_variable));
 658  708                                  DEBUGMSG((MODNAME_STR, "\n"));
 659  709                          } else {
 660  710                                  if (sunFmProblemTable_nextpr(reginfo,
 661  711                                      table_info) == NULL)
 662  712                                          return (NULL);
 663  713                          }
↓ open down ↓ 20 lines elided ↑ open up ↑
 684  734  
 685  735          *statusp = faultstatus_lookup_index_exact(data,
 686  736              *(ulong_t *)table_info->indexes->next_variable->val.integer);
 687  737          if (*statusp == 0)
 688  738                  return (NULL);
 689  739          return (faultevent_lookup_index_exact(data,
 690  740              *(ulong_t *)table_info->indexes->next_variable->val.integer));
 691  741  }
 692  742  
 693  743  /*ARGSUSED*/
 694      -static void
 695      -sunFmProblemTable_return(unsigned int reg, void *arg)
      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)
 696  748  {
 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  749          netsnmp_table_request_info      *table_info;
 702  750          sunFmProblem_data_t             *data;
      751 +        int                             ret = SNMP_ERR_NOERROR;
 703  752  
 704      -        ASSERT(netsnmp_handler_check_cache(cache) != NULL);
      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);
 705  758  
 706  759          (void) pthread_mutex_lock(&update_lock);
 707      -        if (update_status != US_QUIET) {
 708      -                struct timeval                  tv;
 709  760  
 710      -                tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 711      -                tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
      761 +        for (; request != NULL; request = request->next) {
      762 +                table_info = netsnmp_extract_table_info(request);
      763 +                if (table_info == NULL)
      764 +                        continue;
 712  765  
 713      -                (void) snmp_alarm_register_hr(tv, 0, sunFmProblemTable_return,
 714      -                    cache);
 715      -                (void) pthread_mutex_unlock(&update_lock);
 716      -                return;
 717      -        }
      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 +                }
 718  797  
 719      -        request = cache->requests;
 720      -        reqinfo = cache->reqinfo;
 721      -        reginfo = cache->reginfo;
      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];
 722  807  
 723      -        table_info = netsnmp_extract_table_info(request);
 724      -        request->delegated = 0;
      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);
 725  865  
 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;
      866 +                        (void) netsnmp_table_build_result(reginfo, request,
      867 +                            table_info, ASN_OCTET_STR, dt, dt_size);
      868 +                        break;
 751  869                  }
 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;
      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;
 760  881                  }
 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  882          }
 769  883  
 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);
      884 +out:
 826  885          (void) pthread_mutex_unlock(&update_lock);
      886 +        return (ret);
 827  887  }
 828  888  
      889 +/*ARGSUSED*/
 829  890  static int
 830      -sunFmProblemTable_handler(netsnmp_mib_handler *handler,
      891 +sunFmFaultEventTable_handler(netsnmp_mib_handler *handler,
 831  892      netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
 832      -    netsnmp_request_info *requests)
      893 +    netsnmp_request_info *request)
 833  894  {
 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  895          netsnmp_table_request_info      *table_info;
 868      -        sunFmProblem_data_t             *pdata;
 869  896          sunFmFaultEvent_data_t          *data;
 870  897          sunFmFaultStatus_data_t         status;
      898 +        sunFmProblem_data_t             *pdata;
      899 +        int                             ret = SNMP_ERR_NOERROR;
 871  900  
 872      -        ASSERT(netsnmp_handler_check_cache(cache) != NULL);
      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);
 873  906  
 874  907          (void) pthread_mutex_lock(&update_lock);
 875      -        if (update_status != US_QUIET) {
 876      -                struct timeval                  tv;
 877  908  
 878      -                tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 879      -                tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
      909 +        for (; request != NULL; request = request->next) {
      910 +                table_info = netsnmp_extract_table_info(request);
      911 +                if (table_info == NULL)
      912 +                        continue;
 880  913  
 881      -                (void) snmp_alarm_register_hr(tv, 0,
 882      -                    sunFmFaultEventTable_return, cache);
 883      -                (void) pthread_mutex_unlock(&update_lock);
 884      -                return;
 885      -        }
      914 +                ASSERT(table_info->colnum >= SUNFMFAULTEVENT_COLMIN);
      915 +                ASSERT(table_info->colnum <= SUNFMFAULTEVENT_COLMAX);
 886  916  
 887      -        request = cache->requests;
 888      -        reqinfo = cache->reqinfo;
 889      -        reginfo = cache->reginfo;
      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 +                }
 890  950  
 891      -        table_info = netsnmp_extract_table_info(request);
 892      -        request->delegated = 0;
      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 = "-";
 893  967  
 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;
      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;
 919  973                  }
 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      -        }
      974 +                case SUNFMFAULTEVENT_COL_CERTAINTY: {
      975 +                        uint8_t pct = 0;
      976 +                        ulong_t pl;
 937  977  
 938      -        switch (table_info->colnum) {
 939      -        case SUNFMFAULTEVENT_COL_PROBLEMUUID:
 940      -        {
 941      -                if ((pdata = sunFmProblemTable_pr(reginfo, table_info))
 942      -                    == NULL) {
      978 +                        (void) nvlist_lookup_uint8(data, FM_FAULT_CERTAINTY,
      979 +                            &pct);
      980 +                        pl = (ulong_t)pct;
 943  981                          (void) netsnmp_table_build_result(reginfo, request,
 944      -                            table_info, ASN_OCTET_STR, NULL, 0);
      982 +                            table_info, ASN_UNSIGNED, (uchar_t *)&pl,
      983 +                            sizeof (pl));
 945  984                          break;
 946  985                  }
 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 = "-";
      986 +                case SUNFMFAULTEVENT_COL_ASRU: {
      987 +                        nvlist_t        *asru = NULL;
      988 +                        char            *fmri = "-", *str;
 955  989  
 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;
      990 +                        (void) nvlist_lookup_nvlist(data, FM_FAULT_ASRU, &asru);
      991 +                        if ((str = nvl2fmri(asru)) != NULL)
      992 +                                fmri = str;
 965  993  
 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;
      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;
 977 1003  
 978      -                (void) nvlist_lookup_nvlist(data, FM_FAULT_ASRU, &asru);
 979      -                if ((str = sunFm_nvl2str(asru)) == NULL)
 980      -                        fmri = "-";
 981      -                else
 982      -                        fmri = str;
     1004 +                        (void) nvlist_lookup_nvlist(data, FM_FAULT_FRU, &fru);
     1005 +                        if ((str = nvl2fmri(fru)) != NULL)
     1006 +                                fmri = str;
 983 1007  
 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;
     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;
 993 1017  
 994      -                (void) nvlist_lookup_nvlist(data, FM_FAULT_FRU, &fru);
 995      -                if ((str = sunFm_nvl2str(fru)) == NULL)
 996      -                        fmri = "-";
 997      -                else
 998      -                        fmri = str;
     1018 +                        (void) nvlist_lookup_nvlist(data, FM_FAULT_RESOURCE,
     1019 +                            &rsrc);
     1020 +                        if ((str = nvl2fmri(rsrc)) != NULL)
     1021 +                                fmri = str;
 999 1022  
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;
     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;
1009 1031  
1010      -                (void) nvlist_lookup_nvlist(data, FM_FAULT_RESOURCE, &rsrc);
1011      -                if ((str = sunFm_nvl2str(rsrc)) == NULL)
1012      -                        fmri = "-";
1013      -                else
1014      -                        fmri = str;
     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 = "-";
1015 1049  
1016      -                (void) netsnmp_table_build_result(reginfo, request, table_info,
1017      -                    ASN_OCTET_STR, (uchar_t *)fmri, strlen(fmri));
1018      -                free(str);
1019      -                break;
     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 +                }
1020 1060          }
1021      -        case SUNFMFAULTEVENT_COL_STATUS:
1022      -        {
1023      -                ulong_t pl = SUNFMFAULTEVENT_STATE_OTHER;
1024 1061  
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);
     1062 +out:
1053 1063          (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);
     1064 +        return (ret);
1084 1065  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX