components/net-snmp/sun/sdk/demo/demo_module_5/demo_module_5.c
changeset 252 ee0fb1eabcbf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/net-snmp/sun/sdk/demo/demo_module_5/demo_module_5.c	Fri May 20 12:17:45 2011 +0530
@@ -0,0 +1,646 @@
+/*
+ * 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);
+
+
+}
+