/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
*
* U.S. Government Rights - Commercial software. Government users are subject to
* the Sun Microsystems, Inc. standard license agreement and applicable
* provisions of the FAR and its supplements.
*
*
* This distribution may include materials developed by third parties. Sun, Sun
* Microsystems, the Sun logo and Solaris are trademarks or registered
* trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
*/
/*
* Note: this file originally auto-generated by mib2c using :
* mib2c.iterate.conf,v 1.1.1.1 2003/03/26 18:12:29 pcarroll Exp $
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "demo_module_5.h"
#include <net-snmp/agent/agent_trap.h>
/*
* MAXNAMELEN is the maximum permissible file name defined in param.h
*/
fileEntry *fileList = 0;
char file1[MAXNAMELEN], file2[MAXNAMELEN], file3[MAXNAMELEN],
file4[MAXNAMELEN];
/** Initialize the me5FileTable table by defining its contents and how it's structured */
void
initialize_table_me5FileTable(void)
{
static oid me5FileTable_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 4, 5, 2, 1};
netsnmp_table_registration_info *table_info;
netsnmp_handler_registration *my_handler;
netsnmp_iterator_info *iinfo;
/* create the table structure itself */
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
/*
* if your table is read only, it's easiest to change the
* HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY
*/
my_handler = netsnmp_create_handler_registration("me5FileTable",
me5FileTable_handler,
me5FileTable_oid,
OID_LENGTH(me5FileTable_oid),
HANDLER_CAN_RWRITE);
if (!my_handler || !table_info || !iinfo) {
return; /* mallocs failed */
}
/***************************************************
* Setting up the table's definition
*/
netsnmp_table_helper_add_indexes(table_info,
ASN_UNSIGNED, /* index: me5FileIndex */
0);
table_info->min_column = 1;
table_info->max_column = 4;
/* iterator access routines */
iinfo->get_first_data_point = me5FileTable_get_first_data_point;
iinfo->get_next_data_point = me5FileTable_get_next_data_point;
iinfo->table_reginfo = table_info;
/***************************************************
* registering the table with the master agent
*/
DEBUGMSGTL(("initialize_table_me5FileTable",
"Registering table me5FileTable as a table iterator\n"));
netsnmp_register_table_iterator(my_handler, iinfo);
}
/** Initializes the demo_module_5 module */
void
init_demo_module_5(void)
{
/* here we initialize all the tables we're planning on supporting */
initialize_table_me5FileTable();
/*
* These are the default files that are monitored by the module if there
* is no persistent data (file names to be monitored). This is likely
* during the first running on the module, when the .conf file does not
* have any file related information.
*/
strcpy(file1, "/etc/hosts");
strcpy(file2, "/etc/group");
strcpy(file3, "/etc/passwd");
strcpy(file4, "/etc/system");
/*
* Register for tokens from demo_module_5.conf file. The names of the
* tokens are demo5_file1,demo5_file2,demo5_file3,demo5_file4. The function
* demo5_load_tokens is called whenever these 4 tokens are encountered in
* demo_module_5.conf file.
*/
register_config_handler(DEMO5_CONF_FILE, "demo5_file1",
demo5_load_tokens, NULL, NULL);
register_config_handler(DEMO5_CONF_FILE, "demo5_file2",
demo5_load_tokens, NULL, NULL);
register_config_handler(DEMO5_CONF_FILE, "demo5_file3",
demo5_load_tokens, NULL, NULL);
register_config_handler(DEMO5_CONF_FILE, "demo5_file4",
demo5_load_tokens, NULL, NULL);
/*
* Register for a callback when all the configuration files are read. The
* callback function here is demo5_post_read_config
*/
snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG,
demo5_post_read_config, NULL);
}
/** returns the first data point within the me5FileTable table data.
Set the my_loop_context variable to the first data point structure
of your choice (from which you can find the next one). This could
be anything from the first node in a linked list, to an integer
pointer containing the beginning of an array variable.
Set the my_data_context variable to something to be returned to
you later that will provide you with the data to return in a given
row. This could be the same pointer as what my_loop_context is
set to, or something different.
The put_index_data variable contains a list of snmp variable
bindings, one for each index in your table. Set the values of
each appropriately according to the data matching the first row
and return the put_index_data variable at the end of the function.
*/
netsnmp_variable_list *
me5FileTable_get_first_data_point(void **my_loop_context, void **my_data_context,
netsnmp_variable_list * put_index_data,
netsnmp_iterator_info * mydata)
{
netsnmp_variable_list *vptr;
fileEntry *firstFile = fileList;
if (!firstFile) {
return NULL;
}
*my_loop_context = firstFile;
*my_data_context = firstFile;
vptr = put_index_data;
snmp_set_var_value(vptr, (u_char *) & fileList->findex, sizeof(fileList->findex));
vptr = vptr->next_variable;
return put_index_data;
}
/** functionally the same as me5FileTable_get_first_data_point, but
my_loop_context has already been set to a previous value and should
be updated to the next in the list. For example, if it was a
linked list, you might want to cast it and the return
my_loop_context->next. The my_data_context pointer should be set
to something you need later and the indexes in put_index_data
updated again. */
netsnmp_variable_list *
me5FileTable_get_next_data_point(void **my_loop_context, void **my_data_context,
netsnmp_variable_list * put_index_data,
netsnmp_iterator_info * mydata)
{
netsnmp_variable_list *vptr;
fileEntry *nextNode = (fileEntry *) * my_loop_context;
nextNode = nextNode->next;
if (!nextNode) {
return NULL;
}
*my_loop_context = nextNode;
*my_data_context = nextNode;
vptr = put_index_data;
snmp_set_var_value(vptr, (u_char *) & nextNode->findex,
sizeof(nextNode->findex));
vptr = vptr->next_variable;
return put_index_data;
}
/** handles requests for the me5FileTable table, if anything else needs to be done */
int
me5FileTable_handler(
netsnmp_mib_handler * handler,
netsnmp_handler_registration * reginfo,
netsnmp_agent_request_info * reqinfo,
netsnmp_request_info * requests)
{
netsnmp_request_info *request;
netsnmp_table_request_info *table_info;
netsnmp_variable_list *var;
fileEntry *data;
char *fileName = NULL;
char *undofn;
int len;
char filebuf[255];
for (request = requests; request; request = request->next) {
var = request->requestvb;
if (request->processed != 0)
continue;
/*
* the following extracts the my_data_context pointer set in the loop
* functions above. You can then use the results to help return data
* for the columns of the me5FileTable table in question
*/
data = (fileEntry *) netsnmp_extract_iterator_context(request);
if (data == NULL) {
if (reqinfo->mode == MODE_GET) {
netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
} else {
netsnmp_set_request_error(reqinfo, request,
SNMP_ERR_NOCREATION);
}
continue;
} else {
struct stat fAttrib;
if (stat(GetFileName(data->findex), &fAttrib) != -1) {
data->fileSize = fAttrib.st_size;
sprintf(data->filePerm, "%o", fAttrib.st_mode & 0777);
} else {
data->fileSize = 0;
sprintf(data->filePerm, "%d", -1);
}
}
/* extracts the information about the table from the request */
table_info = netsnmp_extract_table_info(request);
/* table_info->colnum contains the column number requested */
/*
* table_info->indexes contains a linked list of snmp variable
* bindings for the indexes of the table. Values in the list have
* been set corresponding to the indexes of the request
*/
if (table_info == NULL) {
continue;
}
switch (reqinfo->mode) {
/*
* the table_iterator helper should change all GETNEXTs into GETs
* for you automatically, so you don't have to worry about the
* GETNEXT case. Only GETs and SETs need to be dealt with here
*/
case MODE_GET:
switch (table_info->colnum) {
case COLUMN_ME5FILEINDEX:
snmp_set_var_typed_value(var, ASN_UNSIGNED,
(u_char *) & data->findex,
sizeof(data->findex));
break;
case COLUMN_ME5FILENAME:
snmp_set_var_typed_value(var, ASN_OCTET_STR,
(u_char *) data->fileName,
strlen(data->fileName));
break;
case COLUMN_ME5FILESIZE:
snmp_set_var_typed_value(var, ASN_UNSIGNED,
(u_char *) & data->fileSize,
sizeof(data->fileSize));
break;
case COLUMN_ME5FILEPERM:
snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->filePerm,
strlen(data->filePerm));
break;
default:
/* We shouldn't get here */
snmp_log(LOG_ERR,
"problem encountered in me5FileTable_handler: unknown column\n");
}
break;
case MODE_SET_RESERVE1:
/* set handling... */
switch (table_info->colnum) {
/*
* Check that the value being set is acceptable
*/
case COLUMN_ME5FILENAME:
if (var->type != ASN_OCTET_STR) {
DEBUGMSGTL(("me5FileTable", "COLUMN NAME\n"));
DEBUGMSGTL(("me5FileTable", "%x not octet string type", var->type));
netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
return SNMP_ERR_WRONGTYPE;
}
if (!var->val.string) {
DEBUGMSGTL(("me2FileTable", "Empty file name"));
netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE);
return SNMP_ERR_WRONGVALUE;
}
break;
default:
/* We shouldn't get here */
snmp_log(LOG_ERR,
"problem encountered in me5FileTable_handler: unknown column\n");
netsnmp_set_request_error(reqinfo, request, SNMP_ERR_READONLY);
return SNMP_ERR_NOTWRITABLE;
}
break;
case MODE_SET_RESERVE2:
/*
* This is conventially where any necesary resources are
* allocated (e.g. calls to malloc)
*/
/* Store old info for undo later */
undofn = GetFileName(data->findex);
if (undofn) {
if (!(fileName = strdup(undofn))) {
netsnmp_set_request_error(reqinfo, request,
SNMP_ERR_RESOURCEUNAVAILABLE);
} else
netsnmp_request_add_list_data(request,
netsnmp_create_data_list
(ME5FILE_SET_FILENAME, fileName,
free));
}
break;
case MODE_SET_FREE:
/*
* This is where any of the above resources are freed again
* (because one of the other values being SET failed for some
* reason).
*/
/*
* The netsnmp_free_list_data should take care of the alocated
* resources
*/
break;
case MODE_SET_ACTION:
/*
* Set the variable as requested. Note that this may need to be
* reversed, so save any information needed to do this.
*/
len = var->val_len;
var->val.string[len] = '\0';
if (!ChangeItem(data->findex, (char *) var->val.string )) {
netsnmp_set_request_error(reqinfo, request,
SNMP_ERR_COMMITFAILED);
}
break;
case MODE_SET_COMMIT:
/*
* Everything worked, so we can discard any saved information,
* and make the change permanent (e.g. write to the config file).
* We also free any allocated resources.
*
*/
/* Persist the file information */
snprintf(&filebuf[0], MAXNAMELEN, "demo5_file%d %s",
data->findex, data->fileName);
read_config_store(DEMO5_CONF_FILE, &filebuf[0]);
/*
* The netsnmp_free_list_data should take care of the alocated
* resources
*/
break;
case MODE_SET_UNDO:
/*
* Something failed, so re-set the variable to its previous value
* (and free any allocated resources).
*/
if (GetFileName(data->findex)) {
/******* Get the saved value ************/
undofn = (char *) netsnmp_request_get_list_data(request,
ME5FILE_SET_FILENAME);
if (!ChangeItem(data->findex, undofn)) {
netsnmp_set_request_error(reqinfo, request,
SNMP_ERR_UNDOFAILED);
}
}
break;
default:
snmp_log(LOG_ERR,
"problem encountered in me5FileTable_handler: unsupported mode\n");
}
}
return SNMP_ERR_NOERROR;
}
/* Function to add a fileName to the linked list of files */
int
AddItem(char *fileName)
{
fileEntry *fprt = fileList;
struct stat fAttrib; /* Need to check if memory is valid */
if (!fileName || !strlen(fileName)) {
return FALSE;
}
if (stat(fileName, &fAttrib) == -1) {
/*
* Unable to get the file information, it could be more than file not
* exists if (errno == ENOENT) { return FALSE; } return FALSE;
*/
DEBUGMSGTL(("demo_module_5", "Can't access the file %s", fileName));
}
if (fprt != NULL) {
while (fprt->next != NULL) {
fprt = fprt->next;
}
fprt->next = (fileEntry *) malloc(sizeof(fileEntry));
fprt->next->findex = fprt->findex + 1;
fprt = fprt->next;
fprt->next = NULL;
strcpy(fprt->fileName, fileName);
fprt->fileSize = fAttrib.st_size;
sprintf(fprt->filePerm, "%d", fAttrib.st_mode);
} else {
fprt = (fileEntry *) malloc(sizeof(fileEntry));
fprt->next = NULL;
fprt->findex = 1;
strcpy(fprt->fileName, fileName);
fprt->fileSize = fAttrib.st_size;
sprintf(fprt->filePerm, "%d", fAttrib.st_mode);
fileList = fprt;
}
return TRUE;
}
/*
* Function to change the file for a particular index. This function is
* called when a snmp set request arrives to change the list of files being
* monitored.
*/
int
ChangeItem(int fileIndex, char *fileName)
{
fileEntry *tempp = fileList;
if (!fileName || !strlen(fileName)) {
return FALSE;
}
while (tempp != NULL) {
if (tempp->findex == fileIndex) {
strcpy(tempp->fileName, fileName);
switch(fileIndex) {
case 1:
strcpy(file1, fileName);
case 2:
strcpy(file2, fileName);
case 3:
strcpy(file3, fileName);
case 4:
strcpy(file4, fileName);
}
return TRUE;
}
tempp = tempp->next;
}
return FALSE;
}
/* Function to return the filename corresponding to an index */
char *
GetFileName(int fIndex)
{
fileEntry *fprt = fileList;
while (fprt != NULL) {
if (fprt->findex == fIndex) {
return fprt->fileName;
}
fprt = fprt->next;
}
return NULL;
}
/*
* Function that is called whenever interested tokens are encountered in
* demo_module_5.conf file. The token values represent the persistent filename
* information.
*/
void
demo5_load_tokens(const char *token, char *cptr)
{
if (strcmp(token, "demo5_file1") == 0) {
strcpy(file1, cptr);
} else if (strcmp(token, "demo5_file2") == 0) {
strcpy(file2, cptr);
} else if (strcmp(token, "demo5_file3") == 0) {
strcpy(file3, cptr);
} else if (strcmp(token, "demo5_file4") == 0) {
strcpy(file4, cptr);
} else {
/* Do Nothing */
}
return;
}
/*
* Function that persists file information. This is called by the agent
* whenever data needs to be persisted.
*/
int
demo5_persist_data(int a, int b, void *c, void *d)
{
char filebuf[300];
sprintf(filebuf, "demo5_file1 %s", file1);
read_config_store(DEMO5_CONF_FILE, filebuf);
sprintf(filebuf, "demo5_file2 %s", file2);
read_config_store(DEMO5_CONF_FILE, filebuf);
sprintf(filebuf, "demo5_file3 %s", file3);
read_config_store(DEMO5_CONF_FILE, filebuf);
sprintf(filebuf, "demo5_file4 %s", file4);
read_config_store(DEMO5_CONF_FILE, filebuf);
}
/*
* Callback function that is called after all the configuration files are
* read by the agent. See init_demo_module_5 function to see how this
* callback is specified.
*
* When this function is called, any persistent file information would have been
* read into the module. These files are added to the file list.
*
* The callback function to persist data (demo5_persist_data) is registered.
*/
int
demo5_post_read_config(int a, int b, void *c, void *d)
{
if (!AddItem(file1))
snmp_log(LOG_ERR, "Failed to add instance in init_demo_module_5\n");
if (!AddItem(file2))
snmp_log(LOG_ERR, "Failed to add instance in init_demo_module_5\n");
if (!AddItem(file3))
snmp_log(LOG_ERR, "Failed to add instance in init_demo_module_5\n");
if (!AddItem(file4))
snmp_log(LOG_ERR, "Failed to add instance in init_demo_module_5\n");
snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
demo5_persist_data, NULL);
}