Solaris System Management Agent Developer's Guide

Chapter 4 Storing Module Data

This chapter discusses how a module can store data that persists when the agent is restarted.

The chapter includes the following topics:

About Storing Module Data

You might want your module to store persistent data. Persistent data is information such as configuration settings that the module stores in a file and reads from that file. The data is preserved across restarts of the agent.

Modules can store tokens with assigned values in module-specific configuration files. A configuration file is created manually. Tokens can be written to the file or read from the file by a module. The module registers handlers that are associated with the module's specific configuration tokens.

Configuration Files

The snmp_config(4) man page discusses SNMP configuration files in general. The man page documents the locations where the files can be stored so the agent can find the files. These locations are on the default search path for SNMP configuration files.

For your modules, the best location to store configuration files is in a $HOME/.snmp directory, which is on the default search path. You can also set the SNMPCONFPATH environment variable if you want to use a non-default location for configuration files.

When you create your own configuration file, you must name the file module.conf or module.local.conf. You must place the file in one of the directories on the SNMP configuration file search path.


Note –

You might find that the Net-SNMP routines write your module's configuration file to the /var/sma_snmp directory. The routines make updates to that version of the file. However, the routines can find the configuration file in other locations when the module needs to initially read the file.


Defining New Configuration Tokens

Configuration tokens are used by modules to get persistent data during runtime. When your module uses custom configuration tokens, you should create one or more custom configuration files for the module. You might also choose to create one configuration file for several related modules. You can define new tokens in the custom configuration file.

Custom tokens must use the same format as the directives in snmpd.conf. One token is defined in each line of the configuration file. The configuration tokens are written in the form:

Token Value

For example, your token might be:


my_token 4

Modules should not define custom tokens in the SNMP configuration file, /etc/sma/snmp/snmpd.conf. If a module stores tokens in /etc/sma/snmp/snmpd.conf, namespace collisions can potentially occur. See Avoiding Namespace Collisions for more information about namespace collisions.

Implementing Persistent Data in a Module

The module can register handlers that are associated with tokens in a module-specific configuration file with the register_config_handler() function. The handlers can then be used later in the module for a specific task.

The register_config_handler() is defined as follows:

register_config_handler (const char *type_param, const char *token, 
                    void(*parser)(const char *, char *),
                    void(*releaser)(void), const char *help)   

The first argument to this function designates the base name of the configuration file, which should be the same as the name of the module. For example, if the first argument is my_custom_module, then the agent infrastructure looks for the configuration tokens in the file my_custom_module.conf. Note that you must create the configuration file manually before the module can use the file.

The second argument to this function designates the configuration token that the module is looking for.

For more information about register_config_handler() and other related functions, see the API documentation in /usr/sfw/doc/sma_snmp/html/group__read__config.html. You can also look at /usr/demo/sma_snmp/demo_module_5/demo_module_5.c to see how the function is used.

Storing Persistent Data

Your module must use the read_config_store_data() and read_config_store() functions together with callback functions to store data.

Your module must first register a callback with the snmp_register_callback() function so that data is written to the configuration file when the agent shuts down.

The snmp_register_callback() function is as follows:

int snmp_register_callback(int major, 
                           int minor, 
                           SNMPCallback *new_callback, 
                           void *arg);

You must set major to SNMP_CALLBACK_LIBRARY, set minor to SNMP_CALLBACK_STORE_DATA. When arg is not set to NULL, arg is a void pointer used whenever the new_callback function is exercised.

The prototype to your callback function, the new_callback pointer, is as follows:

int (SNMPCallback) (int majorID, 
                    int minorID, 
                    void *serverarg, 
                    void *clientarg);

See the API documentation for more information about setting up callback registrations with the agent at /usr/sfw/doc/sma_snmp/html/group__callback.html.

The read_config_store_data() function should be used to create the token-value pair that is to be written into the module's configuration file. The read_config_store() function actually does the storing when the registered callbacks are exercised upon agent shutdown.


Note –

When your module stores persistent data, you might find that the configuration file is written to the /var/sma_snmp directory. Modified token-value pairs are appended to the file, rather than overwriting the previous token-value pairs in the file. The last values that were defined in the file are the values that are used.


Reading Persistent Data

Data is read from a module's configuration file into the module by using the register_config_handler() function. For example, you can call the function as follows:

register_config_handler("my_module", "some_token",
                            load_my_tokens, NULL, NULL);

Whenever the token some_token is read by the agent in my_module.conf file, the load_my_tokens() function is called with token name and value as arguments. The load_my_tokens() function is invoked. The data can be parsed by using the read_config_read_data() function.

demo_module_5 Code Example for Persistent Data

The demo_module_5 code example demonstrates the persistence of data across agent restart. The demo is located in the directory /usr/demo/sma_snmp/demo_module_5 by default.

This module implements SDK-DEMO5-MIB.txt. The demo_module_5.c and demo_module_5.h templates were renamed from the original templates me5FileGroup.c and me5FileGroup.h that were generated with the mib2c command. The name of the initialization function is changed from init_me5FileGroup to init_demo_module_5.

See the README_demo_module_5 file in the demo_module_5 directory for the procedures to build and run the demo.

Storing Persistent Data in demo_module_5

This example stores configuration data in the /var/sma_snmp/demo_module_5.conf file.

In demo_module_5.c, the following statement registers the callback function. The callback function is called whenever the agent sees that module data needs to be stored, such as during normal termination of the agent.

snmp_register_callback(SNMP_CALLBACK_LIBRARY, 
                                SNMP_CALLBACK_STORE_DATA,
                                demo5_persist_data, 
                                NULL);

The demo5_persist_data() function uses read_store_config to store data:

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);

}

In demo_module_5, a new file can be added for monitoring, by using the snmpset command. The commit phase of the snmpset request uses the read_config_store() function to store file information:

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 allocated
	     * resources
	     */

The persistent data is stored in the /var/sma_snmp/demo_module_5.conf file.

Reading Persistent Data in demo_module_5

Data is read from the configuration files into a module by registering a callback function to be called whenever an relevant token is encountered. For example, you can call the function as follows:

register_config_handler(DEMO5_CONF_FILE, "demo5_file1",
demo5_load_tokens, NULL, NULL);

Whenever the demo5_file1 token in the demo_module_5.conf file is read by the agent, the function demo5_load_tokens() is called with token name and value as arguments. The demo5_load_tokens() function stores the token value in appropriate variables:

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;

}

Using SNMP_CALLBACK_POST_READ_CONFIG in demo_module_5

A few seconds elapse after agent startup while all configuration tokens are read by the module. During this interval, the module should not perform certain functions. For example, until the persistent file names are read from /var/sma_snmp/demo_module_5.conf into the module, the file table cannot be populated. To handle these cases, a callback function can be set. This callback function is called when the process of reading the configuration files is complete. For example, you might call the function as follows:


snmp_register_callback(SNMP_CALLBACK_LIBRARY,
 SNMP_CALLBACK_POST_READ_CONFIG, demo_5_post_read_config, NULL);

The demo_5_post_read_config() function is called after the configuration files are read. In this example, the demo_5_post_read_config() function populates the file table, then registers the callback function for data persistence.

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);

}