Blame snmplib/text_utils.c

Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
#include <net-snmp/net-snmp-features.h>
Packit fcad23
#include <net-snmp/net-snmp-includes.h>
Packit fcad23
Packit fcad23
#include <stdio.h>
Packit fcad23
#include <ctype.h>
Packit fcad23
#if HAVE_STDLIB_H
Packit fcad23
#   include <stdlib.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_UNISTD_H
Packit fcad23
#   include <unistd.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_STRING_H
Packit fcad23
#   include <string.h>
Packit fcad23
#else
Packit fcad23
#  include <strings.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <sys/types.h>
Packit fcad23
Packit fcad23
#if HAVE_LIMITS_H
Packit fcad23
#   include <limits.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_SYS_PARAM_H
Packit fcad23
#   include <sys/param.h>
Packit fcad23
#endif
Packit fcad23
#ifdef HAVE_SYS_STAT_H
Packit fcad23
#   include <sys/stat.h>
Packit fcad23
#endif
Packit fcad23
#ifdef HAVE_FCNTL_H
Packit fcad23
#   include <fcntl.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <errno.h>
Packit fcad23
Packit fcad23
#if HAVE_DMALLOC_H
Packit fcad23
#  include <dmalloc.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <net-snmp/types.h>
Packit fcad23
#include <net-snmp/library/snmp_debug.h>
Packit fcad23
#include <net-snmp/library/container.h>
Packit fcad23
#include <net-snmp/library/file_utils.h>
Packit fcad23
#include <net-snmp/library/text_utils.h>
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(text_utils, libnetsnmp)
Packit fcad23
Packit fcad23
netsnmp_feature_provide(text_utils)
Packit fcad23
#ifdef NETSNMP_FEATURE_REQUIRE_TEXT_UTILS
Packit fcad23
netsnmp_feature_require(file_utils)
Packit fcad23
#endif /* NETSNMP_FEATURE_REQUIRE_TEXT_UTILS */
Packit fcad23
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_TEXT_UTILS
Packit fcad23
/*------------------------------------------------------------------
Packit fcad23
 *
Packit fcad23
 * Prototypes
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
/*
Packit fcad23
 * parse methods
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_pm_save_index_string_string(FILE *f, netsnmp_container *cin,
Packit fcad23
                             int flags);
Packit fcad23
static void
Packit fcad23
_pm_save_everything(FILE *f, netsnmp_container *cin, int flags);
Packit fcad23
Packit fcad23
static void
Packit fcad23
_pm_user_function(FILE *f, netsnmp_container *cin,
Packit fcad23
                  netsnmp_line_process_info *lpi, int flags);
Packit fcad23
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * line processors
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
_process_line_tvi(netsnmp_line_info *line_info, void *mem,
Packit fcad23
                  struct netsnmp_line_process_info_s* lpi);
Packit fcad23
Packit fcad23
Packit fcad23
Packit fcad23
/*------------------------------------------------------------------
Packit fcad23
 *
Packit fcad23
 * Text file processing functions
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * process text file, reading into extras
Packit fcad23
 */
Packit fcad23
netsnmp_container *
Packit fcad23
netsnmp_file_text_parse(netsnmp_file *f, netsnmp_container *cin,
Packit fcad23
                        int parse_mode, u_int flags, void *context)
Packit fcad23
{
Packit fcad23
    netsnmp_container *c = cin;
Packit fcad23
    FILE              *fin;
Packit fcad23
    int                rc;
Packit fcad23
Packit fcad23
    if (NULL == f)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    if ((NULL == c) && (!(flags & PM_FLAG_NO_CONTAINER))) {
Packit fcad23
        c = netsnmp_container_find("text_parse:binary_array");
Packit fcad23
        if (NULL == c)
Packit fcad23
            return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    rc = netsnmp_file_open(f);
Packit fcad23
    if (rc < 0) { /** error already logged */
Packit fcad23
        if ((NULL !=c) && (c != cin))
Packit fcad23
            CONTAINER_FREE(c);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    /*
Packit fcad23
     * get a stream from the file descriptor. This DOES NOT rewind the
Packit fcad23
     * file (if fd was previously opened).
Packit fcad23
     */
Packit fcad23
    fin = fdopen(f->fd, "r");
Packit fcad23
    if (NULL == fin) {
Packit fcad23
        if (NS_FI_AUTOCLOSE(f->ns_flags))
Packit fcad23
            close(f->fd);
Packit fcad23
        if ((NULL !=c) && (c != cin))
Packit fcad23
            CONTAINER_FREE(c);
Packit fcad23
        return NULL;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    switch (parse_mode) {
Packit fcad23
Packit fcad23
        case PM_SAVE_EVERYTHING:
Packit fcad23
            _pm_save_everything(fin, c, flags);
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case PM_INDEX_STRING_STRING:
Packit fcad23
            _pm_save_index_string_string(fin, c, flags);
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case PM_USER_FUNCTION:
Packit fcad23
            if (NULL != context)
Packit fcad23
                _pm_user_function(fin, c, (netsnmp_line_process_info*)context,
Packit fcad23
                                  flags);
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        default:
Packit fcad23
            snmp_log(LOG_ERR, "unknown parse mode %d\n", parse_mode);
Packit fcad23
            break;
Packit fcad23
    }
Packit fcad23
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * close the stream, which will have the side effect of also closing
Packit fcad23
     * the file descriptor, so we need to reset it.
Packit fcad23
     */
Packit fcad23
    fclose(fin);
Packit fcad23
    f->fd = -1;
Packit fcad23
Packit fcad23
    return c;
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(text_token_container_from_file, netsnmp_unused)
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_TEXT_TOKEN_CONTAINER_FROM_FILE
Packit fcad23
netsnmp_container *
Packit fcad23
netsnmp_text_token_container_from_file(const char *file, u_int flags,
Packit fcad23
                                       netsnmp_container *cin, void *context)
Packit fcad23
{
Packit fcad23
    netsnmp_line_process_info  lpi;
Packit fcad23
    netsnmp_container         *c = cin, *c_rc;
Packit fcad23
    netsnmp_file              *fp;
Packit fcad23
Packit fcad23
    if (NULL == file)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * allocate file resources
Packit fcad23
     */
Packit fcad23
    fp = netsnmp_file_fill(NULL, file, O_RDONLY, 0, 0);
Packit fcad23
    if (NULL == fp) /** msg already logged */
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    memset(&lpi, 0x0, sizeof(lpi));
Packit fcad23
    lpi.mem_size = sizeof(netsnmp_token_value_index);
Packit fcad23
    lpi.process = _process_line_tvi;
Packit fcad23
    lpi.user_context = context;
Packit fcad23
Packit fcad23
    if (NULL == c) {
Packit fcad23
        c = netsnmp_container_find("string:binary_array");
Packit fcad23
        if (NULL == c) {
Packit fcad23
            snmp_log(LOG_ERR,"malloc failed\n");
Packit fcad23
            netsnmp_file_release(fp);
Packit fcad23
            return NULL;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    c_rc = netsnmp_file_text_parse(fp, c, PM_USER_FUNCTION, 0, &lpi;;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if we got a bad return and the user didn't pass us a container,
Packit fcad23
     * we need to release the container we allocated.
Packit fcad23
     */
Packit fcad23
    if ((NULL == c_rc) && (NULL == cin)) {
Packit fcad23
        CONTAINER_FREE(c);
Packit fcad23
        c = NULL;
Packit fcad23
    }
Packit fcad23
    else
Packit fcad23
        c = c_rc;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * release file resources
Packit fcad23
     */
Packit fcad23
    netsnmp_file_release(fp);
Packit fcad23
    
Packit fcad23
    return c;
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_TEXT_TOKEN_CONTAINER_FROM_FILE */
Packit fcad23
Packit fcad23
Packit fcad23
/*------------------------------------------------------------------
Packit fcad23
 *
Packit fcad23
 * Text file process modes helper functions
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * @internal
Packit fcad23
 * parse mode: save everything
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_pm_save_everything(FILE *f, netsnmp_container *cin, int flags)
Packit fcad23
{
Packit fcad23
    char               line[STRINGMAX], *ptr;
Packit fcad23
    size_t             len;
Packit fcad23
Packit fcad23
    netsnmp_assert(NULL != f);
Packit fcad23
    netsnmp_assert(NULL != cin);
Packit fcad23
Packit fcad23
    while (fgets(line, sizeof(line), f) != NULL) {
Packit fcad23
Packit fcad23
        ptr = line;
Packit fcad23
        len = strlen(line) - 1;
Packit fcad23
        if (line[len] == '\n')
Packit fcad23
            line[len] = 0;
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * save blank line or comment?
Packit fcad23
         */
Packit fcad23
        if (flags & PM_FLAG_SKIP_WHITESPACE) {
Packit fcad23
            if (NULL == (ptr = skip_white(ptr)))
Packit fcad23
                continue;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        ptr = strdup(line);
Packit fcad23
        if (NULL == ptr) {
Packit fcad23
            snmp_log(LOG_ERR,"malloc failed\n");
Packit fcad23
            break;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        CONTAINER_INSERT(cin,ptr);
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * @internal
Packit fcad23
 * parse mode:
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_pm_save_index_string_string(FILE *f, netsnmp_container *cin,
Packit fcad23
                             int flags)
Packit fcad23
{
Packit fcad23
    char                        line[STRINGMAX], *ptr;
Packit fcad23
    netsnmp_token_value_index  *tvi;
Packit fcad23
    size_t                      count = 0, len;
Packit fcad23
Packit fcad23
    netsnmp_assert(NULL != f);
Packit fcad23
    netsnmp_assert(NULL != cin);
Packit fcad23
Packit fcad23
    while (fgets(line, sizeof(line), f) != NULL) {
Packit fcad23
Packit fcad23
        ++count;
Packit fcad23
        ptr = line;
Packit fcad23
        len = strlen(line) - 1;
Packit fcad23
        if (line[len] == '\n')
Packit fcad23
            line[len] = 0;
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * save blank line or comment?
Packit fcad23
         */
Packit fcad23
        if (flags & PM_FLAG_SKIP_WHITESPACE) {
Packit fcad23
            if (NULL == (ptr = skip_white(ptr)))
Packit fcad23
                continue;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        tvi = SNMP_MALLOC_TYPEDEF(netsnmp_token_value_index);
Packit fcad23
        if (NULL == tvi) {
Packit fcad23
            snmp_log(LOG_ERR,"malloc failed\n");
Packit fcad23
            break;
Packit fcad23
        }
Packit fcad23
            
Packit fcad23
        /*
Packit fcad23
         * copy whole line, then set second pointer to
Packit fcad23
         * after token. One malloc, 2 strings!
Packit fcad23
         */
Packit fcad23
        tvi->index = count;
Packit fcad23
        tvi->token = strdup(line);
Packit fcad23
        if (NULL == tvi->token) {
Packit fcad23
            snmp_log(LOG_ERR,"malloc failed\n");
Packit fcad23
            free(tvi);
Packit fcad23
            break;
Packit fcad23
        }
Packit fcad23
        tvi->value.cp = skip_not_white(tvi->token);
Packit fcad23
        if (NULL != tvi->value.cp) {
Packit fcad23
            *(tvi->value.cp) = 0;
Packit fcad23
            ++(tvi->value.cp);
Packit fcad23
        }
Packit fcad23
        CONTAINER_INSERT(cin, tvi);
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * @internal
Packit fcad23
 * parse mode:
Packit fcad23
 */
Packit fcad23
static void
Packit fcad23
_pm_user_function(FILE *f, netsnmp_container *cin,
Packit fcad23
                  netsnmp_line_process_info *lpi, int flags)
Packit fcad23
{
Packit fcad23
    char                        buf[STRINGMAX];
Packit fcad23
    netsnmp_line_info           li;
Packit fcad23
    void                       *mem = NULL;
Packit fcad23
    int                         rc;
Packit fcad23
Packit fcad23
    netsnmp_assert(NULL != f);
Packit fcad23
    netsnmp_assert(NULL != cin);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * static buf, or does the user want the memory?
Packit fcad23
     */
Packit fcad23
    if (flags & PMLP_FLAG_ALLOC_LINE) {
Packit fcad23
        if (0 != lpi->line_max)
Packit fcad23
            li.line_max =  lpi->line_max;
Packit fcad23
        else
Packit fcad23
            li.line_max = STRINGMAX;
Packit fcad23
        li.line = (char *)calloc(li.line_max, 1);
Packit fcad23
        if (NULL == li.line) {
Packit fcad23
            snmp_log(LOG_ERR,"malloc failed\n");
Packit fcad23
            return;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    else {
Packit fcad23
        li.line = buf;
Packit fcad23
        li.line_max = sizeof(buf);
Packit fcad23
    }
Packit fcad23
        
Packit fcad23
    li.index = 0;
Packit fcad23
    while (fgets(li.line, li.line_max, f) != NULL) {
Packit fcad23
Packit fcad23
        ++li.index;
Packit fcad23
        li.start = li.line;
Packit fcad23
        li.line_len = strlen(li.line) - 1;
Packit fcad23
        if ((!(lpi->flags & PMLP_FLAG_LEAVE_NEWLINE)) &&
Packit fcad23
            (li.line[li.line_len] == '\n'))
Packit fcad23
            li.line[li.line_len] = 0;
Packit fcad23
        
Packit fcad23
        /*
Packit fcad23
         * save blank line or comment?
Packit fcad23
         */
Packit fcad23
        if (!(lpi->flags & PMLP_FLAG_PROCESS_WHITESPACE)) {
Packit fcad23
            if (NULL == (li.start = skip_white(li.start)))
Packit fcad23
                continue;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         *  do we need to allocate memory for the use?
Packit fcad23
         * if the last call didn't use the memory we allocated,
Packit fcad23
         * re-use it. Otherwise, allocate new chunk.
Packit fcad23
         */
Packit fcad23
        if ((0 != lpi->mem_size) && (NULL == mem)) {
Packit fcad23
            mem = calloc(lpi->mem_size, 1);
Packit fcad23
            if (NULL == mem) {
Packit fcad23
                snmp_log(LOG_ERR,"malloc failed\n");
Packit fcad23
                break;
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * do they want a copy ot the line?
Packit fcad23
         */
Packit fcad23
        if (lpi->flags & PMLP_FLAG_STRDUP_LINE) {
Packit fcad23
            li.start = strdup(li.start);
Packit fcad23
            if (NULL == li.start) {
Packit fcad23
                snmp_log(LOG_ERR,"malloc failed\n");
Packit fcad23
                break;
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
        else if (lpi->flags & PMLP_FLAG_ALLOC_LINE) {
Packit fcad23
            li.start = li.line;
Packit fcad23
        }
Packit fcad23
Packit fcad23
        /*
Packit fcad23
         * call the user function. If the function wants to save
Packit fcad23
         * the memory chunk, insert it in the container, the clear
Packit fcad23
         * pointer so we reallocate next time.
Packit fcad23
         */
Packit fcad23
        li.start_len = strlen(li.start);
Packit fcad23
        rc = (*lpi->process)(&li, mem, lpi);
Packit fcad23
        if (PMLP_RC_MEMORY_USED == rc) {
Packit fcad23
Packit fcad23
            if (!(lpi->flags & PMLP_FLAG_NO_CONTAINER))
Packit fcad23
                CONTAINER_INSERT(cin, mem);
Packit fcad23
            
Packit fcad23
            mem = NULL;
Packit fcad23
            
Packit fcad23
            if (lpi->flags & PMLP_FLAG_ALLOC_LINE) {
Packit fcad23
	        li.line = (char *)calloc(li.line_max, 1);
Packit fcad23
                if (NULL == li.line) {
Packit fcad23
                    snmp_log(LOG_ERR,"malloc failed\n");
Packit fcad23
                    break;
Packit fcad23
                }
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
        else if (PMLP_RC_MEMORY_UNUSED == rc ) {
Packit fcad23
            /*
Packit fcad23
             * they didn't use the memory. if li.start was a strdup, we have
Packit fcad23
             * to release it. leave mem, we can re-use it (its a fixed size).
Packit fcad23
             */
Packit fcad23
            if (lpi->flags & PMLP_FLAG_STRDUP_LINE)
Packit fcad23
                free(li.start); /* no point in SNMP_FREE */
Packit fcad23
        }
Packit fcad23
        else {
Packit fcad23
            if (PMLP_RC_STOP_PROCESSING != rc )
Packit fcad23
                snmp_log(LOG_ERR, "unknown rc %d from text processor\n", rc);
Packit fcad23
            break;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    SNMP_FREE(mem);
Packit fcad23
}
Packit fcad23
Packit fcad23
/*------------------------------------------------------------------
Packit fcad23
 *
Packit fcad23
 * Test line process helper functions
Packit fcad23
 *
Packit fcad23
 */
Packit fcad23
/**
Packit fcad23
 * @internal
Packit fcad23
 * process token value index line
Packit fcad23
 */
Packit fcad23
static int
Packit fcad23
_process_line_tvi(netsnmp_line_info *line_info, void *mem,
Packit fcad23
                  struct netsnmp_line_process_info_s* lpi)
Packit fcad23
{
Packit fcad23
    netsnmp_token_value_index *tvi = (netsnmp_token_value_index *)mem;
Packit fcad23
    char                      *ptr;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * get token
Packit fcad23
     */
Packit fcad23
    ptr = skip_not_white(line_info->start);
Packit fcad23
    if (NULL == ptr) {
Packit fcad23
        DEBUGMSGTL(("text:util:tvi", "no value after token '%s'\n",
Packit fcad23
                    line_info->start));
Packit fcad23
        return PMLP_RC_MEMORY_UNUSED;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * null terminate, search for value;
Packit fcad23
     */
Packit fcad23
    *(ptr++) = 0;
Packit fcad23
    ptr = skip_white(ptr);
Packit fcad23
    if (NULL == ptr) {
Packit fcad23
        DEBUGMSGTL(("text:util:tvi", "no value after token '%s'\n",
Packit fcad23
                    line_info->start));
Packit fcad23
        return PMLP_RC_MEMORY_UNUSED;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * get value
Packit fcad23
     */
Packit fcad23
    switch((int)(intptr_t)lpi->user_context) {
Packit fcad23
Packit fcad23
        case PMLP_TYPE_UNSIGNED:
Packit fcad23
            tvi->value.ul = strtoul(ptr, NULL, 0);
Packit fcad23
            if ((errno == ERANGE) && (ULONG_MAX == tvi->value.ul))
Packit fcad23
                snmp_log(LOG_WARNING,"value overflow\n");
Packit fcad23
            break;
Packit fcad23
Packit fcad23
Packit fcad23
        case PMLP_TYPE_INTEGER:
Packit fcad23
            tvi->value.sl = strtol(ptr, NULL, 0);
Packit fcad23
            if ((errno == ERANGE) &&
Packit fcad23
                ((LONG_MAX == tvi->value.sl) ||
Packit fcad23
                 (LONG_MIN == tvi->value.sl)))
Packit fcad23
                snmp_log(LOG_WARNING,"value over/under-flow\n");
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case PMLP_TYPE_STRING:
Packit fcad23
            tvi->value.cp = strdup(ptr);
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        case PMLP_TYPE_BOOLEAN:
Packit fcad23
            if (isdigit((unsigned char)(*ptr)))
Packit fcad23
                tvi->value.ul = strtoul(ptr, NULL, 0);
Packit fcad23
            else if (strcasecmp(ptr,"true") == 0)
Packit fcad23
                tvi->value.ul = 1;
Packit fcad23
            else if (strcasecmp(ptr,"false") == 0)
Packit fcad23
                tvi->value.ul = 0;
Packit fcad23
            else {
Packit fcad23
                snmp_log(LOG_WARNING,"bad value for boolean\n");
Packit fcad23
                return PMLP_RC_MEMORY_UNUSED;
Packit fcad23
            }
Packit fcad23
            break;
Packit fcad23
Packit fcad23
        default:
Packit fcad23
            snmp_log(LOG_ERR,"unsupported value type %d\n",
Packit fcad23
                     (int)(intptr_t)lpi->user_context);
Packit fcad23
            break;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    /*
Packit fcad23
     * save token and value
Packit fcad23
     */
Packit fcad23
    tvi->token = strdup(line_info->start);
Packit fcad23
    tvi->index = line_info->index;
Packit fcad23
Packit fcad23
    return PMLP_RC_MEMORY_USED;
Packit fcad23
}
Packit fcad23
Packit fcad23
#else  /* ! NETSNMP_FEATURE_REMOVE_TEXT_UTILS */
Packit fcad23
netsnmp_feature_unused(text_utils);
Packit fcad23
#endif /* ! NETSNMP_FEATURE_REMOVE_TEXT_UTILS */