From: M. Sean Finney Date: Tue, 6 Feb 2007 19:33:55 +0000 (+0000) Subject: initial version of ini file parsing routines in C X-Git-Url: https://git.tokkee.org/?p=nagiosplug.git;a=commitdiff_plain;h=a70fb5becfef4479fc44c530658e5fcf2512d289 initial version of ini file parsing routines in C git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@1610 f882894a-f735-0410-b71e-b25c423dba1c --- diff --git a/lib/parse_ini.c b/lib/parse_ini.c new file mode 100644 index 0000000..5155b6d --- /dev/null +++ b/lib/parse_ini.c @@ -0,0 +1,247 @@ +#include "common.h" +#include "parse_ini.h" +#include "utils_base.h" +#include + +/* np_ini_info contains the result of parsing a "locator" in the format + * [stanza_name][@config_filename] (check_foo@/etc/foo.ini, for example) + */ +typedef struct { + char *file; + char *stanza; +} np_ini_info; + +/* eat all characters from a FILE pointer until n is encountered */ +#define GOBBLE_TO(f, c, n) do { (c)=fgetc((f)); } while((c)!=EOF && (c)!=(n)) + +/* internal function that returns the constructed defaults options */ +static char* read_defaults(FILE *f, const char *stanza); +/* internal function that converts a single line into options format */ +static int add_option(FILE *f, char **optbuf, size_t *bufsize); + +/* parse_locator decomposes a string of the form + * [stanza][@filename] + * into its seperate parts + */ +static void parse_locator(const char *locator, const char *def_stanza, np_ini_info *i){ + size_t locator_len, stanza_len; + + locator_len=strlen(locator); + stanza_len=strcspn(locator, "@"); + /* if a non-default stanza is provided */ + if(stanza_len>0){ + i->stanza=(char*)malloc(sizeof(char)*(stanza_len+1)); + strncpy(i->stanza, locator, stanza_len); + i->stanza[stanza_len]='\0'; + } else { /* otherwise we use the default stanza */ + i->stanza=strdup(def_stanza); + } + /* if there is no @file part */ + if(stanza_len==locator_len){ + i->file=strdup(NP_DEFAULT_INI_PATH); + } else { + i->file=strdup(&(locator[stanza_len+1])); + } + + if(i->file==NULL || i->stanza==NULL){ + die(STATE_UNKNOWN, _("malloc() failed!\n")); + } +} + +/* this is the externally visible function used by plugins */ +char* np_get_defaults(const char *locator, const char *default_section){ + FILE *inifile=NULL; + char *defaults=NULL; + np_ini_info i; + + parse_locator(locator, default_section, &i); + /* if a file was specified or if we're using the default file */ + if(i.file != NULL && strlen(i.file) > 0){ + if(strcmp(i.file, "-")==0){ + inifile=stdout; + } else { + inifile=fopen(i.file, "r"); + } + if(inifile==NULL) die(STATE_UNKNOWN, _("Config file error")); + defaults=read_defaults(inifile, i.stanza); + free(i.file); + if(inifile!=stdout) fclose(inifile); + } + free(i.stanza); + return defaults; +} + +/* read_defaults is where the meat of the parsing takes place. + * + * note that this may be called by a setuid binary, so we need to + * be extra careful about user-supplied input (i.e. avoiding possible + * format string vulnerabilities, etc) + */ +static char* read_defaults(FILE *f, const char *stanza){ + int c; + char *opts=NULL; + size_t i, stanza_len, opts_buf_size=0; + enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate=NOSTANZA; + + stanza_len=strlen(stanza); + + /* our little stanza-parsing state machine. */ + while((c=fgetc(f))!=EOF){ + /* gobble up leading whitespace */ + if(isspace(c)) continue; + switch(c){ + /* globble up coment lines */ + case '#': + GOBBLE_TO(f, c, '\n'); + break; + /* start of a stanza. check to see if it matches */ + case '[': + stanzastate=WRONGSTANZA; + for(i=0; i= linebuf_sz){ + linebuf_sz=(linebuf_sz>0)?linebuf_sz<<1:read_sz; + linebuf=realloc(linebuf, linebuf_sz); + if(linebuf==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n")); + } + if(fgets(&linebuf[read_pos], read_sz, f)==NULL) done_reading=1; + else { + read_pos=strlen(linebuf); + if(linebuf[read_pos-1]=='\n') { + linebuf[--read_pos]='\0'; + done_reading=1; + } + } + } + lineend=&linebuf[read_pos]; + /* all that to read one line. isn't C fun? :) now comes the parsing :/ */ + + /* skip leading whitespace */ + for(optptr=linebuf; optptr= bs){ + bs=(bs>0)?(bs+cfg_len+2)<<1:cfg_len+1; + newbuf=realloc(newbuf, bs); + if(newbuf==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n")); + } + if(read_pos>0) newbuf[read_pos++]=' '; + strncpy(&newbuf[read_pos], "--", 2); read_pos+=2; + strncpy(&newbuf[read_pos], optptr, opt_len); read_pos+=opt_len; + if(equals) newbuf[read_pos++]='='; + if(value) { + strncpy(&newbuf[read_pos], valptr, val_len); read_pos+=val_len; + } + newbuf[read_pos]='\0'; + + *optbuf=newbuf; + *bufsize=bs; + + free(linebuf); + return 0; +} + +int main(){ + char *optstr=NULL; + optstr=np_get_defaults("check_foo@./foo.ini", "check_bar"); + if(optstr!=NULL) { + printf("optstr:\n\t%s\n", optstr); + free(optstr); + } + return 0; +} diff --git a/lib/parse_ini.h b/lib/parse_ini.h new file mode 100644 index 0000000..1c28c7d --- /dev/null +++ b/lib/parse_ini.h @@ -0,0 +1,19 @@ +#ifndef _PARSE_INI_H_ +#define _PARSE_INI_H_ + +/* + * parse_ini.h: routines for loading nagios-plugin defaults from ini + * configuration files. + */ + +/* NP_DEFAULT_INI_PATH: compile-time default location for ini file */ +#ifndef NP_DEFAULT_INI_PATH +# define NP_DEFAULT_INI_PATH "/etc/nagios-plugins/plugins.ini" +#endif /* NP_DEFAULT_INI_PATH */ + +/* np_load_defaults: load the default configuration (if present) for + * a plugin from the ini file + */ +char* np_get_defaults(const char *locator, const char *default_section); + +#endif /* _PARSE_INI_H_ */