Print this page
    
5835 fix printf tokens for net-snmp 5.7.2
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/fm/libfmd_snmp/common/resource.c
          +++ new/usr/src/lib/fm/libfmd_snmp/common/resource.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  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   27  #include <fm/fmd_adm.h>
  28   28  #include <fm/fmd_snmp.h>
  29   29  #include <net-snmp/net-snmp-config.h>
  30   30  #include <net-snmp/net-snmp-includes.h>
  31   31  #include <net-snmp/agent/net-snmp-agent-includes.h>
  32   32  #include <pthread.h>
  33   33  #include <stddef.h>
  34   34  #include <errno.h>
  35   35  #include <libuutil.h>
  36   36  #include "sunFM_impl.h"
  37   37  #include "resource.h"
  38   38  
  39   39  static uu_avl_pool_t    *rsrc_fmri_avl_pool;
  40   40  static uu_avl_pool_t    *rsrc_index_avl_pool;
  41   41  static uu_avl_t         *rsrc_fmri_avl;
  42   42  static uu_avl_t         *rsrc_index_avl;
  43   43  
  44   44  #define VALID_AVL_STATE (rsrc_fmri_avl_pool != NULL &&          \
  45   45          rsrc_index_avl_pool != NULL && rsrc_fmri_avl != NULL && \
  46   46          rsrc_index_avl != NULL)
  47   47  
  48   48  #define UPDATE_WAIT_MILLIS      10      /* poll interval in milliseconds */
  49   49  
  50   50  /*
  51   51   * Update types: single-index and all are mutually exclusive; a count
  52   52   * update is optional.
  53   53   */
  54   54  #define UCT_INDEX       0x1
  55   55  #define UCT_ALL         0x2
  56   56  #define UCT_COUNT       0x4
  57   57  #define UCT_FLAGS       0x7
  58   58  
  59   59  #define RESOURCE_DATA_VALID(d)  ((d)->d_valid == valid_stamp)
  60   60  
  61   61  /*
  62   62   * Locking strategy is described in module.c.
  63   63   */
  64   64  static ulong_t          max_index;
  65   65  static int              valid_stamp;
  66   66  static uint32_t         rsrc_count;
  67   67  static pthread_mutex_t  update_lock;
  68   68  static pthread_cond_t   update_cv;
  69   69  static volatile enum { US_QUIET, US_NEEDED, US_INPROGRESS } update_status;
  70   70  
  71   71  static Netsnmp_Node_Handler     sunFmResourceTable_handler;
  72   72  static Netsnmp_Node_Handler     sunFmResourceCount_handler;
  73   73  
  74   74  static sunFmResource_data_t *
  75   75  key_build(const char *fmri, const ulong_t index)
  76   76  {
  77   77          static sunFmResource_data_t     key;
  78   78  
  79   79          key.d_index = index;
  80   80          if (fmri)
  81   81                  (void) strlcpy(key.d_ari_fmri, fmri, sizeof (key.d_ari_fmri));
  82   82          else
  83   83                  key.d_ari_fmri[0] = '\0';
  84   84  
  85   85          return (&key);
  86   86  }
  87   87  
  88   88  /*
  89   89   * If fmri is the fmri of a resource we have previously seen and indexed, return
  90   90   * data for it.  Otherwise, return NULL.  Note that the resource may not be
  91   91   * valid; that is, it may have been removed from the fault manager since its
  92   92   * information was last updated.
  93   93   */
  94   94  static sunFmResource_data_t *
  95   95  resource_lookup_fmri(const char *fmri)
  96   96  {
  97   97          sunFmResource_data_t    *key;
  98   98  
  99   99          key = key_build(fmri, 0);
 100  100          return (uu_avl_find(rsrc_fmri_avl, key, NULL, NULL));
 101  101  }
 102  102  
 103  103  /*
 104  104   * If index corresponds to a resource we have previously seen and indexed,
 105  105   * return data for it.  Otherwise, return NULL.  Note that the resource may
 106  106   * not be valid; that is, it may have been expired from the fault manager
 107  107   * since its information was last updated.
 108  108   */
 109  109  static sunFmResource_data_t *
 110  110  resource_lookup_index_exact(const ulong_t index)
 111  111  {
 112  112          sunFmResource_data_t    *key;
 113  113  
 114  114          key = key_build(NULL, index);
 115  115          return (uu_avl_find(rsrc_index_avl, key, NULL, NULL));
 116  116  }
 117  117  
 118  118  /*
 119  119   * If index corresponds to a valid (that is, extant as of latest information
 120  120   * from the fault manager) resource, return the data for that resource.
 121  121   * Otherwise, return the data for the valid resource whose index is as close as
 122  122   * possible to index but not lower.  This preserves the lexicographical
 123  123   * ordering required for GETNEXT processing.
 124  124   */
 125  125  static sunFmResource_data_t *
 126  126  resource_lookup_index_nextvalid(const ulong_t index)
 127  127  {
 128  128          sunFmResource_data_t    *key, *data;
 129  129          uu_avl_index_t          idx;
 130  130  
 131  131          key = key_build(NULL, index);
 132  132  
 133  133          if ((data = uu_avl_find(rsrc_index_avl, key, NULL, &idx)) != NULL &&
 134  134              RESOURCE_DATA_VALID(data))
 135  135                  return (data);
 136  136  
 137  137          data = uu_avl_nearest_next(rsrc_index_avl, idx);
 138  138  
 139  139          while (data != NULL && !RESOURCE_DATA_VALID(data))
 140  140                  data = uu_avl_next(rsrc_index_avl, data);
 141  141  
 142  142          return (data);
 143  143  }
 144  144  
 145  145  /*
 146  146   * Possible update the contents of a single resource within the cache.  This
 147  147   * is our callback from fmd_rsrc_iter.
 148  148   */
 149  149  static int
 150  150  rsrcinfo_update_one(const fmd_adm_rsrcinfo_t *rsrcinfo, void *arg)
 151  151  {
 152  152          const sunFmResource_update_ctx_t *update_ctx =
 153  153              (sunFmResource_update_ctx_t *)arg;
 154  154          sunFmResource_data_t *data = resource_lookup_fmri(rsrcinfo->ari_fmri);
 155  155  
 156  156          ++rsrc_count;
 157  157  
 158  158          /*
 159  159           * A resource we haven't seen before.  We're obligated to index
 160  160           * it and link it into our cache so that we can find it, but we're
 161  161           * not obligated to fill it in completely unless we're doing a
 162  162           * full update or this is the resource we were asked for.  This
 163  163           * avoids unnecessary iteration and memory manipulation for data
 164  164           * we're not going to return for this request.
 165  165           */
 166  166          if (data == NULL) {
 167  167                  uu_avl_index_t idx;
 168  168  
 169  169                  DEBUGMSGTL((MODNAME_STR, "found new resource %s\n",
 170  170                      rsrcinfo->ari_fmri));
 171  171                  if ((data = SNMP_MALLOC_TYPEDEF(sunFmResource_data_t)) ==
 172  172                      NULL) {
 173  173                          (void) snmp_log(LOG_ERR, MODNAME_STR ": Out of memory "
 174  174                              "for new resource data at %s:%d\n", __FILE__,
 175  175                              __LINE__);
 176  176                          return (1);
 177  177                  }
 178  178                  /*
 179  179                   * We allocate indices sequentially and never reuse them.
 180  180                   * This ensures we can always return valid GETNEXT responses
 181  181                   * without having to reindex, and it provides the user a
 182  182                   * more consistent view of the fault manager.
 183  183                   */
 184  184                  data->d_index = ++max_index;
 185  185                  DEBUGMSGTL((MODNAME_STR, "index %lu is %s@%p\n", data->d_index,
 186  186                      rsrcinfo->ari_fmri, data));
 187  187  
 188  188                  (void) strlcpy(data->d_ari_fmri, rsrcinfo->ari_fmri,
 189  189                      sizeof (data->d_ari_fmri));
 190  190  
 191  191                  uu_avl_node_init(data, &data->d_fmri_avl, rsrc_fmri_avl_pool);
 192  192                  (void) uu_avl_find(rsrc_fmri_avl, data, NULL, &idx);
 193  193                  uu_avl_insert(rsrc_fmri_avl, data, idx);
 194  194  
  
    | 
      ↓ open down ↓ | 
    194 lines elided | 
    
      ↑ open up ↑ | 
  
 195  195                  uu_avl_node_init(data, &data->d_index_avl, rsrc_index_avl_pool);
 196  196                  (void) uu_avl_find(rsrc_index_avl, data, NULL, &idx);
 197  197                  uu_avl_insert(rsrc_index_avl, data, idx);
 198  198  
 199  199                  DEBUGMSGTL((MODNAME_STR, "completed new resource %lu/%s@%p\n",
 200  200                      data->d_index, data->d_ari_fmri, data));
 201  201          }
 202  202  
 203  203          data->d_valid = valid_stamp;
 204  204  
 205      -        DEBUGMSGTL((MODNAME_STR, "timestamp updated for %lu/%s@%p: %lu\n",
      205 +        DEBUGMSGTL((MODNAME_STR, "timestamp updated for %lu/%s@%p: %d\n",
 206  206              data->d_index, data->d_ari_fmri, data, data->d_valid));
 207  207  
 208  208          if ((update_ctx->uc_type & UCT_ALL) ||
 209  209              update_ctx->uc_index == data->d_index) {
 210  210                  (void) strlcpy(data->d_ari_case, rsrcinfo->ari_case,
 211  211                      sizeof (data->d_ari_case));
 212  212                  data->d_ari_flags = rsrcinfo->ari_flags;
 213  213          }
 214  214  
 215  215          return (!(update_ctx->uc_type & UCT_ALL) &&
 216  216              update_ctx->uc_index == data->d_index);
 217  217  }
 218  218  
 219  219  /*
 220  220   * Update some or all resource data from fmd.  If type includes UCT_ALL, all
 221  221   * resources will be indexed and their data cached.  If type includes
 222  222   * UCT_INDEX, updates will stop once the resource matching index has been
 223  223   * updated.  If UCT_COUNT is set, the number of faulted resources will be
 224  224   * set.
 225  225   *
 226  226   * Returns appropriate SNMP error codes.
 227  227   */
 228  228  static int
 229  229  rsrcinfo_update(sunFmResource_update_ctx_t *update_ctx)
 230  230  {
 231  231          fmd_adm_t *adm;
 232  232          int err;
 233  233  
 234  234          ASSERT(update_ctx != NULL);
 235  235          ASSERT((update_ctx->uc_type & (UCT_ALL|UCT_INDEX)) !=
 236  236              (UCT_ALL|UCT_INDEX));
 237  237          ASSERT((update_ctx->uc_type & ~UCT_FLAGS) == 0);
 238  238          ASSERT(VALID_AVL_STATE);
 239  239  
 240  240          if ((adm = fmd_adm_open(update_ctx->uc_host, update_ctx->uc_prog,
 241  241              update_ctx->uc_version)) == NULL) {
 242  242                  (void) snmp_log(LOG_ERR, MODNAME_STR ": Communication with fmd "
 243  243                      "failed: %s\n", strerror(errno));
 244  244                  return (SNMP_ERR_RESOURCEUNAVAILABLE);
 245  245          }
 246  246  
 247  247          if (update_ctx->uc_type == UCT_COUNT) {
 248  248                  err = fmd_adm_rsrc_count(adm, update_ctx->uc_all, &rsrc_count);
 249  249          } else {
 250  250                  ++valid_stamp;
 251  251                  rsrc_count = 0;
 252  252                  err = fmd_adm_rsrc_iter(adm, update_ctx->uc_all,
 253  253                      rsrcinfo_update_one, update_ctx);
 254  254                  DEBUGMSGTL((MODNAME_STR, "resource iteration completed\n"));
 255  255          }
 256  256  
 257  257          fmd_adm_close(adm);
 258  258  
 259  259          if (err != 0) {
 260  260                  (void) snmp_log(LOG_ERR, MODNAME_STR ": fmd resource "
 261  261                      "information update failed: %s\n", fmd_adm_errmsg(adm));
 262  262                  return (SNMP_ERR_RESOURCEUNAVAILABLE);
 263  263          }
 264  264  
 265  265          return (SNMP_ERR_NOERROR);
 266  266  }
 267  267  
 268  268  /*ARGSUSED*/
 269  269  static void
 270  270  update_thread(void *arg)
 271  271  {
 272  272          /*
 273  273           * The current rsrcinfo_update implementation offers minimal savings
 274  274           * for the use of index-only updates; therefore we always do a full
 275  275           * update.  If it becomes advantageous to limit updates to a single
 276  276           * index, the contexts can be queued by the handler instead.
 277  277           */
 278  278          sunFmResource_update_ctx_t      uc;
 279  279  
 280  280          uc.uc_host = NULL;
 281  281          uc.uc_prog = FMD_ADM_PROGRAM;
 282  282          uc.uc_version = FMD_ADM_VERSION;
 283  283  
 284  284          uc.uc_all = 0;
 285  285          uc.uc_index = 0;
 286  286          uc.uc_type = UCT_ALL;
 287  287  
 288  288          for (;;) {
 289  289                  (void) pthread_mutex_lock(&update_lock);
 290  290                  update_status = US_QUIET;
 291  291                  while (update_status == US_QUIET)
 292  292                          (void) pthread_cond_wait(&update_cv, &update_lock);
 293  293                  update_status = US_INPROGRESS;
 294  294                  (void) pthread_mutex_unlock(&update_lock);
 295  295                  (void) rsrcinfo_update(&uc);
 296  296          }
 297  297  }
 298  298  
 299  299  static void
 300  300  request_update(void)
 301  301  {
 302  302          (void) pthread_mutex_lock(&update_lock);
 303  303          if (update_status != US_QUIET) {
 304  304                  (void) pthread_mutex_unlock(&update_lock);
 305  305                  return;
 306  306          }
 307  307          update_status = US_NEEDED;
 308  308          (void) pthread_cond_signal(&update_cv);
 309  309          (void) pthread_mutex_unlock(&update_lock);
 310  310  }
 311  311  
 312  312  /*ARGSUSED*/
 313  313  static int
 314  314  resource_compare_fmri(const void *l, const void *r, void *private)
 315  315  {
 316  316          sunFmResource_data_t    *l_data = (sunFmResource_data_t *)l;
 317  317          sunFmResource_data_t    *r_data = (sunFmResource_data_t *)r;
 318  318  
 319  319          ASSERT(l_data != NULL && r_data != NULL);
 320  320  
 321  321          return (strcmp(l_data->d_ari_fmri, r_data->d_ari_fmri));
 322  322  }
 323  323  
 324  324  /*ARGSUSED*/
 325  325  static int
 326  326  resource_compare_index(const void *l, const void *r, void *private)
 327  327  {
 328  328          sunFmResource_data_t    *l_data = (sunFmResource_data_t *)l;
 329  329          sunFmResource_data_t    *r_data = (sunFmResource_data_t *)r;
 330  330  
 331  331          ASSERT(l_data != NULL && r_data != NULL);
 332  332  
 333  333          return (l_data->d_index < r_data->d_index ? -1 :
 334  334              l_data->d_index > r_data->d_index ? 1 : 0);
 335  335  }
 336  336  
 337  337  int
 338  338  sunFmResourceTable_init(void)
 339  339  {
 340  340          static oid sunFmResourceTable_oid[] = { SUNFMRESOURCETABLE_OID };
 341  341          static oid sunFmResourceCount_oid[] = { SUNFMRESOURCECOUNT_OID, 0 };
 342  342          netsnmp_table_registration_info *table_info;
 343  343          netsnmp_handler_registration *handler;
 344  344          int err;
 345  345  
 346  346          if ((err = pthread_mutex_init(&update_lock, NULL)) != 0) {
 347  347                  (void) snmp_log(LOG_ERR, MODNAME_STR ": mutex_init failure: "
 348  348                      "%s\n", strerror(err));
 349  349                  return (MIB_REGISTRATION_FAILED);
 350  350          }
 351  351          if ((err = pthread_cond_init(&update_cv, NULL)) != 0) {
 352  352                  (void) snmp_log(LOG_ERR, MODNAME_STR ": cond_init failure: "
 353  353                      "%s\n", strerror(err));
 354  354                  return (MIB_REGISTRATION_FAILED);
 355  355          }
 356  356  
 357  357          if ((err = pthread_create(NULL, NULL, (void *(*)(void *))update_thread,
 358  358              NULL)) != 0) {
 359  359                  (void) snmp_log(LOG_ERR, MODNAME_STR ": error creating update "
 360  360                      "thread: %s\n", strerror(err));
 361  361                  return (MIB_REGISTRATION_FAILED);
 362  362          }
 363  363  
 364  364          if ((table_info =
 365  365              SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL)
 366  366                  return (MIB_REGISTRATION_FAILED);
 367  367  
 368  368          if ((handler = netsnmp_create_handler_registration("sunFmResourceTable",
 369  369              sunFmResourceTable_handler, sunFmResourceTable_oid,
 370  370              OID_LENGTH(sunFmResourceTable_oid), HANDLER_CAN_RONLY)) == NULL) {
 371  371                  SNMP_FREE(table_info);
 372  372                  return (MIB_REGISTRATION_FAILED);
 373  373          }
 374  374  
 375  375          /*
 376  376           * The Net-SNMP template uses add_indexes here, but that
 377  377           * function is unsafe because it does not check for failure.
 378  378           */
 379  379          if (netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED) == NULL) {
 380  380                  SNMP_FREE(table_info);
 381  381                  SNMP_FREE(handler);
 382  382                  return (MIB_REGISTRATION_FAILED);
 383  383          }
 384  384  
 385  385          table_info->min_column = SUNFMRESOURCE_COLMIN;
 386  386          table_info->max_column = SUNFMRESOURCE_COLMAX;
 387  387  
 388  388          if ((rsrc_fmri_avl_pool = uu_avl_pool_create("rsrc_fmri",
 389  389              sizeof (sunFmResource_data_t),
 390  390              offsetof(sunFmResource_data_t, d_fmri_avl), resource_compare_fmri,
 391  391              UU_AVL_DEBUG)) == NULL) {
 392  392                  (void) snmp_log(LOG_ERR, MODNAME_STR ": rsrc_fmri avl pool "
 393  393                      "creation failed: %s\n", uu_strerror(uu_error()));
 394  394                  snmp_free_varbind(table_info->indexes);
 395  395                  SNMP_FREE(table_info);
 396  396                  SNMP_FREE(handler);
 397  397          }
 398  398  
 399  399          if ((rsrc_fmri_avl = uu_avl_create(rsrc_fmri_avl_pool, NULL,
 400  400              UU_AVL_DEBUG)) == NULL) {
 401  401                  (void) snmp_log(LOG_ERR, MODNAME_STR ": rsrc_fmri avl creation "
 402  402                      "failed: %s\n", uu_strerror(uu_error()));
 403  403                  snmp_free_varbind(table_info->indexes);
 404  404                  SNMP_FREE(table_info);
 405  405                  SNMP_FREE(handler);
 406  406                  uu_avl_pool_destroy(rsrc_fmri_avl_pool);
 407  407                  return (MIB_REGISTRATION_FAILED);
 408  408          }
 409  409  
 410  410          if ((rsrc_index_avl_pool = uu_avl_pool_create("rsrc_index",
 411  411              sizeof (sunFmResource_data_t),
 412  412              offsetof(sunFmResource_data_t, d_index_avl),
 413  413              resource_compare_index, UU_AVL_DEBUG)) == NULL) {
 414  414                  (void) snmp_log(LOG_ERR, MODNAME_STR ": rsrc_index avl pool "
 415  415                      "creation failed: %s\n", uu_strerror(uu_error()));
 416  416                  snmp_free_varbind(table_info->indexes);
 417  417                  SNMP_FREE(table_info);
 418  418                  SNMP_FREE(handler);
 419  419                  uu_avl_destroy(rsrc_fmri_avl);
 420  420                  uu_avl_pool_destroy(rsrc_fmri_avl_pool);
 421  421          }
 422  422  
 423  423          if ((rsrc_index_avl = uu_avl_create(rsrc_index_avl_pool, NULL,
 424  424              UU_AVL_DEBUG)) == NULL) {
 425  425                  (void) snmp_log(LOG_ERR, MODNAME_STR ": rsrc_index avl "
 426  426                      "creation failed: %s\n", uu_strerror(uu_error()));
 427  427                  snmp_free_varbind(table_info->indexes);
 428  428                  SNMP_FREE(table_info);
 429  429                  SNMP_FREE(handler);
 430  430                  uu_avl_destroy(rsrc_fmri_avl);
 431  431                  uu_avl_pool_destroy(rsrc_fmri_avl_pool);
 432  432                  uu_avl_pool_destroy(rsrc_index_avl_pool);
 433  433                  return (MIB_REGISTRATION_FAILED);
 434  434          }
 435  435  
 436  436          if ((err = netsnmp_register_table(handler, table_info)) !=
 437  437              MIB_REGISTERED_OK) {
 438  438                  snmp_free_varbind(table_info->indexes);
 439  439                  SNMP_FREE(table_info);
 440  440                  SNMP_FREE(handler);
 441  441                  uu_avl_destroy(rsrc_fmri_avl);
 442  442                  uu_avl_pool_destroy(rsrc_fmri_avl_pool);
 443  443                  uu_avl_destroy(rsrc_index_avl);
 444  444                  uu_avl_pool_destroy(rsrc_index_avl_pool);
 445  445                  return (err);
 446  446          }
 447  447  
 448  448          if ((err = netsnmp_register_read_only_instance(
 449  449              netsnmp_create_handler_registration("sunFmResourceCount",
 450  450              sunFmResourceCount_handler, sunFmResourceCount_oid,
 451  451              OID_LENGTH(sunFmResourceCount_oid), HANDLER_CAN_RONLY))) !=
 452  452              MIB_REGISTERED_OK) {
 453  453                  /*
 454  454                   * There's no way to unregister the table handler, so we
 455  455                   * can't free any of the data, either.
 456  456                   */
 457  457                  return (err);
 458  458          }
 459  459  
 460  460          return (MIB_REGISTERED_OK);
 461  461  }
 462  462  
 463  463  /*
 464  464   * These two functions form the core of GET/GETNEXT/GETBULK handling (the
 465  465   * only kind we do).  They perform two functions:
 466  466   *
 467  467   * - First, frob the request to set all the index variables to correspond
 468  468   *   to the value that's going to be returned.  For GET, this is a nop;
 469  469   *   for GETNEXT/GETBULK it always requires some work.
 470  470   * - Second, find and return the fmd resource information corresponding to
 471  471   *   the (possibly updated) indices.
 472  472   *
 473  473   * These should be as fast as possible; they run in the agent thread.
 474  474   */
 475  475  static sunFmResource_data_t *
 476  476  sunFmResourceTable_nextrsrc(netsnmp_handler_registration *reginfo,
 477  477      netsnmp_table_request_info *table_info)
 478  478  {
 479  479          sunFmResource_data_t    *data;
 480  480          netsnmp_variable_list   *var;
 481  481          ulong_t index;
 482  482  
 483  483          /*
 484  484           * If we have no index, we must make one.
 485  485           */
 486  486          if (table_info->number_indexes < 1) {
 487  487                  oid tmpoid[MAX_OID_LEN];
 488  488                  index = 1;
 489  489  
 490  490                  DEBUGMSGTL((MODNAME_STR, "nextrsrc: no indexes given\n"));
 491  491                  var = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
 492  492                  (void) snmp_set_var_typed_value(var, ASN_UNSIGNED,
 493  493                      (uchar_t *)&index, sizeof (index));
 494  494                  (void) memcpy(tmpoid, reginfo->rootoid,
 495  495                      reginfo->rootoid_len * sizeof (oid));
 496  496                  tmpoid[reginfo->rootoid_len] = 1;
 497  497                  tmpoid[reginfo->rootoid_len + 1] = table_info->colnum;
 498  498                  if (build_oid(&var->name, &var->name_length, tmpoid,
 499  499                      reginfo->rootoid_len + 2, var) != SNMPERR_SUCCESS) {
 500  500                          snmp_free_varbind(var);
 501  501                          return (NULL);
 502  502                  }
 503  503                  DEBUGMSGTL((MODNAME_STR, "nextrsrc: built fake index:\n"));
 504  504                  DEBUGMSGVAR((MODNAME_STR, var));
 505  505                  DEBUGMSG((MODNAME_STR, "\n"));
 506  506          } else {
 507  507                  var = snmp_clone_varbind(table_info->indexes);
 508  508                  index = *var->val.integer;
 509  509                  DEBUGMSGTL((MODNAME_STR, "nextrsrc: received index:\n"));
 510  510                  DEBUGMSGVAR((MODNAME_STR, var));
 511  511                  DEBUGMSG((MODNAME_STR, "\n"));
 512  512                  index++;
 513  513          }
 514  514  
 515  515          snmp_free_varbind(table_info->indexes);
 516  516          table_info->indexes = NULL;
 517  517          table_info->number_indexes = 0;
 518  518  
 519  519          if ((data = resource_lookup_index_nextvalid(index)) == NULL) {
 520  520                  DEBUGMSGTL((MODNAME_STR, "nextrsrc: exact match not found for "
 521  521                      "index %lu; trying next column\n", index));
 522  522                  if (table_info->colnum >=
 523  523                      netsnmp_find_table_registration_info(reginfo)->max_column) {
 524  524                          snmp_free_varbind(var);
 525  525                          DEBUGMSGTL((MODNAME_STR, "nextrsrc: out of columns\n"));
 526  526                          return (NULL);
 527  527                  }
 528  528                  table_info->colnum++;
 529  529                  index = 1;
 530  530  
 531  531                  data = resource_lookup_index_nextvalid(index);
 532  532          }
 533  533  
 534  534          if (data == NULL) {
 535  535                  DEBUGMSGTL((MODNAME_STR, "nextrsrc: exact match not found for "
 536  536                      "index %lu; stopping\n", index));
 537  537                  snmp_free_varbind(var);
 538  538                  return (NULL);
 539  539          }
 540  540  
 541  541          *var->val.integer = data->d_index;
 542  542          table_info->indexes = var;
 543  543          table_info->number_indexes = 1;
 544  544  
 545  545          DEBUGMSGTL((MODNAME_STR, "matching data is %lu/%s@%p\n", data->d_index,
 546  546              data->d_ari_fmri, data));
 547  547  
 548  548          return (data);
 549  549  }
 550  550  
 551  551  /*ARGSUSED*/
 552  552  static sunFmResource_data_t *
 553  553  sunFmResourceTable_rsrc(netsnmp_handler_registration *reginfo,
 554  554      netsnmp_table_request_info *table_info)
 555  555  {
 556  556          ASSERT(table_info->number_indexes == 1);
 557  557  
 558  558          return (resource_lookup_index_exact(table_info->index_oid[0]));
 559  559  }
 560  560  
 561  561  /*ARGSUSED*/
 562  562  static void
 563  563  sunFmResourceTable_return(unsigned int reg, void *arg)
 564  564  {
 565  565          netsnmp_delegated_cache         *cache = (netsnmp_delegated_cache *)arg;
 566  566          netsnmp_request_info            *request;
 567  567          netsnmp_agent_request_info      *reqinfo;
 568  568          netsnmp_handler_registration    *reginfo;
 569  569          netsnmp_table_request_info      *table_info;
 570  570          sunFmResource_data_t            *data;
 571  571          ulong_t                         rsrcstate;
 572  572  
 573  573          ASSERT(netsnmp_handler_check_cache(cache) != NULL);
 574  574  
 575  575          (void) pthread_mutex_lock(&update_lock);
 576  576          if (update_status != US_QUIET) {
 577  577                  struct timeval                  tv;
 578  578  
 579  579                  tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 580  580                  tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
 581  581  
 582  582                  (void) snmp_alarm_register_hr(tv, 0, sunFmResourceTable_return,
 583  583                      cache);
 584  584                  (void) pthread_mutex_unlock(&update_lock);
 585  585                  return;
 586  586          }
 587  587  
 588  588          request = cache->requests;
 589  589          reqinfo = cache->reqinfo;
 590  590          reginfo = cache->reginfo;
 591  591  
 592  592          table_info = netsnmp_extract_table_info(request);
 593  593          request->delegated = 0;
 594  594  
 595  595          ASSERT(table_info->colnum >= SUNFMRESOURCE_COLMIN);
 596  596          ASSERT(table_info->colnum <= SUNFMRESOURCE_COLMAX);
 597  597  
 598  598          /*
 599  599           * table_info->colnum contains the column number requested.
 600  600           * table_info->indexes contains a linked list of snmp variable
 601  601           * bindings for the indexes of the table.  Values in the list
 602  602           * have been set corresponding to the indexes of the
 603  603           * request.  We have other guarantees as well:
 604  604           *
 605  605           * - The column number is always within range.
 606  606           * - If we have no index data, table_info->index_oid_len is 0.
 607  607           * - We will never receive requests outside our table nor
 608  608           *   those with the first subid anything other than 1 (Entry)
 609  609           *   nor those without a column number.  This is true even
 610  610           *   for GETNEXT requests.
 611  611           */
 612  612  
 613  613          switch (reqinfo->mode) {
 614  614          case MODE_GET:
 615  615                  if ((data = sunFmResourceTable_rsrc(reginfo, table_info)) ==
 616  616                      NULL) {
 617  617                          netsnmp_free_delegated_cache(cache);
 618  618                          (void) pthread_mutex_unlock(&update_lock);
 619  619                          return;
 620  620                  }
 621  621                  break;
 622  622          case MODE_GETNEXT:
 623  623          case MODE_GETBULK:
 624  624                  if ((data = sunFmResourceTable_nextrsrc(reginfo, table_info)) ==
 625  625                      NULL) {
 626  626                          netsnmp_free_delegated_cache(cache);
 627  627                          (void) pthread_mutex_unlock(&update_lock);
 628  628                          return;
 629  629                  }
 630  630                  break;
 631  631          default:
 632  632                  (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request "
 633  633                      "mode %d\n", reqinfo->mode);
 634  634                  netsnmp_free_delegated_cache(cache);
 635  635                  (void) pthread_mutex_unlock(&update_lock);
 636  636                  return;
 637  637          }
 638  638  
 639  639          switch (table_info->colnum) {
 640  640          case SUNFMRESOURCE_COL_FMRI:
 641  641                  (void) netsnmp_table_build_result(reginfo, request, table_info,
 642  642                      ASN_OCTET_STR, (uchar_t *)data->d_ari_fmri,
 643  643                      strlen(data->d_ari_fmri));
 644  644                  break;
 645  645          case SUNFMRESOURCE_COL_STATUS:
 646  646                  switch (data->d_ari_flags &
 647  647                      (FMD_ADM_RSRC_FAULTY|FMD_ADM_RSRC_UNUSABLE)) {
 648  648                  default:
 649  649                          rsrcstate = SUNFMRESOURCE_STATE_OK;
 650  650                          break;
 651  651                  case FMD_ADM_RSRC_FAULTY:
 652  652                          rsrcstate = SUNFMRESOURCE_STATE_DEGRADED;
 653  653                          break;
 654  654                  case FMD_ADM_RSRC_UNUSABLE:
 655  655                          rsrcstate = SUNFMRESOURCE_STATE_UNKNOWN;
 656  656                          break;
 657  657                  case FMD_ADM_RSRC_FAULTY | FMD_ADM_RSRC_UNUSABLE:
 658  658                          rsrcstate = SUNFMRESOURCE_STATE_FAULTED;
 659  659                          break;
 660  660                  }
 661  661                  (void) netsnmp_table_build_result(reginfo, request, table_info,
 662  662                      ASN_INTEGER, (uchar_t *)&rsrcstate,
 663  663                      sizeof (rsrcstate));
 664  664                  break;
 665  665          case SUNFMRESOURCE_COL_DIAGNOSISUUID:
 666  666                  (void) netsnmp_table_build_result(reginfo, request, table_info,
 667  667                      ASN_OCTET_STR, (uchar_t *)data->d_ari_case,
 668  668                      strlen(data->d_ari_case));
 669  669                  break;
 670  670          default:
 671  671                  break;
 672  672          }
 673  673          netsnmp_free_delegated_cache(cache);
 674  674          (void) pthread_mutex_unlock(&update_lock);
 675  675  }
 676  676  
 677  677  static int
 678  678  sunFmResourceTable_handler(netsnmp_mib_handler *handler,
 679  679      netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
 680  680      netsnmp_request_info *requests)
 681  681  {
 682  682          netsnmp_request_info            *request;
 683  683          struct timeval                  tv;
 684  684  
 685  685          tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 686  686          tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
 687  687  
 688  688          request_update();
 689  689  
 690  690          for (request = requests; request; request = request->next) {
 691  691                  if (request->processed != 0)
 692  692                          continue;
 693  693  
 694  694                  if (netsnmp_extract_table_info(request) == NULL)
 695  695                          continue;
 696  696  
 697  697                  request->delegated = 1;
 698  698                  (void) snmp_alarm_register_hr(tv, 0, sunFmResourceTable_return,
 699  699                      (void *) netsnmp_create_delegated_cache(handler, reginfo,
 700  700                      reqinfo, request, NULL));
 701  701          }
 702  702  
 703  703          return (SNMP_ERR_NOERROR);
 704  704  }
 705  705  
 706  706  /*ARGSUSED*/
 707  707  static void
 708  708  sunFmResourceCount_return(unsigned int reg, void *arg)
 709  709  {
 710  710          netsnmp_delegated_cache         *cache = (netsnmp_delegated_cache *)arg;
 711  711          netsnmp_request_info            *request;
 712  712          netsnmp_agent_request_info      *reqinfo;
 713  713          ulong_t                         rsrc_count_long;
 714  714  
 715  715          ASSERT(netsnmp_handler_check_cache(cache) != NULL);
 716  716  
 717  717          (void) pthread_mutex_lock(&update_lock);
 718  718          if (update_status != US_QUIET) {
 719  719                  struct timeval  tv;
 720  720  
 721  721                  tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 722  722                  tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
 723  723  
 724  724                  (void) snmp_alarm_register_hr(tv, 0, sunFmResourceCount_return,
 725  725                      cache);
 726  726                  (void) pthread_mutex_unlock(&update_lock);
 727  727                  return;
 728  728          }
 729  729  
 730  730          request = cache->requests;
 731  731          reqinfo = cache->reqinfo;
 732  732  
 733  733          request->delegated = 0;
 734  734  
 735  735          switch (reqinfo->mode) {
 736  736          /*
 737  737           * According to the documentation, it's not possible for us ever to
 738  738           * be called with MODE_GETNEXT.  However, Net-SNMP does the following:
 739  739           * - set reqinfo->mode to MODE_GET
 740  740           * - invoke the handler
 741  741           * - set reqinfo->mode to MODE_GETNEXT (even if the request was not
 742  742           *   actually processed; i.e. it's been delegated)
 743  743           * Since we're called back later with the same reqinfo, we see
 744  744           * GETNEXT.  Therefore this case is needed to work around the
 745  745           * Net-SNMP bug.
 746  746           */
 747  747          case MODE_GET:
 748  748          case MODE_GETNEXT:
 749  749                  DEBUGMSGTL((MODNAME_STR, "resource count is %u\n", rsrc_count));
 750  750                  rsrc_count_long = (ulong_t)rsrc_count;
 751  751                  (void) snmp_set_var_typed_value(request->requestvb, ASN_GAUGE,
 752  752                      (uchar_t *)&rsrc_count_long, sizeof (rsrc_count_long));
 753  753                  break;
 754  754          default:
 755  755                  (void) snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request "
 756  756                      "mode %d\n", reqinfo->mode);
 757  757          }
 758  758  
 759  759          netsnmp_free_delegated_cache(cache);
 760  760          (void) pthread_mutex_unlock(&update_lock);
 761  761  }
 762  762  
 763  763  static int
 764  764  sunFmResourceCount_handler(netsnmp_mib_handler *handler,
 765  765      netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo,
 766  766      netsnmp_request_info *requests)
 767  767  {
 768  768          struct timeval  tv;
 769  769  
 770  770          tv.tv_sec = UPDATE_WAIT_MILLIS / 1000;
 771  771          tv.tv_usec = (UPDATE_WAIT_MILLIS % 1000) * 1000;
 772  772  
 773  773          request_update();
 774  774  
 775  775          /*
 776  776           * We are never called for a GETNEXT when registered as an
 777  777           * instance; it's handled for us and converted to a GET.
 778  778           * Also, an instance handler is given only one request at a time, so
 779  779           * we don't need to loop over a list of requests.
 780  780           */
 781  781  
 782  782          if (requests->processed != 0)
 783  783                  return (SNMP_ERR_NOERROR);
 784  784  
 785  785          requests->delegated = 1;
 786  786          (void) snmp_alarm_register_hr(tv, 0, sunFmResourceCount_return,
 787  787              (void *) netsnmp_create_delegated_cache(handler, reginfo,
 788  788              reqinfo, requests, NULL));
 789  789  
 790  790          return (SNMP_ERR_NOERROR);
 791  791  }
  
    | 
      ↓ open down ↓ | 
    576 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX