extend.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:50k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. #include <net-snmp/net-snmp-config.h>
  2. #include <net-snmp/net-snmp-includes.h>
  3. #include <net-snmp/agent/net-snmp-agent-includes.h>
  4. #include <net-snmp/agent/watcher.h>
  5. #include "agent/extend.h"
  6. #include "utilities/execute.h"
  7. #include "struct.h"
  8. #ifndef USING_UCD_SNMP_EXTENSIBLE_MODULE
  9. #include "util_funcs.h"
  10. #include "mibdefs.h"
  11. #define SHELLCOMMAND 3
  12. #endif
  13. oid  ns_extend_oid[]    = { 1, 3, 6, 1, 4, 1, 8072, 1, 3, 2 };
  14. oid  extend_count_oid[] = { 1, 3, 6, 1, 4, 1, 8072, 1, 3, 2, 1 };
  15. oid  extend_config_oid[] = { 1, 3, 6, 1, 4, 1, 8072, 1, 3, 2, 2 };
  16. oid  extend_out1_oid[]  = { 1, 3, 6, 1, 4, 1, 8072, 1, 3, 2, 3 };
  17. oid  extend_out2_oid[]  = { 1, 3, 6, 1, 4, 1, 8072, 1, 3, 2, 4 };
  18. typedef struct extend_registration_block_s {
  19.     netsnmp_table_data *dinfo;
  20.     oid                *root_oid;
  21.     size_t              oid_len;
  22.     long                num_entries;
  23.     netsnmp_extend     *ehead;
  24.     struct extend_registration_block_s *next;
  25. } extend_registration_block;
  26. extend_registration_block *ereg_head = NULL;
  27. #ifndef USING_UCD_SNMP_EXTENSIBLE_MODULE
  28. typedef struct netsnmp_old_extend_s {
  29.     int idx;
  30.     netsnmp_extend *exec_entry;
  31.     netsnmp_extend *efix_entry;
  32. } netsnmp_old_extend;
  33. int             num_compatability_entries = 0;
  34. int             max_compatability_entries = 50;
  35. netsnmp_old_extend *compatability_entries;
  36. WriteMethod fixExec2Error;
  37. FindVarMethod var_extensible_old;
  38. oid  old_extensible_variables_oid[] = { UCDAVIS_MIB, SHELLMIBNUM, 1 };
  39. struct variable2 old_extensible_variables[] = {
  40.     {MIBINDEX,     ASN_INTEGER,   RONLY, var_extensible_old, 1, {MIBINDEX}},
  41.     {ERRORNAME,    ASN_OCTET_STR, RONLY, var_extensible_old, 1, {ERRORNAME}},
  42.     {SHELLCOMMAND, ASN_OCTET_STR, RONLY, var_extensible_old, 1, {SHELLCOMMAND}},
  43.     {ERRORFLAG,    ASN_INTEGER,   RONLY, var_extensible_old, 1, {ERRORFLAG}},
  44.     {ERRORMSG,     ASN_OCTET_STR, RONLY, var_extensible_old, 1, {ERRORMSG}},
  45.     {ERRORFIX,     ASN_INTEGER,  RWRITE, var_extensible_old, 1, {ERRORFIX}},
  46.     {ERRORFIXCMD,  ASN_OCTET_STR, RONLY, var_extensible_old, 1, {ERRORFIXCMD}}
  47. };
  48. #endif
  49.         /*************************
  50.          *
  51.          *  Main initialisation routine
  52.          *
  53.          *************************/
  54. extend_registration_block *
  55. _find_extension_block( oid *name, size_t name_len )
  56. {
  57.     extend_registration_block         *eptr;
  58.     size_t len;
  59.     for ( eptr=ereg_head; eptr; eptr=eptr->next ) {
  60.         len = SNMP_MIN(name_len, eptr->oid_len);
  61.         if (!snmp_oid_compare( name, len, eptr->root_oid, eptr->oid_len))
  62.             return eptr;
  63.     }
  64.     return NULL;
  65. }
  66. extend_registration_block *
  67. _register_extend( oid *base, size_t len )
  68. {
  69.     extend_registration_block         *eptr;
  70.     oid oid_buf[MAX_OID_LEN];
  71.     netsnmp_table_data                *dinfo;
  72.     netsnmp_table_registration_info   *tinfo;
  73.     netsnmp_watcher_info              *winfo;
  74.     netsnmp_handler_registration      *reg;
  75.     for ( eptr=ereg_head; eptr; eptr=eptr->next ) {
  76.         if (!snmp_oid_compare( base, len, eptr->root_oid, eptr->oid_len))
  77.             return eptr;
  78.     }
  79.     if (!eptr) {
  80.         eptr = SNMP_MALLOC_TYPEDEF( extend_registration_block );
  81.         eptr->root_oid = snmp_duplicate_objid( base, len );
  82.         eptr->oid_len  = len;
  83.         eptr->num_entries = 0;
  84.         eptr->ehead       = NULL;
  85.         eptr->dinfo       = netsnmp_create_table_data( "nsExtendTable" );
  86.         eptr->next        = ereg_head;
  87.         ereg_head         = eptr;
  88.     }
  89.     dinfo = eptr->dinfo;
  90.     memcpy( oid_buf, base, len*sizeof(oid) );
  91.         /*
  92.          * Register the configuration table
  93.          */
  94.     tinfo = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info );
  95.     netsnmp_table_helper_add_indexes( tinfo, ASN_OCTET_STR, 0 );
  96.     tinfo->min_column = COLUMN_EXTCFG_FIRST_COLUMN;
  97.     tinfo->max_column = COLUMN_EXTCFG_LAST_COLUMN;
  98.     oid_buf[len] = 2;
  99.     reg   = netsnmp_create_handler_registration(
  100.                 "nsExtendConfigTable", handle_nsExtendConfigTable, 
  101.                 oid_buf, len+1, HANDLER_CAN_RWRITE);
  102.     netsnmp_register_table_data( reg, dinfo, tinfo );
  103.         /*
  104.          * Register the main output table
  105.          *   using the same table_data handle.
  106.          * This is sufficient to link the two tables,
  107.          *   and implement the AUGMENTS behaviour
  108.          */
  109.     tinfo = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info );
  110.     netsnmp_table_helper_add_indexes( tinfo, ASN_OCTET_STR, 0 );
  111.     tinfo->min_column = COLUMN_EXTOUT1_FIRST_COLUMN;
  112.     tinfo->max_column = COLUMN_EXTOUT1_LAST_COLUMN;
  113.     oid_buf[len] = 3;
  114.     reg   = netsnmp_create_handler_registration(
  115.                 "nsExtendOut1Table", handle_nsExtendOutput1Table, 
  116.                 oid_buf, len+1, HANDLER_CAN_RONLY);
  117.     netsnmp_register_table_data( reg, dinfo, tinfo );
  118.         /*
  119.          * Register the multi-line output table
  120.          *   using a simple table helper.
  121.          * This handles extracting the indexes from
  122.          *   the request OID, but leaves most of
  123.          *   the work to our handler routine.
  124.          * Still, it was nice while it lasted...
  125.          */
  126.     tinfo = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info );
  127.     netsnmp_table_helper_add_indexes( tinfo, ASN_OCTET_STR, ASN_INTEGER, 0 );
  128.     tinfo->min_column = COLUMN_EXTOUT2_FIRST_COLUMN;
  129.     tinfo->max_column = COLUMN_EXTOUT2_LAST_COLUMN;
  130.     oid_buf[len] = 4;
  131.     reg   = netsnmp_create_handler_registration(
  132.                 "nsExtendOut2Table", handle_nsExtendOutput2Table, 
  133.                 oid_buf, len+1, HANDLER_CAN_RONLY);
  134.     netsnmp_register_table( reg, tinfo );
  135.         /*
  136.          * Register a watched scalar to keep track of the number of entries
  137.          */
  138.     oid_buf[len] = 1;
  139.     reg   = netsnmp_create_handler_registration(
  140.                 "nsExtendNumEntries", NULL, 
  141.                 oid_buf, len+1, HANDLER_CAN_RONLY);
  142.     winfo = netsnmp_create_watcher_info(
  143.                 &(eptr->num_entries), sizeof(eptr->num_entries),
  144.                 ASN_INTEGER, WATCHER_FIXED_SIZE);
  145.     netsnmp_register_watched_scalar( reg, winfo );
  146.     return eptr;
  147. }
  148. void init_extend( void )
  149. {
  150.     snmpd_register_config_handler("extend",    extend_parse_config, NULL, NULL);
  151.     snmpd_register_config_handler("extend-sh", extend_parse_config, NULL, NULL);
  152.     snmpd_register_config_handler("extendfix", extend_parse_config, NULL, NULL);
  153.     snmpd_register_config_handler("exec2", extend_parse_config, NULL, NULL);
  154.     snmpd_register_config_handler("sh2",   extend_parse_config, NULL, NULL);
  155.     snmpd_register_config_handler("execFix2", extend_parse_config, NULL, NULL);
  156.     (void)_register_extend( ns_extend_oid, OID_LENGTH(ns_extend_oid));
  157. #ifndef USING_UCD_SNMP_EXTENSIBLE_MODULE
  158.     snmpd_register_config_handler("exec", extend_parse_config, NULL, NULL);
  159.     snmpd_register_config_handler("sh",   extend_parse_config, NULL, NULL);
  160.     snmpd_register_config_handler("execFix", extend_parse_config, NULL, NULL);
  161.     compatability_entries = calloc( max_compatability_entries,
  162.                                     sizeof(netsnmp_old_extend));
  163.     REGISTER_MIB("ucd-extensible", old_extensible_variables,
  164.                  variable2, old_extensible_variables_oid);
  165. #endif
  166. }
  167.         /*************************
  168.          *
  169.          *  Cached-data hooks
  170.          *  see 'cache_handler' helper
  171.          *
  172.          *************************/
  173. int
  174. extend_load_cache(netsnmp_cache *cache, void *magic)
  175. {
  176.     int  out_len = 1024*100;
  177.     char out_buf[ 1024*100 ];
  178.     int  cmd_len = 255*2 + 2; /* 2 * DisplayStrings */
  179.     char cmd_buf[ 255*2 + 2 ];
  180.     int  ret;
  181.     char *cp;
  182.     char *line_buf[ 1024 ];
  183.     netsnmp_extend *extension = (netsnmp_extend *)magic;
  184.     if (!magic)
  185.         return -1;
  186.     DEBUGMSGTL(( "nsExtendTable:cache", "load %s", extension->token ));
  187.     if ( extension->args )
  188.         snprintf( cmd_buf, cmd_len, "%s %s", extension->command, extension->args );
  189.     else 
  190.         snprintf( cmd_buf, cmd_len, "%s", extension->command );
  191.     if ( extension->flags & NS_EXTEND_FLAGS_SHELL )
  192.         ret = run_shell_command( cmd_buf, extension->input, out_buf, &out_len);
  193.     else
  194.         ret = run_exec_command(  cmd_buf, extension->input, out_buf, &out_len);
  195.     DEBUGMSG(( "nsExtendTable:cache", ": %s : %dn", cmd_buf, ret));
  196.     if (ret >= 0) {
  197.         if (out_buf[   out_len-1 ] == 'n')
  198.             out_buf[ --out_len   ] =  ''; /* Stomp on trailing newline */
  199.         extension->output   = strdup( out_buf );
  200.         extension->out_len  = out_len;
  201.         /*
  202.          * Now we need to pick the output apart into separate lines.
  203.          * Start by counting how many lines we've got, and keeping
  204.          * track of where each line starts in a static buffer
  205.          */
  206.         extension->numlines = 1;
  207.         line_buf[ 0 ] = extension->output;
  208.         for (cp=extension->output; *cp; cp++) {
  209.             if (*cp == 'n') {
  210.                 line_buf[ extension->numlines++ ] = cp+1;
  211.             }
  212.         }
  213.         if ( extension->numlines > 1 ) {
  214.             extension->lines = calloc( sizeof(char *), extension->numlines );
  215.             memcpy( extension->lines, line_buf,
  216.                                        sizeof(char *) * extension->numlines );
  217.         }
  218.     }
  219.     extension->result = ret;
  220.     return ret;
  221. }
  222. void
  223. extend_free_cache(netsnmp_cache *cache, void *magic)
  224. {
  225.     netsnmp_extend *extension = (netsnmp_extend *)magic;
  226.     if (!magic)
  227.         return;
  228.     DEBUGMSGTL(( "nsExtendTable:cache", "free %sn", extension->token ));
  229.     if (extension->output) {
  230.         SNMP_FREE(extension->output);
  231.         extension->output = NULL;
  232.     }
  233.     if (extension->lines) {
  234.         SNMP_FREE(extension->lines);
  235.         extension->lines  = NULL;
  236.     }
  237.     extension->out_len  = 0;
  238.     extension->numlines = 0;
  239. }
  240.         /*************************
  241.          *
  242.          *  Utility routines for setting up a new entry
  243.          *  (either via SET requests, or the config file)
  244.          *
  245.          *************************/
  246. void
  247. _free_extension( netsnmp_extend *extension, extend_registration_block *ereg )
  248. {
  249.     netsnmp_extend *eptr  = NULL;
  250.     netsnmp_extend *eprev = NULL;
  251.     if (!extension)
  252.         return;
  253.     if (ereg) {
  254.         /* Unlink from 'ehead' list */
  255.         for (eptr=ereg->ehead; eptr; eptr=eptr->next) {
  256.             if (eptr == extension)
  257.                 break;
  258.             eprev = eptr;
  259.         }
  260.         if (eprev)
  261.             eprev->next = eptr->next;
  262.         else
  263.             ereg->ehead = eptr->next;
  264.     }
  265.     netsnmp_table_data_remove_and_delete_row( ereg->dinfo, extension->row);
  266.     SNMP_FREE( extension->token );
  267.     SNMP_FREE( extension->cache );
  268.     SNMP_FREE( extension->command );
  269.     SNMP_FREE( extension->args  );
  270.     SNMP_FREE( extension->input );
  271.     SNMP_FREE( extension );
  272.     return;
  273. }
  274. netsnmp_extend *
  275. _new_extension( char *exec_name, int exec_flags, extend_registration_block *ereg )
  276. {
  277.     netsnmp_extend     *extension;
  278.     netsnmp_table_row  *row;
  279.     netsnmp_extend     *eptr1, *eptr2; 
  280.     netsnmp_table_data *dinfo = ereg->dinfo;
  281.     if (!exec_name)
  282.         return NULL;
  283.     extension = SNMP_MALLOC_TYPEDEF( netsnmp_extend );
  284.     if (!extension)
  285.         return NULL;
  286.     extension->token    = strdup( exec_name );
  287.     extension->flags    = exec_flags;
  288.     extension->cache    = netsnmp_cache_create( 0, extend_load_cache,
  289.                                                    extend_free_cache, NULL, 0 );
  290.     if (extension->cache)
  291.         extension->cache->magic = extension;
  292.     row = netsnmp_create_table_data_row();
  293.     if (!row || !extension->cache) {
  294.         _free_extension( extension, ereg );
  295.         SNMP_FREE( row );
  296.         return NULL;
  297.     }
  298.     row->data = (void *)extension;
  299.     extension->row = row;
  300.     netsnmp_table_row_add_index( row, ASN_OCTET_STR,
  301.                                  exec_name, strlen(exec_name));
  302.     netsnmp_table_data_add_row( dinfo, row);
  303.     ereg->num_entries++;
  304.         /*
  305.          *  Now add this structure to a private linked list.
  306.          *  We don't need this for the main tables - the
  307.          *   'table_data' helper will take care of those.
  308.          *  But it's probably easier to handle the multi-line
  309.          *  output table ourselves, for which we need access
  310.          *  to the underlying data.
  311.          *   So we'll keep a list internally as well.
  312.          */
  313.     for ( eptr1 = ereg->ehead, eptr2 = NULL;
  314.           eptr1;
  315.           eptr2 = eptr1, eptr1 = eptr1->next ) {
  316.         if (strlen( eptr1->token )  > strlen( exec_name ))
  317.             break;
  318.         if (strlen( eptr1->token ) == strlen( exec_name ) &&
  319.             strcmp( eptr1->token, exec_name ) > 0 )
  320.             break;
  321.     }
  322.     if ( eptr2 )
  323.         eptr2->next = extension;
  324.     else
  325.         ereg->ehead = extension;
  326.     extension->next = eptr1;
  327.     return extension;
  328. }
  329. void
  330. extend_parse_config(const char *token, char *cptr)
  331. {
  332.     netsnmp_extend *extension;
  333.     char exec_name[STRMAX];
  334.     char exec_command[STRMAX];
  335.     oid  oid_buf[MAX_OID_LEN];
  336.     size_t oid_len;
  337.     extend_registration_block *eptr;
  338.     int  flags;
  339.     cptr = copy_nword(cptr, exec_name,    sizeof(exec_name));
  340.     if ( *exec_name == '.' ) {
  341.         oid_len = MAX_OID_LEN;
  342.         read_objid( exec_name, oid_buf, &oid_len );
  343.         cptr = copy_nword(cptr, exec_name,    sizeof(exec_name));
  344.     } else {
  345.         memcpy( oid_buf, ns_extend_oid, sizeof(ns_extend_oid));
  346.         oid_len = OID_LENGTH(ns_extend_oid);
  347.     }
  348.     cptr = copy_nword(cptr, exec_command, sizeof(exec_command));
  349.     /* XXX - check 'exec_command' exists & is executable */
  350.     flags = (NS_EXTEND_FLAGS_ACTIVE | NS_EXTEND_FLAGS_CONFIG);
  351.     if (!strcmp( token, "sh"        ) ||
  352.         !strcmp( token, "extend-sh" ) ||
  353.         !strcmp( token, "sh2" ))
  354.         flags |= NS_EXTEND_FLAGS_SHELL;
  355.     if (!strcmp( token, "execFix"   ) ||
  356.         !strcmp( token, "extendfix" ) ||
  357.         !strcmp( token, "execFix2" )) {
  358.         strcat( exec_name, "Fix" );
  359.         flags |= NS_EXTEND_FLAGS_WRITEABLE;
  360.         /* XXX - Check for shell... */
  361.     }
  362.     eptr      = _register_extend( oid_buf, oid_len );
  363.     extension = _new_extension( exec_name, flags, eptr );
  364.     if (extension) {
  365.         extension->command  = strdup( exec_command );
  366.         if (cptr)
  367.             extension->args = strdup( cptr );
  368.     }
  369. #ifndef USING_UCD_SNMP_EXTENSIBLE_MODULE
  370.     /*
  371.      *  Compatability with the UCD extTable
  372.      */
  373.     if (!strcmp( token, "execFix"  )) {
  374.         int  i;
  375.         for ( i=0; i < num_compatability_entries; i++ ) {
  376.             if (!strcmp( exec_name,
  377.                     compatability_entries[i].exec_entry->token))
  378.                 break;
  379.         }
  380.         if ( i == num_compatability_entries )
  381.             config_perror("No matching exec entry" );
  382.         else
  383.             compatability_entries[ i ].efix_entry = extension;
  384.             
  385.     } else if (!strcmp( token, "sh"   ) ||
  386.                !strcmp( token, "exec" )) {
  387.         if ( num_compatability_entries == max_compatability_entries )
  388.             /* XXX - should really use dynamic allocation */
  389.             config_perror("No further UCD-compatible entries" );
  390.         else
  391.             compatability_entries[
  392.                 num_compatability_entries++ ].exec_entry = extension;
  393.     }
  394. #endif
  395. }
  396.         /*************************
  397.          *
  398.          *  Main table handlers
  399.          *  Most of the work is handled
  400.          *   by the 'table_data' helper.
  401.          *
  402.          *************************/
  403. int
  404. handle_nsExtendConfigTable(netsnmp_mib_handler          *handler,
  405.                      netsnmp_handler_registration *reginfo,
  406.                      netsnmp_agent_request_info   *reqinfo,
  407.                      netsnmp_request_info         *requests)
  408. {
  409.     netsnmp_request_info       *request;
  410.     netsnmp_table_request_info *table_info;
  411.     netsnmp_extend             *extension;
  412.     extend_registration_block  *eptr;
  413.     int  i;
  414.     int  need_to_validate = 0;
  415.     for ( request=requests; request; request=request->next ) {
  416.         if (request->processed)
  417.             continue;
  418.         table_info = netsnmp_extract_table_info( request );
  419.         extension  = (netsnmp_extend*)netsnmp_extract_table_row_data( request );
  420.         DEBUGMSGTL(( "nsExtendTable:config", "varbind: "));
  421.         DEBUGMSGOID(("nsExtendTable:config", request->requestvb->name,
  422.                                              request->requestvb->name_length));
  423.         DEBUGMSG((   "nsExtendTable:config", " (%s)n",
  424.                       se_find_label_in_slist("agent_mode", reqinfo->mode)));
  425.         switch (reqinfo->mode) {
  426.         case MODE_GET:
  427.             switch (table_info->colnum) {
  428.             case COLUMN_EXTCFG_COMMAND:
  429.                 snmp_set_var_typed_value(
  430.                      request->requestvb, ASN_OCTET_STR,
  431.                      extension->command,
  432.                     (extension->command)?strlen(extension->command):0);
  433.                 break;
  434.             case COLUMN_EXTCFG_ARGS:
  435.                 snmp_set_var_typed_value(
  436.                      request->requestvb, ASN_OCTET_STR,
  437.                      extension->args,
  438.                     (extension->args)?strlen(extension->args):0);
  439.                 break;
  440.             case COLUMN_EXTCFG_INPUT:
  441.                 snmp_set_var_typed_value(
  442.                      request->requestvb, ASN_OCTET_STR,
  443.                      extension->input,
  444.                     (extension->input)?strlen(extension->input):0);
  445.                 break;
  446.             case COLUMN_EXTCFG_CACHETIME:
  447.                 snmp_set_var_typed_value(
  448.                      request->requestvb, ASN_INTEGER,
  449.                     (u_char*)&extension->cache->timeout, sizeof(int));
  450.                 break;
  451.             case COLUMN_EXTCFG_EXECTYPE:
  452.                 i = ((extension->flags & NS_EXTEND_FLAGS_SHELL) ?
  453.                                          NS_EXTEND_ETYPE_SHELL :
  454.                                          NS_EXTEND_ETYPE_EXEC);
  455.                 snmp_set_var_typed_value(
  456.                      request->requestvb, ASN_INTEGER,
  457.                     (u_char*)&i, sizeof(i));
  458.                 break;
  459.             case COLUMN_EXTCFG_RUNTYPE:
  460.                 i = ((extension->flags & NS_EXTEND_FLAGS_WRITEABLE) ?
  461.                                          NS_EXTEND_RTYPE_RWRITE :
  462.                                          NS_EXTEND_RTYPE_RONLY);
  463.                 snmp_set_var_typed_value(
  464.                      request->requestvb, ASN_INTEGER,
  465.                     (u_char*)&i, sizeof(i));
  466.                 break;
  467.             case COLUMN_EXTCFG_STORAGE:
  468.                 i = ((extension->flags & NS_EXTEND_FLAGS_CONFIG) ?
  469.                                          ST_PERMANENT : ST_VOLATILE);
  470.                 snmp_set_var_typed_value(
  471.                      request->requestvb, ASN_INTEGER,
  472.                     (u_char*)&i, sizeof(i));
  473.                 break;
  474.             case COLUMN_EXTCFG_STATUS:
  475.                 i = ((extension->flags & NS_EXTEND_FLAGS_ACTIVE) ?
  476.                                          RS_ACTIVE :
  477.                                          RS_NOTINSERVICE);
  478.                 snmp_set_var_typed_value(
  479.                      request->requestvb, ASN_INTEGER,
  480.                     (u_char*)&i, sizeof(i));
  481.                 break;
  482.             default:
  483.                 netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
  484.                 continue;
  485.             }
  486.             break;
  487.         /**********
  488.          *
  489.          * Start of SET handling
  490.          *
  491.          *   All config objects are potentially writable except
  492.          *     nsExtendStorage which is fixed as either 'permanent'
  493.          *     (if read from a config file) or 'volatile' (if set via SNMP)
  494.          *   The string-based settings of a 'permanent' entry cannot 
  495.          *     be changed - neither can the execution or run type.
  496.          *   Such entries can be (temporarily) marked as inactive,
  497.          *     and the cache timeout adjusted, but these changes are
  498.          *     not persistent.
  499.          *
  500.          **********/
  501.         case MODE_SET_RESERVE1:
  502.             /*
  503.              * Validate the new assignments
  504.              */
  505.             switch (table_info->colnum) {
  506.             case COLUMN_EXTCFG_COMMAND:
  507.                 if (request->requestvb->type != ASN_OCTET_STR) {
  508.                     netsnmp_set_request_error(reqinfo, request,
  509.                                               SNMP_ERR_WRONGTYPE);
  510.                     return SNMP_ERR_WRONGTYPE;
  511.                 }
  512.                 /*
  513.                  * Must have a full path to the command
  514.                  * XXX - Assumes Unix-style paths
  515.                  */
  516.                 if (request->requestvb->val_len == 0 ||
  517.                     request->requestvb->val.string[0] != '/') {
  518.                     netsnmp_set_request_error(reqinfo, request,
  519.                                               SNMP_ERR_WRONGVALUE);
  520.                     return SNMP_ERR_WRONGVALUE;
  521.                 }
  522.                 /*
  523.                  * XXX - need to check this file exists
  524.                  *       (and is executable)
  525.                  */
  526.                 if (extension && extension->flags & NS_EXTEND_FLAGS_CONFIG) {
  527.                     /*
  528.                      * config entries are "permanent" so can't be changed
  529.                      */
  530.                     netsnmp_set_request_error(reqinfo, request,
  531.                                               SNMP_ERR_NOTWRITABLE);
  532.                     return SNMP_ERR_NOTWRITABLE;
  533.                 }
  534.                 break;
  535.             case COLUMN_EXTCFG_ARGS:
  536.             case COLUMN_EXTCFG_INPUT:
  537.                 if (request->requestvb->type != ASN_OCTET_STR) {
  538.                     netsnmp_set_request_error(reqinfo, request,
  539.                                               SNMP_ERR_WRONGTYPE);
  540.                     return SNMP_ERR_WRONGTYPE;
  541.                 }
  542.                 if (extension && extension->flags & NS_EXTEND_FLAGS_CONFIG) {
  543.                     /*
  544.                      * config entries are "permanent" so can't be changed
  545.                      */
  546.                     netsnmp_set_request_error(reqinfo, request,
  547.                                               SNMP_ERR_NOTWRITABLE);
  548.                     return SNMP_ERR_NOTWRITABLE;
  549.                 }
  550.                 break;
  551.             case COLUMN_EXTCFG_CACHETIME:
  552.                 if (request->requestvb->type != ASN_INTEGER) {
  553.                     netsnmp_set_request_error(reqinfo, request,
  554.                                               SNMP_ERR_WRONGTYPE);
  555.                     return SNMP_ERR_WRONGTYPE;
  556.                 }
  557.                 i = *request->requestvb->val.integer;
  558.                 /*
  559.                  * -1 is a special value indicating "don't cache"
  560.                  *    [[ XXX - should this be 0 ?? ]]
  561.                  * Otherwise, cache times must be non-negative
  562.                  */
  563.                 if (i < -1 ) {
  564.                     netsnmp_set_request_error(reqinfo, request,
  565.                                               SNMP_ERR_WRONGVALUE);
  566.                     return SNMP_ERR_WRONGVALUE;
  567.                 }
  568.                 break;
  569.             case COLUMN_EXTCFG_EXECTYPE:
  570.                 if (request->requestvb->type != ASN_INTEGER) {
  571.                     netsnmp_set_request_error(reqinfo, request,
  572.                                               SNMP_ERR_WRONGTYPE);
  573.                     return SNMP_ERR_WRONGTYPE;
  574.                 }
  575.                 i = *request->requestvb->val.integer;
  576.                 if (i<1 || i>2) {  /* 'exec(1)' or 'shell(2)' only */
  577.                     netsnmp_set_request_error(reqinfo, request,
  578.                                               SNMP_ERR_WRONGVALUE);
  579.                     return SNMP_ERR_WRONGVALUE;
  580.                 }
  581.                 if (extension && extension->flags & NS_EXTEND_FLAGS_CONFIG) {
  582.                     /*
  583.                      * config entries are "permanent" so can't be changed
  584.                      */
  585.                     netsnmp_set_request_error(reqinfo, request,
  586.                                               SNMP_ERR_NOTWRITABLE);
  587.                     return SNMP_ERR_NOTWRITABLE;
  588.                 }
  589.                 break;
  590.             case COLUMN_EXTCFG_RUNTYPE:
  591.                 if (request->requestvb->type != ASN_INTEGER) {
  592.                     netsnmp_set_request_error(reqinfo, request,
  593.                                               SNMP_ERR_WRONGTYPE);
  594.                     return SNMP_ERR_WRONGTYPE;
  595.                 }
  596.                 /*
  597.                  * 'run-on-read(1)', 'run-on-set(2)'
  598.                  *  or 'run-command(3)' only
  599.                  */
  600.                 i = *request->requestvb->val.integer;
  601.                 if (i<1 || i>3) {
  602.                     netsnmp_set_request_error(reqinfo, request,
  603.                                               SNMP_ERR_WRONGVALUE);
  604.                     return SNMP_ERR_WRONGVALUE;
  605.                 }
  606.                 /*
  607.                  * 'run-command(3)' can only be used with
  608.                  *  a pre-existing 'run-on-set(2)' entry.
  609.                  */
  610.                 if (i==3 && !(extension && (extension->flags & NS_EXTEND_FLAGS_WRITEABLE))) {
  611.                     netsnmp_set_request_error(reqinfo, request,
  612.                                               SNMP_ERR_INCONSISTENTVALUE);
  613.                     return SNMP_ERR_INCONSISTENTVALUE;
  614.                 }
  615.                 /*
  616.                  * 'run-command(3)' is the only valid assignment
  617.                  *  for permanent (i.e. config) entries
  618.                  */
  619.                 if ((extension && extension->flags & NS_EXTEND_FLAGS_CONFIG)
  620.                     && i!=3 ) {
  621.                     netsnmp_set_request_error(reqinfo, request,
  622.                                               SNMP_ERR_INCONSISTENTVALUE);
  623.                     return SNMP_ERR_INCONSISTENTVALUE;
  624.                 }
  625.                 break;
  626.             case COLUMN_EXTCFG_STATUS:
  627.                 if (request->requestvb->type != ASN_INTEGER) {
  628.                     netsnmp_set_request_error(reqinfo, request,
  629.                                               SNMP_ERR_WRONGTYPE);
  630.                     return SNMP_ERR_WRONGTYPE;
  631.                 }
  632.                 i = *request->requestvb->val.integer;
  633.                 switch (i) {
  634.                 case RS_ACTIVE:
  635.                 case RS_NOTINSERVICE:
  636.                     if (!extension) {
  637.                         /* Must be used with existing rows */
  638.                         netsnmp_set_request_error(reqinfo, request,
  639.                                                   SNMP_ERR_INCONSISTENTVALUE);
  640.                         return SNMP_ERR_INCONSISTENTVALUE;
  641.                     }
  642.                     break;    /* OK */
  643.                 case RS_CREATEANDGO:
  644.                 case RS_CREATEANDWAIT:
  645.                     if (extension) {
  646.                         /* Can only be used to create new rows */
  647.                         netsnmp_set_request_error(reqinfo, request,
  648.                                                   SNMP_ERR_INCONSISTENTVALUE);
  649.                         return SNMP_ERR_INCONSISTENTVALUE;
  650.                     }
  651.                     break;
  652.                 case RS_DESTROY:
  653.                     break;
  654.                 default:
  655.                     netsnmp_set_request_error(reqinfo, request,
  656.                                               SNMP_ERR_WRONGVALUE);
  657.                     return SNMP_ERR_WRONGVALUE;
  658.                 }
  659.                 break;
  660.             default:
  661.                 netsnmp_set_request_error(reqinfo, request,
  662.                                           SNMP_ERR_NOTWRITABLE);
  663.                 return SNMP_ERR_NOTWRITABLE;
  664.             }
  665.             break;
  666.         case MODE_SET_RESERVE2:
  667.             switch (table_info->colnum) {
  668.             case COLUMN_EXTCFG_STATUS:
  669.                 i = *request->requestvb->val.integer;
  670.                 switch (i) {
  671.                 case RS_CREATEANDGO:
  672.                 case RS_CREATEANDWAIT:
  673.                     eptr = _find_extension_block( request->requestvb->name,
  674.                                                   request->requestvb->name_length );
  675.                     extension = _new_extension( table_info->indexes->val.string,
  676.                                                 0, eptr );
  677.                     if (!extension) {  /* failed */
  678.                         netsnmp_set_request_error(reqinfo, request,
  679.                                                   SNMP_ERR_RESOURCEUNAVAILABLE);
  680.                         return SNMP_ERR_RESOURCEUNAVAILABLE;
  681.                     }
  682.                     netsnmp_insert_table_row( request, extension->row );
  683.                 }
  684.             }
  685.             break;
  686.         case MODE_SET_FREE:
  687.             switch (table_info->colnum) {
  688.             case COLUMN_EXTCFG_STATUS:
  689.                 i = *request->requestvb->val.integer;
  690.                 switch (i) {
  691.                 case RS_CREATEANDGO:
  692.                 case RS_CREATEANDWAIT:
  693.                     eptr = _find_extension_block( request->requestvb->name,
  694.                                                   request->requestvb->name_length );
  695.                     _free_extension( extension, eptr );
  696.                 }
  697.             }
  698.             break;
  699.         case MODE_SET_ACTION:
  700.             switch (table_info->colnum) {
  701.             case COLUMN_EXTCFG_COMMAND:
  702.                 extension->old_command = extension->command;
  703.                 extension->command = netsnmp_strdup_and_null(
  704.                     request->requestvb->val.string,
  705.                     request->requestvb->val_len);
  706.                 break;
  707.             case COLUMN_EXTCFG_ARGS:
  708.                 extension->old_args = extension->args;
  709.                 extension->args = netsnmp_strdup_and_null(
  710.                     request->requestvb->val.string,
  711.                     request->requestvb->val_len);
  712.                 break;
  713.             case COLUMN_EXTCFG_INPUT:
  714.                 extension->old_input = extension->input;
  715.                 extension->input = netsnmp_strdup_and_null(
  716.                     request->requestvb->val.string,
  717.                     request->requestvb->val_len);
  718.                 break;
  719.             case COLUMN_EXTCFG_STATUS:
  720.                 i = *request->requestvb->val.integer;
  721.                 switch (i) {
  722.                 case RS_ACTIVE:
  723.                 case RS_CREATEANDGO:
  724.                     need_to_validate = 1;
  725.                 }
  726.                 break;
  727.             }
  728.             break;
  729.         case MODE_SET_UNDO:
  730.             switch (table_info->colnum) {
  731.             case COLUMN_EXTCFG_COMMAND:
  732.                 if ( extension && extension->old_command ) {
  733.                     SNMP_FREE(extension->command);
  734.                     extension->command     = extension->old_command;
  735.                     extension->old_command = NULL;
  736.                 }
  737.                 break;
  738.             case COLUMN_EXTCFG_ARGS:
  739.                 if ( extension && extension->old_args ) {
  740.                     SNMP_FREE(extension->args);
  741.                     extension->args     = extension->old_args;
  742.                     extension->old_args = NULL;
  743.                 }
  744.                 break;
  745.             case COLUMN_EXTCFG_INPUT:
  746.                 if ( extension && extension->old_input ) {
  747.                     SNMP_FREE(extension->input);
  748.                     extension->input     = extension->old_input;
  749.                     extension->old_input = NULL;
  750.                 }
  751.                 break;
  752.             case COLUMN_EXTCFG_STATUS:
  753.                 i = *request->requestvb->val.integer;
  754.                 switch (i) {
  755.                 case RS_CREATEANDGO:
  756.                 case RS_CREATEANDWAIT:
  757.                     eptr = _find_extension_block( request->requestvb->name,
  758.                                                   request->requestvb->name_length );
  759.                     _free_extension( extension, eptr );
  760.                 }
  761.                 break;
  762.             }
  763.             break;
  764.         case MODE_SET_COMMIT:
  765.             switch (table_info->colnum) {
  766.             case COLUMN_EXTCFG_CACHETIME:
  767.                 i = *request->requestvb->val.integer;
  768.                 extension->cache->timeout = i;
  769.                 break;
  770.             case COLUMN_EXTCFG_RUNTYPE:
  771.                 i = *request->requestvb->val.integer;
  772.                 switch (i) {
  773.                 case 1:
  774.                     extension->flags &= ~NS_EXTEND_FLAGS_WRITEABLE;
  775.                     break;
  776.                 case 2:
  777.                     extension->flags |=  NS_EXTEND_FLAGS_WRITEABLE;
  778.                     break;
  779.                 case 3:
  780.                     (void)netsnmp_cache_check_and_reload( extension->cache );
  781.                     break;
  782.                 }
  783.                 break;
  784.             case COLUMN_EXTCFG_EXECTYPE:
  785.                 i = *request->requestvb->val.integer;
  786.                 if ( i == NS_EXTEND_ETYPE_SHELL )
  787.                     extension->flags |=  NS_EXTEND_FLAGS_SHELL;
  788.                 else
  789.                     extension->flags &= ~NS_EXTEND_FLAGS_SHELL;
  790.                 break;
  791.             case COLUMN_EXTCFG_STATUS:
  792.                 i = *request->requestvb->val.integer;
  793.                 switch (i) {
  794.                 case RS_ACTIVE:
  795.                 case RS_CREATEANDGO:
  796.                     extension->flags |= NS_EXTEND_FLAGS_ACTIVE;
  797.                     break;
  798.                 case RS_NOTINSERVICE:
  799.                 case RS_CREATEANDWAIT:
  800.                     extension->flags &= ~NS_EXTEND_FLAGS_ACTIVE;
  801.                     break;
  802.                 case RS_DESTROY:
  803.                     eptr = _find_extension_block( request->requestvb->name,
  804.                                                   request->requestvb->name_length );
  805.                     _free_extension( extension, eptr );
  806.                     break;
  807.                 }
  808.             }
  809.             break;
  810.         default:
  811.             netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
  812.             return SNMP_ERR_GENERR;
  813.         }
  814.     }
  815.     /*
  816.      * If we're marking a given row as active,
  817.      *  then we need to check that it's ready.
  818.      */
  819.     if (need_to_validate) {
  820.         for ( request=requests; request; request=request->next ) {
  821.             if (request->processed)
  822.                 continue;
  823.             table_info = netsnmp_extract_table_info( request );
  824.             extension  = (netsnmp_extend*)netsnmp_extract_table_row_data( request );
  825.             switch (table_info->colnum) {
  826.             case COLUMN_EXTCFG_STATUS:
  827.                 i = *request->requestvb->val.integer;
  828.                 if (( i == RS_ACTIVE || i == RS_CREATEANDGO ) &&
  829.                     !(extension && extension->command &&
  830.                       extension->command[0] == '/' /* &&
  831.                       is_executable(extension->command) */)) {
  832.                     netsnmp_set_request_error(reqinfo, request,
  833.                                               SNMP_ERR_INCONSISTENTVALUE);
  834.                     return SNMP_ERR_INCONSISTENTVALUE;
  835.                 }
  836.             }
  837.         }
  838.     }
  839.     return SNMP_ERR_NOERROR;
  840. }
  841. int
  842. handle_nsExtendOutput1Table(netsnmp_mib_handler          *handler,
  843.                      netsnmp_handler_registration *reginfo,
  844.                      netsnmp_agent_request_info   *reqinfo,
  845.                      netsnmp_request_info         *requests)
  846. {
  847.     netsnmp_request_info       *request;
  848.     netsnmp_table_request_info *table_info;
  849.     netsnmp_extend             *extension;
  850.     int len;
  851.     for ( request=requests; request; request=request->next ) {
  852.         if (request->processed)
  853.             continue;
  854.         table_info = netsnmp_extract_table_info( request );
  855.         extension  = (netsnmp_extend*)netsnmp_extract_table_row_data( request );
  856.         DEBUGMSGTL(( "nsExtendTable:output1", "varbind: "));
  857.         DEBUGMSGOID(("nsExtendTable:output1", request->requestvb->name,
  858.                                               request->requestvb->name_length));
  859.         DEBUGMSG((   "nsExtendTable:output1", "n"));
  860.         switch (reqinfo->mode) {
  861.         case MODE_GET:
  862.             if (!extension || !(extension->flags & NS_EXTEND_FLAGS_ACTIVE)) {
  863.                 /*
  864.                  * If this row is inactive, then skip it.
  865.                  */
  866.                 netsnmp_set_request_error(reqinfo, request,
  867.                                           SNMP_NOSUCHINSTANCE);
  868.                 continue;
  869.             }
  870.             if (!(extension->flags & NS_EXTEND_FLAGS_WRITEABLE) &&
  871.                 (netsnmp_cache_check_and_reload( extension->cache ) < 0 )) {
  872.                 /*
  873.                  * If reloading the output cache of a 'run-on-read'
  874.                  * entry fails, then skip it.
  875.                  */
  876.                 netsnmp_set_request_error(reqinfo, request,
  877.                                           SNMP_NOSUCHINSTANCE);
  878.                 continue;
  879.             }
  880.             if ((extension->flags & NS_EXTEND_FLAGS_WRITEABLE) &&
  881.                 (netsnmp_cache_check_expired( extension->cache ) == 1 )) {
  882.                 /*
  883.                  * If the output cache of a 'run-on-write'
  884.                  * entry has expired, then skip it.
  885.                  */
  886.                 netsnmp_set_request_error(reqinfo, request,
  887.                                           SNMP_NOSUCHINSTANCE);
  888.                 continue;
  889.             }
  890.             switch (table_info->colnum) {
  891.             case COLUMN_EXTOUT1_OUTLEN:
  892.                 snmp_set_var_typed_value(
  893.                      request->requestvb, ASN_INTEGER,
  894.                     (u_char*)&extension->out_len, sizeof(int));
  895.                 break;
  896.             case COLUMN_EXTOUT1_OUTPUT1:
  897.                 /* 
  898.                  * If we've got more than one line,
  899.                  * find the length of the first one.
  900.                  * Otherwise find the length of the whole string.
  901.                  */
  902.                 if (extension->lines) {
  903.                     len = (extension->lines[1])-(extension->output) -1;
  904.                 } else if (extension->output) {
  905.                     len = strlen(extension->output);
  906.                 } else {
  907.                     len = 0;
  908.                 }
  909.                 snmp_set_var_typed_value(
  910.                      request->requestvb, ASN_OCTET_STR,
  911.                      extension->output, len);
  912.                 break;
  913.             case COLUMN_EXTOUT1_OUTPUT2:
  914.                 snmp_set_var_typed_value(
  915.                      request->requestvb, ASN_OCTET_STR,
  916.                      extension->output,
  917.                     (extension->output)?strlen(extension->output):0);
  918.                 break;
  919.             case COLUMN_EXTOUT1_NUMLINES:
  920.                 snmp_set_var_typed_value(
  921.                      request->requestvb, ASN_INTEGER,
  922.                     (u_char*)&extension->numlines, sizeof(int));
  923.                 break;
  924.             case COLUMN_EXTOUT1_RESULT:
  925.                 snmp_set_var_typed_value(
  926.                      request->requestvb, ASN_INTEGER,
  927.                     (u_char*)&extension->result, sizeof(int));
  928.                 break;
  929.             default:
  930.                 netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
  931.                 continue;
  932.             }
  933.             break;
  934.         default:
  935.             netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
  936.             return SNMP_ERR_GENERR;
  937.         }
  938.     }
  939.     return SNMP_ERR_NOERROR;
  940. }
  941.         /*************************
  942.          *
  943.          *  Multi-line output table handler
  944.          *  Most of the work is handled here.
  945.          *
  946.          *************************/
  947. /*
  948.  *  Locate the appropriate entry for a given request
  949.  */
  950. netsnmp_extend *
  951. _extend_find_entry( netsnmp_request_info       *request,
  952.                     netsnmp_table_request_info *table_info,
  953.                     int mode  )
  954. {
  955.     netsnmp_extend            *eptr;
  956.     extend_registration_block *ereg;
  957.     int line_idx;
  958.     oid oid_buf[MAX_OID_LEN];
  959.     int oid_len;
  960.     int i;
  961.     char *token;
  962.     if (!request || !table_info || !table_info->indexes
  963.                  || !table_info->indexes->next_variable) {
  964.         DEBUGMSGTL(( "nsExtendTable:output2", "invalid invocationn"));
  965.         return NULL;
  966.     }
  967.     ereg = _find_extension_block( request->requestvb->name,
  968.                                   request->requestvb->name_length );
  969.     /***
  970.      *  GET handling - find the exact entry being requested
  971.      ***/
  972.     if ( mode == MODE_GET ) {
  973.         DEBUGMSGTL(( "nsExtendTable:output2", "GET: %s / %dn ",
  974.                       table_info->indexes->val.string,
  975.                      *table_info->indexes->next_variable->val.integer));
  976.         for ( eptr = ereg->ehead; eptr; eptr = eptr->next ) {
  977.             if ( !strcmp( eptr->token, table_info->indexes->val.string ))
  978.                 break;
  979.         }
  980.         if ( eptr ) {
  981.             /*
  982.              * Ensure the output is available...
  983.              */
  984.             if (!(eptr->flags & NS_EXTEND_FLAGS_ACTIVE) ||
  985.                (netsnmp_cache_check_and_reload( eptr->cache ) < 0 ))
  986.                 return NULL;
  987.             /*
  988.              * ...and check the line requested is valid
  989.              */
  990.             line_idx = *table_info->indexes->next_variable->val.integer;
  991.             if (eptr->numlines < line_idx)
  992.                 return NULL;
  993.         }
  994.         return eptr;
  995.     }
  996.         /***
  997.          *  GETNEXT handling - find the first suitable entry
  998.          ***/
  999.     else {
  1000.         if (!table_info->indexes->val_len ) {
  1001.             DEBUGMSGTL(( "nsExtendTable:output2", "GETNEXT: first entryn"));
  1002.             /*
  1003.              * Beginning of the table - find the first active
  1004.              *  (and successful) entry, and use the first line of it
  1005.              */
  1006.             for (eptr = ereg->ehead; eptr; eptr = eptr->next ) {
  1007.                 if ((eptr->flags & NS_EXTEND_FLAGS_ACTIVE) &&
  1008.                     (netsnmp_cache_check_and_reload( eptr->cache ) >= 0 )) {
  1009.                     line_idx = 1;
  1010.                     break;
  1011.                 }
  1012.             }
  1013.         } else {
  1014.             token    =  table_info->indexes->val.string,
  1015.             line_idx = *table_info->indexes->next_variable->val.integer;
  1016.             DEBUGMSGTL(( "nsExtendTable:output2", "GETNEXT: %s / %dn ",
  1017.                           token, line_idx ));
  1018.             /*
  1019.              * Otherwise, find the first entry not earlier
  1020.              * than the requested token...
  1021.              */
  1022.             for (eptr = ereg->ehead; eptr; eptr = eptr->next ) {
  1023.                 if ( strlen(eptr->token) > strlen( token ))
  1024.                     break;
  1025.                 if ( strlen(eptr->token) == strlen( token ) &&
  1026.                      strcmp(eptr->token, token) >= 0 )
  1027.                     break;
  1028.             }
  1029.             if (!eptr)
  1030.                 return NULL;    /* (assuming there is one) */
  1031.             /*
  1032.              * ... and make sure it's active & the output is available
  1033.              * (or use the first following entry that is)
  1034.              */
  1035.             for (    ; eptr; eptr = eptr->next ) {
  1036.                 if ((eptr->flags & NS_EXTEND_FLAGS_ACTIVE) &&
  1037.                     (netsnmp_cache_check_and_reload( eptr->cache ) >= 0 )) {
  1038.                     break;
  1039.                 }
  1040.                 line_idx = 1;
  1041.             }
  1042.             /*
  1043.              *  If we're working with the same entry that was requested,
  1044.              *  see whether we've reached the end of the output...
  1045.              */
  1046.             if (!strcmp( eptr->token, token )) {
  1047.                 if ( eptr->numlines <= line_idx ) {
  1048.                     /*
  1049.                      * ... and if so, move on to the first line
  1050.                      * of the next (active and successful) entry.
  1051.                      */
  1052.                     line_idx = 1;
  1053.                     for (eptr = eptr->next ; eptr; eptr = eptr->next ) {
  1054.                         if ((eptr->flags & NS_EXTEND_FLAGS_ACTIVE) &&
  1055.                             (netsnmp_cache_check_and_reload( eptr->cache ) >= 0 )) {
  1056.                             break;
  1057.                         }
  1058.                     }
  1059.                 } else {
  1060.                     /*
  1061.                      * Otherwise just use the next line of this entry.
  1062.                      */
  1063.                     line_idx++;
  1064.                 }
  1065.             }
  1066.         }
  1067.         if (eptr) {
  1068.             DEBUGMSGTL(( "nsExtendTable:output2", "GETNEXT -> %s / %dn ",
  1069.                           eptr->token, line_idx));
  1070.             /*
  1071.              * Since we're processing a GETNEXT request,
  1072.              * now we've found the appropriate entry (and line),
  1073.              * we need to update the varbind OID ...
  1074.              */
  1075.             memcpy( oid_buf, extend_out2_oid, sizeof(extend_out2_oid));
  1076.             oid_len = OID_LENGTH(extend_out2_oid);
  1077.             oid_buf[ oid_len++ ] = 1;    /* nsExtendOutput2Entry */
  1078.             oid_buf[ oid_len++ ] = COLUMN_EXTOUT2_OUTLINE;
  1079.                                          /* string token index */
  1080.             oid_buf[ oid_len++ ] = strlen(eptr->token);
  1081.             for ( i=0; i < (int)strlen(eptr->token); i++ )
  1082.                 oid_buf[ oid_len+i ] = eptr->token[i];
  1083.             oid_len += strlen( eptr->token );
  1084.                                          /* plus line number */
  1085.             oid_buf[ oid_len++ ] = line_idx;
  1086.             snmp_set_var_objid( request->requestvb, oid_buf, oid_len );
  1087.             /*
  1088.              * ... and index values to match.
  1089.              */
  1090.             snmp_set_var_value( table_info->indexes,
  1091.                                 eptr->token, strlen(eptr->token));
  1092.             *table_info->indexes->next_variable->val.integer = line_idx;
  1093.         }
  1094.         return eptr;  /* Finally, signal success */
  1095.     }
  1096.     return NULL;
  1097. }
  1098. /*
  1099.  *  Multi-line output handler
  1100.  *  Locate the appropriate entry (using _extend_find_entry)
  1101.  *  and return the appropriate output line
  1102.  */
  1103. int
  1104. handle_nsExtendOutput2Table(netsnmp_mib_handler          *handler,
  1105.                      netsnmp_handler_registration *reginfo,
  1106.                      netsnmp_agent_request_info   *reqinfo,
  1107.                      netsnmp_request_info         *requests)
  1108. {
  1109.     netsnmp_request_info       *request;
  1110.     netsnmp_table_request_info *table_info;
  1111.     netsnmp_extend             *extension;
  1112.     char *cp;
  1113.     int line_idx;
  1114.     int len;
  1115.     for ( request=requests; request; request=request->next ) {
  1116.         if (request->processed)
  1117.             continue;
  1118.         table_info = netsnmp_extract_table_info( request );
  1119.         extension  = _extend_find_entry( request, table_info, reqinfo->mode );
  1120.         DEBUGMSGTL(( "nsExtendTable:output2", "varbind: "));
  1121.         DEBUGMSGOID(("nsExtendTable:output2", request->requestvb->name,
  1122.                                               request->requestvb->name_length));
  1123.         DEBUGMSG((   "nsExtendTable:output2", " (%s)n",
  1124.                                     (extension) ? extension->token : "[none]"));
  1125.         if (!extension) {
  1126.             if (reqinfo->mode == MODE_GET)
  1127.                 netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
  1128.             else
  1129.                 netsnmp_set_request_error(reqinfo, request, SNMP_ENDOFMIBVIEW);
  1130.             continue;
  1131.         }
  1132.         switch (reqinfo->mode) {
  1133.         case MODE_GET:
  1134.         case MODE_GETNEXT:
  1135.             switch (table_info->colnum) {
  1136.             case COLUMN_EXTOUT2_OUTLINE:
  1137.                 /* 
  1138.                  * Determine which line we've been asked for....
  1139.                  */
  1140.                 line_idx = *table_info->indexes->next_variable->val.integer;
  1141.                 if (extension->lines)
  1142.                     cp  = extension->lines[line_idx-1];
  1143.                 else
  1144.                     cp  = extension->output;
  1145.                 /* 
  1146.                  * ... and how long it is.
  1147.                  */
  1148.                 if ( extension->numlines > line_idx )
  1149.                     len = (extension->lines[line_idx])-cp -1;
  1150.                 else if (cp)
  1151.                     len = strlen(cp);
  1152.                 else
  1153.                     len = 0;
  1154.                 snmp_set_var_typed_value( request->requestvb,
  1155.                                           ASN_OCTET_STR, cp, len );
  1156.                 break;
  1157.             default:
  1158.                 netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
  1159.                 continue;
  1160.             }
  1161.             break;
  1162.         default:
  1163.             netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
  1164.             return SNMP_ERR_GENERR;
  1165.         }
  1166.     }
  1167.     return SNMP_ERR_NOERROR;
  1168. }
  1169. #ifndef USING_UCD_SNMP_EXTENSIBLE_MODULE
  1170.         /*************************
  1171.          *
  1172.          *  Compatability with the UCD extTable
  1173.          *
  1174.          *************************/
  1175. u_char *
  1176. var_extensible_old(struct variable * vp,
  1177.                      oid * name,
  1178.                      size_t * length,
  1179.                      int exact,
  1180.                      size_t * var_len, WriteMethod ** write_method)
  1181. {
  1182.     netsnmp_old_extend *exten = NULL;
  1183.     static long     long_ret;
  1184.     int idx;
  1185.     if (header_simple_table
  1186.         (vp, name, length, exact, var_len, write_method, num_compatability_entries))
  1187.         return (NULL);
  1188.     idx = name[*length-1] -1;
  1189.     exten = &compatability_entries[ idx ];
  1190.     if (exten) {
  1191.         switch (vp->magic) {
  1192.         case MIBINDEX:
  1193.             long_ret = name[*length - 1];
  1194.             return ((u_char *) (&long_ret));
  1195.         case ERRORNAME:        /* name defined in config file */
  1196.             *var_len = strlen(exten->exec_entry->token);
  1197.             return ((u_char *) (exten->exec_entry->token));
  1198.         case SHELLCOMMAND:
  1199.             *var_len = strlen(exten->exec_entry->command);
  1200.             return ((u_char *) (exten->exec_entry->command));
  1201.         case ERRORFLAG:        /* return code from the process */
  1202.             netsnmp_cache_check_and_reload( exten->exec_entry->cache );
  1203.             long_ret = exten->exec_entry->result;
  1204.             return ((u_char *) (&long_ret));
  1205.         case ERRORMSG:         /* first line of text returned from the process */
  1206.             netsnmp_cache_check_and_reload( exten->exec_entry->cache );
  1207.             if (exten->exec_entry->lines) {
  1208.                 *var_len = (exten->exec_entry->lines[1])-
  1209.                            (exten->exec_entry->output) -1;
  1210.             } else if (exten->exec_entry->output) {
  1211.                 *var_len = strlen(exten->exec_entry->output);
  1212.             } else {
  1213.                 *var_len = 0;
  1214.             }
  1215.             return ((u_char *) (exten->exec_entry->output));
  1216.         case ERRORFIX:
  1217.             *write_method = fixExec2Error;
  1218.             long_return = 0;
  1219.             return ((u_char *) &long_return);
  1220.         case ERRORFIXCMD:
  1221.             if (exten->efix_entry) {
  1222.                 *var_len = strlen(exten->efix_entry->command);
  1223.                 return ((u_char *) exten->efix_entry->command);
  1224.             } else {
  1225.                 *var_len = 0;
  1226.                 return ((u_char *) &long_return);  /* Just needs to be non-null! */
  1227.             }
  1228.         }
  1229.         return NULL;
  1230.     }
  1231.     return NULL;
  1232. }
  1233. int
  1234. fixExec2Error(int action,
  1235.              u_char * var_val,
  1236.              u_char var_val_type,
  1237.              size_t var_val_len,
  1238.              u_char * statP, oid * name, size_t name_len)
  1239. {
  1240.     netsnmp_old_extend *exten = NULL;
  1241.     int idx;
  1242.     idx = name[name_len-1] -1;
  1243.     exten = &compatability_entries[ idx ];
  1244.     switch (action) {
  1245.     case MODE_SET_RESERVE1:
  1246.         if (var_val_type != ASN_INTEGER) {
  1247.             snmp_log(LOG_ERR, "Wrong type != intn");
  1248.             return SNMP_ERR_WRONGTYPE;
  1249.         }
  1250.         idx = *((long *) var_val);
  1251.         if (idx != 1) {
  1252.             snmp_log(LOG_ERR, "Wrong value != 1n");
  1253.             return SNMP_ERR_WRONGVALUE;
  1254.         }
  1255.         if (!exten || !exten->efix_entry) {
  1256.             snmp_log(LOG_ERR, "No command to runn");
  1257.             return SNMP_ERR_GENERR;
  1258.         }
  1259.         return SNMP_ERR_NOERROR;
  1260.     case MODE_SET_COMMIT:
  1261.         netsnmp_cache_check_and_reload( exten->efix_entry->cache );
  1262.     }
  1263.     return SNMP_ERR_NOERROR;
  1264. }
  1265. #endif