# mib2c.storage.conf: # # This is a special mib2c.conf file that assumes that you want to do # all storage of information locally rather than pulling the # information from another source outside the agent (EG, the # kernel). To accomplish this, it defines a structure for the # storage of tables and assumes you want to use the header_complex # functions for retrieving and storing that data in a local data # store. It even writes a .conf file parser for you and sets you up # for being able to do persistant storage fairly simply. # # In short: it trys to do almost all of the work for you... Almost... # # Define types of data by mib type, and translate into needed C code. # # We need to get some extra stuff into the variable declarations # before sourcing the main mib2c.vartypes.conf file below. type: OCTETSTR storage: char *${name}; storage: size_t ${name}Len; varlenname: StorageTmp->${name}Len vartest: if (StorageTmp->${name} == NULL) { vartest: config_perror(\"invalid specification for ${name}\"); vartest: return; vartest: } vartest: action: tmpvar = StorageTmp->$name; action: tmplen = StorageTmp->${name}Len; action: memdup((u_char **) &StorageTmp->$name, var_val, var_val_len); action: StorageTmp->${name}Len = var_val_len; undo: SNMP_FREE(StorageTmp->${name}); undo: StorageTmp->${name} = tmpvar; undo: StorageTmp->${name}Len = tmplen; commit: SNMP_FREE(tmpvar); sizeofstart: sizeofend: Len tmpvar: char * casttmp: strdup((char *) tmpvar); # type: INTEGER storage: long $name; storageret: & varlenname: tmpint sizeofstart: sizeof( sizeofend: ) tmpvar: int action: tmpvar = StorageTmp->$name; action: StorageTmp->${name} = *((long *) var_val); undo: StorageTmp->${name} = tmpvar; casttmp: tmpvar; # type: UNSIGNED32 storage: unsigned long $name; storageret: & varlenname: tmpint sizeofstart: sizeof( sizeofend: ) tmpvar: int action: tmpvar = StorageTmp->$name; action: StorageTmp->${name} = *((unsigned long *) var_val); undo: StorageTmp->${name} = tmpvar; casttmp: tmpvar; # type: OBJECTID storage: oid *$name; storage: size_t ${name}Len; varlenname: StorageTmp->${name}Len vartest: if (StorageTmp->${name} == NULL) { vartest: config_perror(\"invalid specification for ${name}\"); vartest: return; vartest: } vartest: action: tmpvar = StorageTmp->$name; action: tmplen = StorageTmp->${name}Len; action: memdup((u_char **) &StorageTmp->$name, var_val, var_val_len); action: StorageTmp->${name}Len = var_val_len/sizeof(oid); undo: SNMP_FREE(StorageTmp->${name}); undo: StorageTmp->${name} = tmpvar; undo: StorageTmp->${name}Len = tmplen; commit: SNMP_FREE(tmpvar); sizeofstart: sizeofend: Len tmpvar: oid * casttmp: (oid *) tmpvar; freetmp: SNMP_FREE(tmpvar); # type: COUNTER64 storage: struct counter64 $name; varlenname: tmpint sizeofstart: sizeof( sizeofend: ) tmpvar: struct counter64 * casttmp: (struct counter64 *) tmpvar; ############################################################################ # source variable typing information: include: mib2c.vartypes.conf ############################################################################ # The .h file ############################################################################ type: code-dot-h code: /* This file was generated by mib2c and is intended for use as a mib module code: for the ucd-snmp snmpd agent. */ code: code: #ifndef _MIBGROUP_${OUTPUTNAME}_H code: #define _MIBGROUP_${OUTPUTNAME}_H code: code: /* we may use header_complex from the header_complex module */ code: code: config_require(header_complex) code: code: /* our storage structure(s) */ code: $variables{'code-structure-per-table'}{'processed'} code: code: /* enum definitions from the covered mib sections */ code: code: $variables{'code-enums'}{'processed'} code: code: /* function prototypes */ code: code: void init_$outputName(void); code: $variables{'code-var-table-decl'}{'processed'} code: $variables{'code-write-func-decl'}{'processed'} code: $variables{'code-write-rowstatus-decl'}{'processed'} code: code: #endif /* _MIBGROUP_${OUTPUTNAME}_H */ # # Structure definition, one per table # type: code-structure-per-table processtable: code-structure-per-table code: struct ${vtable}_data { code: $variables{$vtable}{'code-structure'}{'processed'} code: }; # # Structure storage arrays, one per table # type: code-structure-storage processtable: code-structure-storage code: static struct header_complex_index *${vtable}Storage = NULL; # # Structure definition line. # type: code-structure process: code-structure code: " . eval ("\"$variables{$mib->{'type'}}{'storage'}\"") . " #$variables{$i}{'code'}\""evalstr( # # ENUM definitions # type: code-enums process: code-enums skipif: $mib->{'textualConvention'} eq "RowStatus" || $mib->{'textualConvention'} eq "StorageType" code: " . eval{ my ($i, $x); foreach $i (sort {$mib->{'enums'}{$a} <=> $mib->{'enums'}{$b}} keys(%{$mib->{'enums'}})) { $x .= sprintf("#define %-40s %d\n","${NAME}_" . uc($i),$mib->{'enums'}{$i}); } $x; } . " ############################################################################ # The .c file, top ############################################################################ type: code-main-part code: /* This file was generated by mib2c and is intended for use as code: a mib module for the ucd-snmp snmpd agent. */ code: code: /* This should always be included first before anything else */ code: #include <config.h> code: #if HAVE_STDLIB_H code: #include <stdlib.h> code: #endif code: #if HAVE_STRING_H code: #include <string.h> code: #else code: #include <strings.h> code: #endif code: code: /* minimal include directives */ code: #include \"mibincl.h\" code: #include \"header_complex.h\" code: #include \"$outputName.h\" code: #include \"snmp-tc.h\" code: code: /* code: * ${outputName}_variables_oid: code: * this is the top level oid that we want to register under. This code: * is essentially a prefix, with the suffix appearing in the code: * variable below. code: */ code: code: oid ${outputName}_variables_oid[] = { $commaoid }; code: code: /* code: * variable$varlen ${outputName}_variables: code: * this variable defines function callbacks and type return information code: * for the $outputName mib section code: */ code: code: struct variable$varlen ${outputName}_variables[] = { code: /* magic number , variable type , ro/rw , callback fn , L, oidsuffix */ code: $variables{'variable-structure-info'}{'processed'} code: }; code: /* (L = length of the oidsuffix) */ code: code: /* global storage of our data, saved in and configured by header_complex() */ code: $variables{'code-structure-storage'}{'processed'} code: code: /* code: * init_$outputName(): code: * Initialization routine. This is called when the agent starts up. code: * At a minimum, registration of your variables should take place here. code: */ code: void init_$outputName(void) { code: DEBUGMSGTL((\"$outputName\", \"initializing... \")); code: code: /* register ourselves with the agent to handle our mib tree */ code: REGISTER_MIB(\"$outputName\", ${outputName}_variables, variable$varlen,\ code: ${outputName}_variables_oid); code: code: /* register our config handler(s) to deal with registrations */ code: $variables{'code-parser-registration'}{'processed'} code: code: /* we need to be called back later to store our data */ code: snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, code: store_$outputName, NULL); code: code: /* place any other initialization junk you need here */ code: code: DEBUGMSGTL((\"$outputName\", \"done.\\n\")); code: } code: code: $variables{'code-parser'}{'processed'} code: code: $variables{'code-var_table'}{'processed'} code: code: $variables{'code-write-func'}{'processed'} code: code: $variables{'code-write-rowstatus'}{'processed'} ############################################################################ # var_ function for tables, which is handled specially and used above # # Note: $vtable is set to the table name in the processtable loop. ############################################################################ # # header file defs first # type: code-var-table-decl processtable: code-var-table-decl code: FindVarMethod var_$vtable; code: void parse_$vtable(const char *, char *); code: SNMPCallback store_$vtable; # # .conf Parser Code per table # type: code-parser-registration processtable: code-parser-registration code: snmpd_register_config_handler(\"$vtable\", parse_$vtable, NULL, code: \"HELP STRING\"); type: code-varlist-add process: code-varlist-add skipif: $variables{$vroutine}{$name}{'isanindex'} != 1 code: snmp_varlist_add_variable(&vars, NULL, 0, $variables{$mib->{type}}{asnType}, ($variables{$mib->{type}}{'cast'}) thedata->$name, $variables{$mib->{type}}{'sizeofstart'}thedata->$name$variables{$mib->{type}}{'sizeofend'}); /* $name */ type: code-parser processtable: code-parser code: /* code: * ${vtable}_add(): adds a structure node to our data set code: */ code: int code: ${vtable}_add(struct ${vtable}_data *thedata) { code: struct variable_list *vars = NULL; code: code: DEBUGMSGTL((\"$outputName\", \"adding data... \")); code: /* add the index variables to the varbind list, which is code: used by header_complex to index the data */ code: code: $variables{$vtable}{'code-varlist-add'}{'processed'} code: code: header_complex_add_data(&${vtable}Storage, vars, thedata); code: DEBUGMSGTL((\"$vtable\",\"registered an entry\\n\")); code: code: DEBUGMSGTL((\"$outputName\", \"done.\\n\")); code: return SNMPERR_SUCCESS; code: } code: code: /* code: * parse_$vtable(): code: * parses .conf file entries needed to configure the mib. code: */ code: void code: parse_$vtable(const char *token, char *line) { code: size_t tmpint; code: struct ${vtable}_data *StorageTmp = SNMP_MALLOC_STRUCT(${vtable}_data); code: struct variable_list *vars = NULL; code: code: DEBUGMSGTL((\"$outputName\", \"parsing config... \")); code: code: if (StorageTmp == NULL) { code: config_perror(\"malloc failure\"); code: return; code: } code: code: $variables{$vtable}{'code-parser-sections'}{'processed'} code: code: ${vtable}_add(StorageTmp); code: code: DEBUGMSGTL((\"$outputName\", \"done.\\n\")); code: } code: code: code: /* code: * store_$vtable(): code: * stores .conf file entries needed to configure the mib. code: */ code: int code: store_$vtable(int majorID, int minorID, void *serverarg, void *clientarg) { code: char line[SNMP_MAXBUF]; code: char *cptr; code: size_t tmpint; code: struct ${vtable}_data *StorageTmp; code: struct header_complex_index *hcindex; code: code: DEBUGMSGTL((\"$outputName\", \"storing data... \")); code: code: for(hcindex=${vtable}Storage; hcindex != NULL; code: hcindex = hcindex->next) { code: StorageTmp = (struct ${vtable}_data *) hcindex->data; code: code: /* XXX: if (StorageTmp->${vtable}StorageType == ST_NONVOLATILE) { */ code: code: memset(line,0,sizeof(line)); code: strcat(line, \"$vtable \"); code: cptr = line + strlen(line); code: code: $variables{$vtable}{'code-persistent-sections'}{'processed'} code: code: snmpd_store_config(line); code: /* } */ code: } code: DEBUGMSGTL((\"$outputName\", \"done.\\n\")); code: return SNMPERR_SUCCESS; code: } # individual sections for the parser type: code-parser-sections process: code-parser-sections #skipif: $mib->{'access'} =~ /NoAccess/ skipif: $mib->{'label'} =~ /(Entry|Table)$/ code: line = read_config_read_data($variables{$mib->{type}}{asnType}, line, &StorageTmp->$name, &" . eval ("\"$variables{$mib->{type}}{varlenname}\"") . "); code: " . eval ("\"$variables{$mib->{type}}{vartest}\"") . " # # .conf persistent save Code per table # type: code-persistent-sections process: code-persistent-sections #skipif: $mib->{'access'} =~ /NoAccess/ skipif: $mib->{'label'} =~ /(Entry|Table)$/ code: cptr = read_config_store_data($variables{$mib->{type}}{asnType}, cptr, &StorageTmp->$name, &" . eval ("\"$variables{$mib->{type}}{varlenname}\"") . "); # # Code code per table # type: code-var_table processtable: code-var_table code: /* code: * var_$vtable(): code: * Handle this table separately from the scalar value case. code: * The workings of this are basically the same as for var_$outputName above. code: */ code: unsigned char * code: var_$vtable(struct variable *vp, code: oid *name, code: size_t *length, code: int exact, code: size_t *var_len, code: WriteMethod **write_method) code: { code: code: struct ${vtable}_data *StorageTmp = NULL; code: code: DEBUGMSGTL((\"$outputName\", \"var_$vtable: Entering... \\n\")); code: /* code: * this assumes you have registered all your data properly cdoe: * with header_complex_add() somewhere before this code: */ code: if ((StorageTmp = code: header_complex(${vtable}Storage, vp,name,length,exact, code: var_len,write_method)) == NULL) code: return NULL; code: code: /* code: * this is where we do the value assignments for the mib results. code: */ code: switch(vp->magic) {\n\n code: $variables{$vtable}{'code-case-statements'}{'processed'} code: default: code: ERROR_MSG(\"\"); code: } code: return NULL; code: } ############################################################################ # case statement sections ############################################################################ type: code-case-statements process: code-case-statements skipif: $mib->{'access'} =~ /NoAccess/ code: case $NAME: code: " . (($mib->{'access'} =~ /ReadWrite|WriteOnly|Create/) ? "*write_method = write_$mib->{label};" : "") . " code: *var_len = $variables{$mib->{'type'}}{'sizeofstart'}StorageTmp->$mib->{label}$variables{$mib->{'type'}}{'sizeofend'}; code: return (u_char *) $variables{$mib->{'type'}}{'storageret'}StorageTmp->$mib->{label}; code: ############################################################################ # storage structure information ############################################################################ type: variable-structure-info process: variable-structure-info skipif: $mib->{'access'} =~ /NoAccess/ code: " . sprintf("#define %-20s $count", $NAME) . " code: " . sprintf(" { %-20s, %-14s, %-6.6s, %s, %d, { %s } },", $NAME, $variables{$mib->{'type'}}{'asnType'}, $accessToUCD{$mib->{'access'}}, "var_$vroutine", $depth-1, $subid) . " ############################################################################ # write function definition, also appended to the end of the .c file. ############################################################################ # # Header info: declair write functions for set processing # process: code-write-func-decl type: code-write-func-decl skipif: $mib->{'access'} !~ /Write|Create/ code: WriteMethod write_$name; # # C code # type: code-write-func process: code-write-func skipif: $mib->{'textualConvention'} eq "RowStatus" || $mib->{'access'} !~ /Write|Create/ code: int code: write_$name(int action, code: u_char *var_val, code: u_char var_val_type, code: size_t var_val_len, code: u_char *statP, code: oid *name, code: size_t name_len) code: { code: static $variables{$mib->{'type'}}{tmpvar} tmpvar; code: struct ${vroutine}_data *StorageTmp = NULL; code: static size_t tmplen; code: size_t newlen=name_len - (sizeof(${outputName}_variables_oid)/sizeof(oid) + $depth - 1); code: code: DEBUGMSGTL((\"$outputName\", \"write_$name entering action=%d... \\n\", action)); code: if ((StorageTmp = code: header_complex(${vroutine}Storage, NULL, code: &name[sizeof(${outputName}_variables_oid)/sizeof(oid) + $depth - 1], code: &newlen, 1, NULL, NULL)) == NULL) code: return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ code: code: switch ( action ) { code: case RESERVE1: code: if (var_val_type != $variables{$mib->{'type'}}{asnType}){ code: fprintf(stderr, \"write to $name not $variables{$mib->{'type'}}{asnType}\\n\"); code: return SNMP_ERR_WRONGTYPE; code: } code: break; code: code: case RESERVE2: code: /* memory reseveration, final preparation... */ code: break; code: code: case FREE: code: /* Release any resources that have been allocated */ code: break; code: code: case ACTION: code: /* The variable has been stored in $variables{$mib->{'type'}}{variable} for code: you to use, and you have just been asked to do something with code: it. Note that anything done here must be reversable in the UNDO case */ code: ".eval ("\"$variables{$mib->{type}}{action}\"")." code: break; code: code: case UNDO: code: /* Back out any changes made in the ACTION case */ code: ".eval ("\"$variables{$mib->{type}}{undo}\"")." code: break; code: code: case COMMIT: code: /* Things are working well, so it's now safe to make the change code: permanently. Make sure that anything done here can't fail! */ code: ".eval ("\"$variables{$mib->{'type'}}{'commit'}\"")." code: break; code: } code: return SNMP_ERR_NOERROR; code: } code: code: ############################################################################ # copy memory from varlist ############################################################################ type: code-varlist-copy process: code-varlist-copy skipif: $variables{$vroutine}{$name}{'isanindex'} != 1 code: memdup((u_char **) &(StorageNew->$name), code: vp->val.$variables{$mib->{'type'}}{variable}, code: vp->val_len); code: StorageNew->${name}Len = vp->val_len; code: vp = vp->next_variable; ############################################################################ # add null pointers to a varlist; value to be parsed later ############################################################################ type: code-varlist-add-null process: code-varlist-add-null skipif: $variables{$vroutine}{$name}{'isanindex'} != 1 code: snmp_varlist_add_variable(&vars, NULL, 0, $variables{$mib->{'type'}}{asnType}, NULL, 0); /* $name */ ############################################################################ # write function definition for a RowStatus object, # - allows for creation/deletion. ############################################################################ # # Header info: declair write functions for set processing # process: code-write-rowstatus-decl type: code-write-rowstatus-decl skipif: $mib->{'textualConvention'} ne "RowStatus" code: WriteMethod write_$name; # # code # type: code-write-rowstatus process: code-write-rowstatus skipif: $mib->{'textualConvention'} ne "RowStatus" code: int code: write_$name(int action, code: u_char *var_val, code: u_char var_val_type, code: size_t var_val_len, code: u_char *statP, code: oid *name, code: size_t name_len) code: { code: struct ${vroutine}_data *StorageTmp = NULL; code: static struct ${vroutine}_data *StorageNew, *StorageDel; code: size_t newlen=name_len - (sizeof(${vroutine}_variables_oid)/sizeof(oid) + 3 - 1); code: static int old_value; code: int set_value; code: static struct variable_list *vars, *vp; code: struct header_complex_index *hciptr; code: char who[MAX_OID_LEN], flagName[MAX_OID_LEN]; code: code: StorageTmp = code: header_complex(${vroutine}Storage, NULL, code: &name[sizeof(${vroutine}_variables_oid)/sizeof(oid) + 3 - 1], code: &newlen, 1, NULL, NULL); code: code: code: if (var_val_type != ASN_INTEGER || var_val == NULL){ code: fprintf(stderr, \"write to $name not ASN_INTEGER\\n\"); code: return SNMP_ERR_WRONGTYPE; code: } code: set_value = *((long *) var_val); code: code: /* check legal range, and notReady is reserved for us, not a user */ code: if (set_value < 1 || set_value > 6 || set_value == RS_NOTREADY) code: return SNMP_ERR_INCONSISTENTVALUE; code: code: switch ( action ) { code: case RESERVE1: code: /* stage one: test validity */ code: if (StorageTmp == NULL) { code: /* create the row now? */ code: code: /* ditch illegal values now */ code: if (set_value == RS_ACTIVE || set_value == RS_NOTINSERVICE) code: return SNMP_ERR_INCONSISTENTVALUE; code: code: /* destroying a non-existent row is actually legal */ code: if (set_value == RS_DESTROY) { code: return SNMP_ERR_NOERROR; code: } code: code: /* illegal creation values */ code: if (set_value == RS_ACTIVE || set_value == RS_NOTINSERVICE) { code: return SNMP_ERR_INCONSISTENTVALUE; code: } code: } else { code: /* row exists. Check for a valid state change */ code: if (set_value == RS_CREATEANDGO || set_value == RS_CREATEANDWAIT) { code: /* can't create a row that exists */ code: return SNMP_ERR_INCONSISTENTVALUE; code: } code: /* XXX: interaction with row storage type needed */ code: } code: break; code: code: code: case RESERVE2: code: /* memory reseveration, final preparation... */ code: if (StorageTmp == NULL) { code: /* creation */ code: vars = NULL; code: code: $variables{'code-varlist-add-null'}{'processed'} code: code: if (header_complex_parse_oid(&(name[sizeof(${vroutine}_variables_oid)/sizeof(oid)+2]), newlen, code: vars) != SNMPERR_SUCCESS) { code: /* XXX: free, zero vars */ code: return SNMP_ERR_INCONSISTENTNAME; code: } code: vp = vars; code: code: StorageNew = SNMP_MALLOC_STRUCT(${vroutine}_data); code: $variables{'code-varlist-copy'}{'processed'} code: code: code: /* XXX: fill in default row values here into StorageNew */ code: code: StorageNew->$name = set_value; code: /* XXX: free, zero vars, no longer needed? */ code: } code: code: break; code: code: code: case FREE: code: /* XXX: free, zero vars */ code: /* Release any resources that have been allocated */ code: break; code: code: code: case ACTION: code: /* The variable has been stored in set_value for you to code: use, and you have just been asked to do something with code: it. Note that anything done here must be reversable in code: the UNDO case */ code: code: if (StorageTmp == NULL) { code: /* row creation, so add it */ code: if (StorageNew != NULL) code: ${vroutine}_add(StorageNew); code: /* XXX: ack, and if it is NULL? */ code: } else if (set_value != RS_DESTROY) { code: /* set the flag? */ code: old_value = StorageTmp->$name; code: StorageTmp->$name = *((long *) var_val); code: } else { code: /* destroy... extract it for now */ code: hciptr = code: header_complex_find_entry(${vroutine}Storage, code: StorageTmp); code: StorageDel = code: header_complex_extract_entry(&${vroutine}Storage, code: hciptr); code: } code: break; code: code: code: case UNDO: code: /* Back out any changes made in the ACTION case */ code: if (StorageTmp == NULL) { code: /* row creation, so remove it again */ code: hciptr = code: header_complex_find_entry(${vroutine}Storage, code: StorageTmp); code: StorageDel = code: header_complex_extract_entry(&${vroutine}Storage, code: hciptr); code: /* XXX: free it */ code: } else if (StorageDel != NULL) { code: /* row deletion, so add it again */ code: ${vroutine}_add(StorageDel); code: } else { code: StorageTmp->$name = old_value; code: } code: break; code: code: code: case COMMIT: code: /* Things are working well, so it's now safe to make the change code: permanently. Make sure that anything done here can't fail! */ code: if (StorageDel != NULL) { code: StorageDel = 0; code: /* XXX: free it, its dead */ code: } else { code: if (StorageTmp && StorageTmp->$name == RS_CREATEANDGO) { code: StorageTmp->$name = RS_ACTIVE; code: } else if (StorageTmp && code: StorageTmp->$name == RS_CREATEANDWAIT) { code: StorageTmp->$name = RS_NOTINSERVICE; code: } code: } code: break; code: } code: return SNMP_ERR_NOERROR; code: } code: