Mercurial > flash_v2
diff packages/net/snmp/lib/current/src/read_config.c @ 103:95f3e12a6327 ecos-sw-2000-06-23
Merge from eCos master repository on 2000-06-23-16:41:10-BST
| author | jlarmour |
|---|---|
| date | Fri, 23 Jun 2000 17:06:31 +0000 |
| parents | |
| children | e0c0827131d1 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/net/snmp/lib/current/src/read_config.c @@ -0,0 +1,1116 @@ +//========================================================================== +// +// ./lib/current/src/read_config.c +// +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//####UCDSNMPCOPYRIGHTBEGIN#### +// +// ------------------------------------------- +// +// Portions of this software may have been derived from the UCD-SNMP +// project, <http://ucd-snmp.ucdavis.edu/> from the University of +// California at Davis, which was originally based on the Carnegie Mellon +// University SNMP implementation. Portions of this software are therefore +// covered by the appropriate copyright disclaimers included herein. +// +// The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2" +// ------------------------------------------- +// +//####UCDSNMPCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): hmt +// Contributors: hmt +// Date: 2000-05-30 +// Purpose: Port of UCD-SNMP distribution to eCos. +// Description: +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== +/******************************************************************** + Copyright 1989, 1991, 1992 by Carnegie Mellon University + + Derivative Work - +Copyright 1996, 1998, 1999, 2000 The Regents of the University of California + + All Rights Reserved + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appears in all copies and +that both that copyright notice and this permission notice appear in +supporting documentation, and that the name of CMU and The Regents of +the University of California not be used in advertising or publicity +pertaining to distribution of the software without specific written +permission. + +CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CMU OR +THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*********************************************************************/ +/* + * read_config.c + */ + +#include <config.h> + +#include <stdio.h> +#include <ctype.h> +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <sys/types.h> +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#if TIME_WITH_SYS_TIME +# ifdef WIN32 +# include <sys/timeb.h> +# else +# include <sys/time.h> +# endif +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#if HAVE_WINSOCK_H +#include <winsock.h> +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if HAVE_NETDB_H +#include <netdb.h> +#endif +#include <errno.h> + +#if HAVE_DMALLOC_H +#include <dmalloc.h> +#endif + +#include "asn1.h" +#include "mib.h" +#include "parse.h" +#include "system.h" +#include "snmp_api.h" +#include "snmp_debug.h" +#include "snmp_logging.h" +#include "snmp_impl.h" +#include "default_store.h" +#include "callback.h" + +#include "read_config.h" +#include "tools.h" + +int config_errors; + +struct config_files *config_files = NULL; + +struct config_line * +register_premib_handler(const char *type, + const char *token, + void (*parser) (const char *, char *), + void (*releaser) (void), + const char *help) +{ + struct config_line *ltmp; + ltmp = register_config_handler(type, token, parser, releaser, help); + if (ltmp != NULL) + ltmp->config_time = PREMIB_CONFIG; + return (ltmp); +} + +struct config_line * +register_app_premib_handler(const char *token, + void (*parser) (const char *, char *), + void (*releaser) (void), + const char *help) +{ + return(register_premib_handler( NULL, token, parser, releaser, help )); +} + +/*******************************************************************-o-****** + * register_config_handler + * + * Parameters: + * *type + * *token + * *parser + * *releaser + * + * Returns: + * Pointer to a new config line entry -OR- NULL on error. + */ +struct config_line * +register_config_handler(const char *type_param, + const char *token, + void (*parser) (const char *, char *), + void (*releaser) (void), + const char *help) +{ + struct config_files **ctmp = &config_files; + struct config_line **ltmp; + const char *type = type_param; + + if ( type == NULL ) + type = ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE); + + /* + * Find type in current list -OR- create a new file type. + */ + while (*ctmp != NULL && strcmp((*ctmp)->fileHeader, type)) { + ctmp = &((*ctmp)->next); + } + + if (*ctmp == NULL) { + *ctmp = (struct config_files *) + malloc(sizeof(struct config_files)); + if ( !*ctmp ) { + return NULL; + } + + (*ctmp)->next = NULL; + (*ctmp)->start = NULL; + (*ctmp)->fileHeader = strdup(type); + } + + /* + * Find parser type in current list -OR- create a new + * line parser entry. + */ + ltmp = &((*ctmp)->start); + + while (*ltmp != NULL && strcmp((*ltmp)->config_token, token)) { + ltmp = &((*ltmp)->next); + } + + if (*ltmp == NULL) { + *ltmp = (struct config_line *) + malloc(sizeof(struct config_line)); + if ( !*ltmp ) { + return NULL; + } + + (*ltmp)->next = NULL; + (*ltmp)->config_time = NORMAL_CONFIG; + (*ltmp)->parse_line = 0; + (*ltmp)->free_func = 0; + (*ltmp)->config_token = strdup(token); + if (help != NULL) + (*ltmp)->help = strdup(help); + + } + + /* + * Add/Replace the parse/free functions for the given line type + * in the given file type. + */ + (*ltmp)->parse_line = parser; + (*ltmp)->free_func = releaser; + + return (*ltmp); + +} /* end register_config_handler() */ + +struct config_line * +register_app_config_handler(const char *token, + void (*parser) (const char *, char *), + void (*releaser) (void), + const char *help) +{ + return(register_config_handler( NULL, token, parser, releaser, help )); +} + +void +unregister_config_handler(const char *type_param, + const char *token) +{ + struct config_files **ctmp = &config_files; + struct config_line **ltmp, *ltmp2; + const char *type = type_param; + + if ( type == NULL ) + type = ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE); + + /* find type in current list */ + while (*ctmp != NULL && strcmp((*ctmp)->fileHeader,type)) { + ctmp = &((*ctmp)->next); + } + + if (*ctmp == NULL) { + /* Not found, return. */ + return; + } + + ltmp = &((*ctmp)->start); + if (*ltmp == NULL) { + /* Not found, return. */ + return; + } + if (strcmp((*ltmp)->config_token,token) == 0) { + /* found it at the top of the list */ + (*ctmp)->start = (*ltmp)->next; + free((*ltmp)->config_token); + SNMP_FREE((*ltmp)->help); + free(*ltmp); + return; + } + while ((*ltmp)->next != NULL && strcmp((*ltmp)->next->config_token,token)) { + ltmp = &((*ltmp)->next); + } + if (*ltmp == NULL) { + free((*ltmp)->config_token); + SNMP_FREE((*ltmp)->help); + ltmp2 = (*ltmp)->next->next; + free((*ltmp)->next); + (*ltmp)->next = ltmp2; + } +} + +void +unregister_app_config_handler(const char *token) +{ + unregister_config_handler( NULL, token ); +} + +#ifdef TESTING +void print_config_handlers (void) +{ + struct config_files *ctmp = config_files; + struct config_line *ltmp; + + for(;ctmp != NULL; ctmp = ctmp->next) { + DEBUGMSGTL(("read_config", "read_conf: %s\n", ctmp->fileHeader)); + for(ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) + DEBUGMSGTL(("read_config", " %s\n", ltmp->config_token)); + } +} +#endif + +int linecount; +const char *curfilename; + +void read_config_with_type(const char *filename, + const char *type) +{ + struct config_files *ctmp = config_files; + for(;ctmp != NULL && strcmp(ctmp->fileHeader,type); ctmp = ctmp->next); + if (ctmp) + read_config(filename, ctmp->start, EITHER_CONFIG); + else + DEBUGMSGTL(("read_config", "read_config: I have no registrations for type:%s,file:%s\n", + type, filename)); +} + +/*******************************************************************-o-****** + * read_config + * + * Parameters: + * *filename + * *line_handler + * when + * + * Read <filename> and process each line in accordance with the list of + * <line_handler> functions. + * + * + * For each line in <filename>, search the list of <line_handler>'s + * for an entry that matches the first token on the line. This comparison is + * case insensitive. + * + * For each match, check that <when> is the designated time for the + * <line_handler> function to be executed before processing the line. + */ +void read_config(const char *filename, + struct config_line *line_handler, + int when) +{ + + FILE *ifile; + char line[STRINGMAX], token[STRINGMAX], tmpbuf[STRINGMAX]; + char *cptr; + int i, done; + struct config_line *lptr; + + linecount = 0; + curfilename = filename; + + if ((ifile = fopen(filename, "r")) == NULL) { +#ifdef ENOENT + if (errno == ENOENT) { + DEBUGMSGTL(("read_config", "%s: %s\n", filename, strerror(errno))); + } else +#endif /* ENOENT */ +#ifdef EACCES + if (errno == EACCES) { + DEBUGMSGTL(("read_config", "%s: %s\n", filename, strerror(errno))); + } else +#endif /* EACCES */ +#if defined(ENOENT) || defined(EACCES) + { + snmp_log_perror(filename); + } +#else /* defined(ENOENT) || defined(EACCES) */ + snmp_log_perror(filename); +#endif /* ENOENT */ + return; + } else { + DEBUGMSGTL(("read_config", "Reading configuration %s\n", filename)); + } + + while (fgets(line, sizeof(line), ifile) != NULL) + { + lptr = line_handler; + linecount++; + cptr = line; + i = strlen(line)-1; + if (line[i] == '\n') + line[i] = 0; + /* check blank line or # comment */ + if ((cptr = skip_white(cptr))) + { + cptr = copy_word(cptr,token); + if (cptr == NULL) { + sprintf(tmpbuf,"Blank line following %s token.", token); + config_perror(tmpbuf); + } else { + for(lptr = line_handler, done=0; + lptr != NULL && !done; + lptr = lptr->next) { + if (!strcasecmp(token,lptr->config_token)) { + if (when == EITHER_CONFIG || lptr->config_time == when) { + DEBUGMSGTL(("read_config", "%s:%d Parsing: %s\n", + filename, linecount, line)); + (*(lptr->parse_line))(token,cptr); + } + done = 1; + } + } + if (!done && when != PREMIB_CONFIG && + !ds_get_boolean(DS_LIBRARY_ID, DS_LIB_NO_TOKEN_WARNINGS)) { + sprintf(tmpbuf,"Unknown token: %s.", token); + config_pwarn(tmpbuf); + } + } + } + } + fclose(ifile); + return; + +} /* end read_config() */ + + + +void +free_config (void) +{ + struct config_files *ctmp = config_files; + struct config_line *ltmp; + + for(;ctmp != NULL; ctmp = ctmp->next) + for(ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) + if (ltmp->free_func) + (*(ltmp->free_func))(); +} + +void +read_configs (void) +{ + + char *optional_config = ds_get_string(DS_LIBRARY_ID, DS_LIB_OPTIONALCONFIG); + char *type = ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE); + + DEBUGMSGTL(("read_config","reading normal configuration tokens\n")); + + if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DONT_READ_CONFIGS)) + read_config_files(NORMAL_CONFIG); + + /* do this even when the normal above wasn't done */ + if (optional_config && type) + read_config_with_type(optional_config, type); + + snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG, + NULL); +} + +void +read_premib_configs (void) +{ + DEBUGMSGTL(("read_config","reading premib configuration tokens\n")); + + if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DONT_READ_CONFIGS)) + read_config_files(PREMIB_CONFIG); + + snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, + SNMP_CALLBACK_POST_PREMIB_READ_CONFIG, + NULL); +} + + + + +/*******************************************************************-o-****** + * read_config_files + * + * Parameters: + * when == PREMIB_CONFIG, NORMAL_CONFIG -or- EITHER_CONFIG + * + * + * Traverse the list of config file types, performing the following actions + * for each -- + * + * First, build a search path for config files. If the contents of + * environment variable SNMPCONFPATH are NULL, then use the following + * path list (where the last entry exists only if HOME is non-null): + * + * SNMPSHAREPATH:SNMPLIBPATH:${HOME}/.snmp + * + * Then, In each of these directories, read config files by the name of: + * + * <dir>/<fileHeader>.conf -AND- + * <dir>/<fileHeader>.local.conf + * + * where <fileHeader> is taken from the config file type structure. + * + * + * PREMIB_CONFIG causes free_config() to be invoked prior to any other action. + * + * + * EXITs if any 'config_errors' are logged while parsing config file lines. + */ +void +read_config_files (int when) +{ +#ifndef ECOSFIXME_NEEDFILESYSTEM + + int i, j; + char configfile[300]; + char *envconfpath, *homepath; + char *cptr1, *cptr2; + char defaultPath[SPRINT_MAX_LEN]; + + struct config_files *ctmp = config_files; + struct config_line *ltmp; + struct stat statbuf; + + if (when == PREMIB_CONFIG) + free_config(); + + /* read all config file types */ + for(;ctmp != NULL; ctmp = ctmp->next) { + + ltmp = ctmp->start; + + /* read the config files */ + if ((envconfpath = getenv("SNMPCONFPATH")) == NULL) { + homepath=getenv("HOME"); + sprintf(defaultPath,"%s%c%s%c%s%s%s%s%c%s", + SNMPCONFPATH, ENV_SEPARATOR_CHAR, + SNMPSHAREPATH, ENV_SEPARATOR_CHAR, SNMPLIBPATH, + ((homepath == NULL) ? "" : ENV_SEPARATOR), + ((homepath == NULL) ? "" : homepath), + ((homepath == NULL) ? "" : "/.snmp"), + ENV_SEPARATOR_CHAR, PERSISTENT_DIRECTORY); + envconfpath = defaultPath; + } + envconfpath = strdup(envconfpath); /* prevent actually writing in env */ + DEBUGMSGTL(("read_config","config path used:%s\n", envconfpath)); + cptr1 = cptr2 = envconfpath; + i = 1; + while (i && *cptr2 != 0) { + while(*cptr1 != 0 && *cptr1 != ENV_SEPARATOR_CHAR) + cptr1++; + if (*cptr1 == 0) + i = 0; + else + *cptr1 = 0; + /* + * for proper persistent storage retrival, we need to read old backup + * copies of the previous storage files. If the application in + * question has died without the proper call to snmp_clean_persistent, + * then we read all the configuration files we can, starting with + * the oldest first. + */ + if (strncmp(cptr2, PERSISTENT_DIRECTORY, + strlen(PERSISTENT_DIRECTORY)) == 0 || + (getenv("SNMP_PERSISTENT_FILE") != NULL && + strncmp(cptr2, getenv("SNMP_PERSISTENT_FILE"), + strlen(getenv("SNMP_PERSISTENT_FILE"))) == 0)) { + /* limit this to the known storage directory only */ + for(j=0; j <= MAX_PERSISTENT_BACKUPS; j++) { + sprintf(configfile,"%s/%s.%d.conf",cptr2, ctmp->fileHeader, j); + if (stat(configfile, &statbuf) != 0) { + /* file not there, continue */ + break; + } else { + /* backup exists, read it */ + DEBUGMSGTL(("read_config_files","old config file found: %s, parsing\n", configfile)); + read_config (configfile, ltmp, when); + } + } + } + sprintf(configfile,"%s/%s.conf",cptr2, ctmp->fileHeader); + read_config (configfile, ltmp, when); + sprintf(configfile,"%s/%s.local.conf",cptr2, ctmp->fileHeader); + read_config (configfile, ltmp, when); + cptr2 = ++cptr1; + } + free(envconfpath); + } + + if (config_errors) { + snmp_log(LOG_ERR, "ucd-snmp: %d errors in config file\n", config_errors); +/* exit(1); */ + } +#endif +} + +void read_config_print_usage(const char *lead) +{ + struct config_files *ctmp = config_files; + struct config_line *ltmp; + + if (lead == NULL) + lead = ""; + + for(ctmp = config_files; ctmp != NULL; ctmp = ctmp->next) { + snmp_log(LOG_INFO, "%sIn %s.conf and %s.local.conf:\n", lead, ctmp->fileHeader, + ctmp->fileHeader); + for(ltmp = ctmp->start; ltmp != NULL; ltmp = ltmp->next) { + if (ltmp->help != NULL) + snmp_log(LOG_INFO, "%s%s%-15s %s\n", lead, lead, ltmp->config_token, + ltmp->help); + } + } +} + +/*******************************************************************-o-****** + * read_config_store + * + * Parameters: + * *type + * *line + * + * + * Append line to a file named either ENV(SNMP_PERSISTENT_FILE) or + * "<PERSISTENT_DIRECTORY>/<type>.conf". + * Add a trailing newline to the stored file if necessary. + * + * Intended for use by applications to store permenant configuration + * information generated by sets or persistent counters. + * + */ +void +read_config_store(const char *type, const char *line) +{ +#ifdef PERSISTENT_DIRECTORY + char file[512], *filep; + FILE *fout; +#ifdef PERSISTENT_MASK + mode_t oldmask; +#endif + + /* store configuration directives in the following order of preference: + 1. ENV variable SNMP_PERSISTENT_FILE + 2. configured <PERSISTENT_DIRECTORY>/<type>.conf + */ + if ((filep = getenv("SNMP_PERSISTENT_FILE")) == NULL) { + sprintf(file,"%s/%s.conf",PERSISTENT_DIRECTORY,type); + filep = file; + } + +#ifdef PERSISTENT_MASK + oldmask = umask(PERSISTENT_MASK); +#endif + if (mkdirhier(filep, AGENT_DIRECTORY_MODE, 1)) { + snmp_log(LOG_ERR, "Failed to create the persistent directory for %s\n", + file); + } + if ((fout = fopen(filep, "a")) != NULL) { + fprintf(fout,line); + if (line[strlen(line)] != '\n') + fprintf(fout,"\n"); + DEBUGMSGTL(("read_config","storing: %s\n",line)); + fclose(fout); + } else { + DEBUGMSGTL(("read_config","open failure")); + } +#ifdef PERSISTENT_MASK + umask(oldmask); +#endif + +#endif +} /* end read_config_store() */ + +void +read_app_config_store(const char *line) +{ + read_config_store(ds_get_string(DS_LIBRARY_ID, DS_LIB_APPTYPE), line); +} + + + + +/*******************************************************************-o-****** + * snmp_save_persistent + * + * Parameters: + * *type + * + * + * Save the file "<PERSISTENT_DIRECTORY>/<type>.conf" into a backup copy + * called "<PERSISTENT_DIRECTORY>/<type>.%d.conf", which %d is an + * incrementing number on each call, but less than MAX_PERSISTENT_BACKUPS. + * + * Should be called just before all persistent information is supposed to be + * written to move aside the existing persistent cache. + * snmp_clean_persistent should then be called afterward all data has been + * saved to remove these backup files. + * + * Note: on an rename error, the files are removed rather than saved. + * + */ +void +snmp_save_persistent(const char *type) +{ +#ifndef ECOSFIXME_NEEDFILESYSTEM + + char file[512], fileold[512]; + struct stat statbuf; + int j; + + DEBUGMSGTL(("snmp_save_persistent","saving %s files...\n", type)); + sprintf(file,"%s/%s.conf", PERSISTENT_DIRECTORY, type); + if (stat(file, &statbuf) == 0) { + for(j=0; j <= MAX_PERSISTENT_BACKUPS; j++) { + sprintf(fileold,"%s/%s.%d.conf", PERSISTENT_DIRECTORY, type, j); + if (stat(fileold, &statbuf) != 0) { + DEBUGMSGTL(("snmp_save_persistent"," saving old config file: %s -> %s.\n", file, fileold)); + if (rename(file, fileold)) { + unlink(file);/* moving it failed, try nuking it, as leaving + it around is very bad. */ + } + break; + } + } + } +#endif +} + + +/*******************************************************************-o-****** + * snmp_clean_persistent + * + * Parameters: + * *type + * + * + * Unlink all backup files called "<PERSISTENT_DIRECTORY>/<type>.%d.conf". + * + * Should be called just after we successfull dumped the last of the + * persistent data, to remove the backup copies of previous storage dumps. + * + * XXX Worth overwriting with random bytes first? This would + * ensure that the data is destroyed, even a buffer containing the + * data persists in memory or swap. Only important if secrets + * will be stored here. + */ +void +snmp_clean_persistent(const char *type) +{ +#ifndef ECOSFIXME_NEEDFILESYSTEM + + char file[512]; + struct stat statbuf; + int j; + + DEBUGMSGTL(("snmp_clean_persistent","cleaning %s files...\n", type)); + sprintf(file,"%s/%s.conf",PERSISTENT_DIRECTORY,type); + if (stat(file, &statbuf) == 0) { + for(j=0; j <= MAX_PERSISTENT_BACKUPS; j++) { + sprintf(file,"%s/%s.%d.conf", PERSISTENT_DIRECTORY, type, j); + if (stat(file, &statbuf) == 0) { + DEBUGMSGTL(("snmp_clean_persistent"," removing old config file: %s\n", file)); + unlink(file); + } + } + } +#endif +} + + + + +/* config_perror: prints a warning string associated with a file and + line number of a .conf file and increments the error count. */ +void config_perror(const char *string) +{ + config_pwarn(string); + config_errors++; +} + +void config_pwarn(const char *string) +{ + snmp_log(LOG_WARNING, "%s: line %d: %s\n", curfilename, linecount, string); +} + +/* skip all white spaces and return 1 if found something either end of + line or a comment character */ +char *skip_white(char *ptr) +{ + + if (ptr == NULL) return (NULL); + while (*ptr != 0 && isspace(*ptr)) ptr++; + if (*ptr == 0 || *ptr == '#') return (NULL); + return (ptr); +} + +char *skip_not_white(char *ptr) +{ + + if (ptr == NULL) return (NULL); + while (*ptr != 0 && !isspace(*ptr)) ptr++; + if (*ptr == 0 || *ptr == '#') return (NULL); + return (ptr); +} + +char *skip_token(char *ptr) +{ + ptr = skip_white(ptr); + ptr = skip_not_white(ptr); + ptr = skip_white(ptr); + return (ptr); +} + +/* copy_word + copies the next 'token' from 'from' into 'to'. + currently a token is anything seperate by white space + or within quotes (double or single) (i.e. "the red rose" + is one token, \"the red rose\" is three tokens) + a '\' character will allow a quote character to be treated + as a regular character + It returns a pointer to first non-white space after the end of the token + being copied or to 0 if we reach the end.*/ + +char *copy_word(char *from, char *to) +{ + char quote; + if ( (*from == '\"') || (*from =='\'') ){ + quote = *(from++); + while ( (*from != quote) && (*from != 0) ) { + if ((*from == '\\') && (*(from+1) != 0)) { + *to++ = *(from+1); + from = from +2; + } + else *to++ = *from++; + } + if (*from == 0) { + DEBUGMSGTL(("read_config_copy_word", + "no end quote found in config string\n")); + } else from++; + } + else { + while (*from != 0 && !isspace(*from)) { + if ((*from == '\\') && (*(from+1) != 0)) { + *to++ = *(from+1); + from = from +2; + } + else *to++ = *from++; + } + } + *to = 0; + from = skip_white(from); + return(from); +} /* copy_word */ + +/* read_config_save_octet_string(): saves an octet string as a length + followed by a string of hex */ +char *read_config_save_octet_string(char *saveto, u_char *str, size_t len) { + int i; + if (str != NULL) { + sprintf(saveto, "0x"); + saveto += 2; + for(i = 0; i < (int)len; i++) { + sprintf(saveto,"%02x", str[i]); + saveto = saveto + 2; + } + return saveto; + } else { + sprintf(saveto,"\"\""); + saveto += 2; + } + return saveto; +} + +/* read_config_read_octet_string(): reads an octet string that was + saved by the read_config_save_octet_string() function */ +char *read_config_read_octet_string(char *readfrom, u_char **str, size_t *len) { + u_char *cptr=NULL; + char *cptr1; + u_int tmp; + int i; + + if (readfrom == NULL || str == NULL) + return NULL; + + if (strncasecmp(readfrom,"0x",2) == 0) { + /* A hex string submitted. How long? */ + readfrom += 2; + cptr1 = skip_not_white(readfrom); + if (cptr1) + *len = (cptr1 - readfrom); + else + *len = strlen(readfrom); + + if (*len % 2) { + DEBUGMSGTL(("read_config_read_octet_string","invalid hex string: wrong length")); + return NULL; + } + *len = *len / 2; + + /* malloc data space if needed */ + if (*str == NULL) { + if (*len == 0) { + /* null length string found */ + cptr = NULL; + + } else if (*len > 0 && (str == NULL || (cptr = (u_char *)malloc(*len)) == NULL)) { + return NULL; + } + *str = cptr; + } else { + cptr = *str; + } + + /* copy data */ + for(i = 0; i < (int)*len; i++) { + sscanf(readfrom,"%2x",&tmp); + *cptr++ = (u_char) tmp; + readfrom += 2; + } + readfrom = skip_white(readfrom); + } else { + /* Normal string */ + + /* malloc data space if needed */ + if (*str == NULL) { + char buf[SNMP_MAXBUF]; + readfrom = copy_word(readfrom, buf); + + *len = strlen(buf); + /* malloc an extra space to add a null */ + if (*len > 0 && (str == NULL || + (cptr = (u_char *) malloc(*len + 1)) + == NULL)) + return NULL; + *str = cptr; + if (cptr) + memcpy(cptr, buf, (*len+1)); + } else { + readfrom = copy_word(readfrom, (char *)*str); + } + } + + return readfrom; +} + + +/* read_config_save_objid(): saves an objid as a numerical string */ +char *read_config_save_objid(char *saveto, oid *objid, size_t len) { + int i; + + if (len == 0) { + strcat(saveto, "NULL"); + saveto += strlen(saveto); + return saveto; + } + + /* in case len=0, this makes it easier to read it back in */ + for(i=0; i < (int)len; i++) { + sprintf(saveto,".%ld", objid[i]); + saveto += strlen(saveto); + } + return saveto; +} + +/* read_config_read_objid(): reads an objid from a format saved by the above */ +char *read_config_read_objid(char *readfrom, oid **objid, size_t *len) { + + if (objid == NULL || readfrom == NULL) + return NULL; + + if (*objid != NULL) { + char buf[SPRINT_MAX_LEN]; + + if (strncmp(readfrom,"NULL",4) == 0) { + /* null length oid */ + *len = 0; + } else { + /* read_objid is touchy with trailing stuff */ + copy_word(readfrom, buf); + + /* read the oid into the buffer passed to us */ + if (!read_objid(buf, *objid, len)) { + DEBUGMSGTL(("read_config_read_objid","Invalid OID")); + return NULL; + } + } + + readfrom = skip_token(readfrom); + } else { + if (strncmp(readfrom,"NULL",4) == 0) { + /* null length oid */ + *len = 0; + readfrom = skip_token(readfrom); + } else { + /* space needs to be malloced. Call ourself recursively to figure + out how long the oid actually is */ + oid obuf[MAX_OID_LEN]; + size_t obuflen = MAX_OID_LEN; + oid *oidp = obuf; + oid **oidpp = &oidp; /* done this way for odd, untrue, gcc warnings */ + + readfrom = read_config_read_objid(readfrom, oidpp, &obuflen); + + /* Then malloc and copy the results */ + *len = obuflen; + if (*len > 0 && (*objid = (oid*)malloc(*len * sizeof(oid))) == NULL) + return NULL; + + if (obuflen > 0) + memcpy(*objid, obuf, obuflen*sizeof(oid)); + } + } + return readfrom; +} + +/* read_config_read_data(): + reads data of a given type from a token(s) on a configuration line. + + Returns: character pointer to the next token in the configuration line. + NULL if none left. + NULL if an unknown type. +*/ +char *read_config_read_data(int type, char *readfrom, void *dataptr, size_t *len) { + + int *intp; + char **charpp; + oid **oidpp; + + if (dataptr == NULL || readfrom == NULL) + return NULL; + + switch(type) { + case ASN_INTEGER: + intp = (int *) dataptr; + *intp = atoi(readfrom); + readfrom = skip_token(readfrom); + return readfrom; + + case ASN_OCTET_STR: + charpp = (char **) dataptr; + return read_config_read_octet_string(readfrom, (u_char **) charpp, len); + + case ASN_OBJECT_ID: + oidpp = (oid **) dataptr; + return read_config_read_objid(readfrom, oidpp, len); + + default: + DEBUGMSGTL(("read_config_read_data","Fail: Unknown type: %d", type)); + return NULL; + } + return NULL; +} + +/* read_config_read_data(): + reads data of a given type from a token(s) on a configuration line. + + Returns: character pointer to the next token in the configuration line. + NULL if none left. + NULL if an unknown type. +*/ +char *read_config_store_data(int type, char *storeto, void *dataptr, size_t *len) { + + int *intp; + u_char **charpp; + oid **oidpp; + + if (dataptr == NULL || storeto == NULL) + return NULL; + + switch(type) { + case ASN_INTEGER: + intp = (int *) dataptr; + sprintf(storeto," %d", *intp); + return (storeto + strlen(storeto)); + + case ASN_OCTET_STR: + charpp = (u_char **) dataptr; + return read_config_save_octet_string(storeto, *charpp, *len); + + case ASN_OBJECT_ID: + oidpp = (oid **) dataptr; + return read_config_save_objid(storeto, *oidpp, *len); + + default: + DEBUGMSGTL(("read_config_store_data","Fail: Unknown type: %d", type)); + return NULL; + } + return NULL; +}
