diff options
| -rw-r--r-- | lib/parse_ini.c | 76 | ||||
| -rw-r--r-- | lib/parse_ini.h | 9 | ||||
| -rw-r--r-- | lib/tests/test_ini.c | 25 | ||||
| -rwxr-xr-x | lib/tests/test_ini.t | 6 |
4 files changed, 74 insertions, 42 deletions
diff --git a/lib/parse_ini.c b/lib/parse_ini.c index ef56be95..c915d795 100644 --- a/lib/parse_ini.c +++ b/lib/parse_ini.c | |||
| @@ -42,9 +42,9 @@ typedef struct { | |||
| 42 | #define GOBBLE_TO(f, c, n) do { (c)=fgetc((f)); } while((c)!=EOF && (c)!=(n)) | 42 | #define GOBBLE_TO(f, c, n) do { (c)=fgetc((f)); } while((c)!=EOF && (c)!=(n)) |
| 43 | 43 | ||
| 44 | /* internal function that returns the constructed defaults options */ | 44 | /* internal function that returns the constructed defaults options */ |
| 45 | static char* read_defaults(FILE *f, const char *stanza); | 45 | static np_arg_list* read_defaults(FILE *f, const char *stanza); |
| 46 | /* internal function that converts a single line into options format */ | 46 | /* internal function that converts a single line into options format */ |
| 47 | static int add_option(FILE *f, char **optbuf, size_t *bufsize); | 47 | static int add_option(FILE *f, np_arg_list **optlst); |
| 48 | 48 | ||
| 49 | /* parse_locator decomposes a string of the form | 49 | /* parse_locator decomposes a string of the form |
| 50 | * [stanza][@filename] | 50 | * [stanza][@filename] |
| @@ -76,9 +76,9 @@ static void parse_locator(const char *locator, const char *def_stanza, np_ini_in | |||
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | /* this is the externally visible function used by plugins */ | 78 | /* this is the externally visible function used by plugins */ |
| 79 | char* np_get_defaults(const char *locator, const char *default_section){ | 79 | np_arg_list* np_get_defaults(const char *locator, const char *default_section){ |
| 80 | FILE *inifile=NULL; | 80 | FILE *inifile=NULL; |
| 81 | char *defaults=NULL; | 81 | np_arg_list *defaults=NULL; |
| 82 | np_ini_info i; | 82 | np_ini_info i; |
| 83 | 83 | ||
| 84 | parse_locator(locator, default_section, &i); | 84 | parse_locator(locator, default_section, &i); |
| @@ -104,10 +104,10 @@ char* np_get_defaults(const char *locator, const char *default_section){ | |||
| 104 | * be extra careful about user-supplied input (i.e. avoiding possible | 104 | * be extra careful about user-supplied input (i.e. avoiding possible |
| 105 | * format string vulnerabilities, etc) | 105 | * format string vulnerabilities, etc) |
| 106 | */ | 106 | */ |
| 107 | static char* read_defaults(FILE *f, const char *stanza){ | 107 | static np_arg_list* read_defaults(FILE *f, const char *stanza){ |
| 108 | int c; | 108 | int c; |
| 109 | char *opts=NULL; | 109 | np_arg_list *opts=NULL; |
| 110 | size_t i, stanza_len, opts_buf_size=0; | 110 | size_t i, stanza_len; |
| 111 | enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate=NOSTANZA; | 111 | enum { NOSTANZA, WRONGSTANZA, RIGHTSTANZA } stanzastate=NOSTANZA; |
| 112 | 112 | ||
| 113 | stanza_len=strlen(stanza); | 113 | stanza_len=strlen(stanza); |
| @@ -154,7 +154,7 @@ static char* read_defaults(FILE *f, const char *stanza){ | |||
| 154 | /* okay, this is where we start taking the config */ | 154 | /* okay, this is where we start taking the config */ |
| 155 | case RIGHTSTANZA: | 155 | case RIGHTSTANZA: |
| 156 | ungetc(c, f); | 156 | ungetc(c, f); |
| 157 | if(add_option(f, &opts, &opts_buf_size)){ | 157 | if(add_option(f, &opts)){ |
| 158 | die(STATE_UNKNOWN, _("Config file error")); | 158 | die(STATE_UNKNOWN, _("Config file error")); |
| 159 | } | 159 | } |
| 160 | break; | 160 | break; |
| @@ -170,15 +170,14 @@ static char* read_defaults(FILE *f, const char *stanza){ | |||
| 170 | * ^option[[:space:]]*(=[[:space:]]*value)? | 170 | * ^option[[:space:]]*(=[[:space:]]*value)? |
| 171 | * and creates it as a cmdline argument | 171 | * and creates it as a cmdline argument |
| 172 | * --option[=value] | 172 | * --option[=value] |
| 173 | * appending it to the string pointed to by optbuf (which will | 173 | * appending it to the linked list optbuf. |
| 174 | * be dynamically grown if needed) | ||
| 175 | */ | 174 | */ |
| 176 | static int add_option(FILE *f, char **optbuf, size_t *bufsize){ | 175 | static int add_option(FILE *f, np_arg_list **optlst){ |
| 177 | char *newbuf=*optbuf; | 176 | np_arg_list *opttmp=*optlst, *optnew; |
| 178 | char *linebuf=NULL, *lineend=NULL, *optptr=NULL, *optend=NULL; | 177 | char *linebuf=NULL, *lineend=NULL, *optptr=NULL, *optend=NULL; |
| 179 | char *eqptr=NULL, *valptr=NULL, *spaceptr=NULL, *valend=NULL; | 178 | char *eqptr=NULL, *valptr=NULL, *spaceptr=NULL, *valend=NULL; |
| 180 | short done_reading=0, equals=0, value=0; | 179 | short done_reading=0, equals=0, value=0; |
| 181 | size_t cfg_len=0, read_sz=8, linebuf_sz=0, read_pos=0, bs=*bufsize; | 180 | size_t cfg_len=0, read_sz=8, linebuf_sz=0, read_pos=0; |
| 182 | size_t opt_len=0, val_len=0; | 181 | size_t opt_len=0, val_len=0; |
| 183 | 182 | ||
| 184 | /* read one line from the file */ | 183 | /* read one line from the file */ |
| @@ -214,14 +213,13 @@ static int add_option(FILE *f, char **optbuf, size_t *bufsize){ | |||
| 214 | if(optptr==eqptr) die(STATE_UNKNOWN, _("Config file error\n")); | 213 | if(optptr==eqptr) die(STATE_UNKNOWN, _("Config file error\n")); |
| 215 | /* continue from '=' to start of value or EOL */ | 214 | /* continue from '=' to start of value or EOL */ |
| 216 | for(valptr=eqptr+1; valptr<lineend && isspace(*valptr); valptr++); | 215 | for(valptr=eqptr+1; valptr<lineend && isspace(*valptr); valptr++); |
| 217 | /* continue to the end of value, watching for trailing space/comments */ | 216 | /* continue to the end of value (FIXME: watching for trailing comments) */ |
| 218 | for(valend=valptr; valend<lineend; valend++){ | 217 | for(valend=valptr; valend<lineend; valend++) |
| 219 | if(isspace(*valend) && spaceptr==NULL) spaceptr=valend; | 218 | /* FIXME: N::P doesn't allow comments. Remove next line and parse_ini won't either */ |
| 220 | else if(*valend=='#') break; | 219 | if(*valend=='#') break; |
| 221 | else spaceptr=NULL; | ||
| 222 | } | ||
| 223 | if(spaceptr!=NULL) valend=spaceptr; | ||
| 224 | --valend; | 220 | --valend; |
| 221 | /* Finally trim off trailing spaces */ | ||
| 222 | for(valend; isspace(*valend); valend--); | ||
| 225 | /* calculate the length of "--foo" */ | 223 | /* calculate the length of "--foo" */ |
| 226 | opt_len=1+optend-optptr; | 224 | opt_len=1+optend-optptr; |
| 227 | cfg_len=2+(opt_len); | 225 | cfg_len=2+(opt_len); |
| @@ -237,27 +235,31 @@ static int add_option(FILE *f, char **optbuf, size_t *bufsize){ | |||
| 237 | cfg_len+=1; | 235 | cfg_len+=1; |
| 238 | } | 236 | } |
| 239 | 237 | ||
| 240 | /* okay, now we have all the info we need, so we grow the default opts | 238 | /* okay, now we have all the info we need, so we create a new np_arg_list |
| 241 | * buffer if it's necessary, and put everything together. | 239 | * element and set the argument... |
| 242 | * (+2 is for a potential space and a null byte) | ||
| 243 | */ | 240 | */ |
| 244 | read_pos=(newbuf==NULL)?0:strlen(newbuf); | 241 | optnew=(np_arg_list *)malloc(sizeof(np_arg_list)); |
| 245 | if(newbuf==NULL || read_pos+cfg_len+2 >= bs){ | 242 | optnew->next=NULL; |
| 246 | bs=(bs>0)?(bs+cfg_len+2)<<1:cfg_len+1; | 243 | |
| 247 | newbuf=realloc(newbuf, bs); | 244 | read_pos=0; |
| 248 | if(newbuf==NULL) die(STATE_UNKNOWN, _("malloc() failed!\n")); | 245 | optnew->arg=(char *)malloc(cfg_len+1); |
| 249 | } | 246 | strncpy(&optnew->arg[read_pos], "--", 2); read_pos+=2; |
| 250 | if(read_pos>0) newbuf[read_pos++]=' '; | 247 | strncpy(&optnew->arg[read_pos], optptr, opt_len); read_pos+=opt_len; |
| 251 | strncpy(&newbuf[read_pos], "--", 2); read_pos+=2; | 248 | if(equals) optnew->arg[read_pos++]='='; |
| 252 | strncpy(&newbuf[read_pos], optptr, opt_len); read_pos+=opt_len; | ||
| 253 | if(equals) newbuf[read_pos++]='='; | ||
| 254 | if(value) { | 249 | if(value) { |
| 255 | strncpy(&newbuf[read_pos], valptr, val_len); read_pos+=val_len; | 250 | strncpy(&optnew->arg[read_pos], valptr, val_len); read_pos+=val_len; |
| 256 | } | 251 | } |
| 257 | newbuf[read_pos]='\0'; | 252 | optnew->arg[read_pos]='\0'; |
| 258 | 253 | ||
| 259 | *optbuf=newbuf; | 254 | /* ...and put that to the end of the list */ |
| 260 | *bufsize=bs; | 255 | if (*optlst==NULL) { |
| 256 | *optlst=optnew; | ||
| 257 | } else { | ||
| 258 | while (opttmp->next!=NULL) { | ||
| 259 | opttmp=opttmp->next; | ||
| 260 | } | ||
| 261 | opttmp->next = optnew; | ||
| 262 | } | ||
| 261 | 263 | ||
| 262 | free(linebuf); | 264 | free(linebuf); |
| 263 | return 0; | 265 | return 0; |
diff --git a/lib/parse_ini.h b/lib/parse_ini.h index 1c28c7de..fea745c5 100644 --- a/lib/parse_ini.h +++ b/lib/parse_ini.h | |||
| @@ -6,6 +6,13 @@ | |||
| 6 | * configuration files. | 6 | * configuration files. |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | /* np_arg_list is a linked list of arguments passed between the ini | ||
| 10 | * parser and the argument parser to construct the final array */ | ||
| 11 | typedef struct np_arg_el { | ||
| 12 | char *arg; | ||
| 13 | struct np_arg_el *next; | ||
| 14 | } np_arg_list; | ||
| 15 | |||
| 9 | /* NP_DEFAULT_INI_PATH: compile-time default location for ini file */ | 16 | /* NP_DEFAULT_INI_PATH: compile-time default location for ini file */ |
| 10 | #ifndef NP_DEFAULT_INI_PATH | 17 | #ifndef NP_DEFAULT_INI_PATH |
| 11 | # define NP_DEFAULT_INI_PATH "/etc/nagios-plugins/plugins.ini" | 18 | # define NP_DEFAULT_INI_PATH "/etc/nagios-plugins/plugins.ini" |
| @@ -14,6 +21,6 @@ | |||
| 14 | /* np_load_defaults: load the default configuration (if present) for | 21 | /* np_load_defaults: load the default configuration (if present) for |
| 15 | * a plugin from the ini file | 22 | * a plugin from the ini file |
| 16 | */ | 23 | */ |
| 17 | char* np_get_defaults(const char *locator, const char *default_section); | 24 | np_arg_list* np_get_defaults(const char *locator, const char *default_section); |
| 18 | 25 | ||
| 19 | #endif /* _PARSE_INI_H_ */ | 26 | #endif /* _PARSE_INI_H_ */ |
diff --git a/lib/tests/test_ini.c b/lib/tests/test_ini.c index 302a2e56..b02d1452 100644 --- a/lib/tests/test_ini.c +++ b/lib/tests/test_ini.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | #include "common.h" | 20 | #include "common.h" |
| 21 | #include "parse_ini.h" | 21 | #include "parse_ini.h" |
| 22 | #include "utils_base.h" | ||
| 22 | 23 | ||
| 23 | #include "tap.h" | 24 | #include "tap.h" |
| 24 | 25 | ||
| @@ -29,6 +30,22 @@ void my_free(char *string) { | |||
| 29 | } | 30 | } |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 33 | char* | ||
| 34 | list2str(np_arg_list *optlst) | ||
| 35 | { | ||
| 36 | char *optstr=NULL; | ||
| 37 | |||
| 38 | /* Put everything as a space-separated string */ | ||
| 39 | while (optlst) { | ||
| 40 | asprintf(&optstr, "%s%s ", optstr?optstr:"", optlst->arg); | ||
| 41 | optlst=optlst->next; | ||
| 42 | } | ||
| 43 | /* Strip last whitespace */ | ||
| 44 | optstr[strlen(optstr)-1]='\0'; | ||
| 45 | |||
| 46 | return optstr; | ||
| 47 | } | ||
| 48 | |||
| 32 | int | 49 | int |
| 33 | main (int argc, char **argv) | 50 | main (int argc, char **argv) |
| 34 | { | 51 | { |
| @@ -36,11 +53,11 @@ main (int argc, char **argv) | |||
| 36 | 53 | ||
| 37 | plan_tests(4); | 54 | plan_tests(4); |
| 38 | 55 | ||
| 39 | optstr=np_get_defaults("section@./config-tiny.ini", "check_disk"); | 56 | optstr=list2str(np_get_defaults("section@./config-tiny.ini", "check_disk")); |
| 40 | ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank="), "config-tiny.ini's section as expected"); | 57 | ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank="), "config-tiny.ini's section as expected"); |
| 41 | my_free(optstr); | 58 | my_free(optstr); |
| 42 | 59 | ||
| 43 | optstr=np_get_defaults("@./config-tiny.ini", "section"); | 60 | optstr=list2str(np_get_defaults("@./config-tiny.ini", "section")); |
| 44 | ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank="), "Used default section name, without specific"); | 61 | ok( !strcmp(optstr, "--one=two --Foo=Bar --this=Your Mother! --blank="), "Used default section name, without specific"); |
| 45 | my_free(optstr); | 62 | my_free(optstr); |
| 46 | 63 | ||
| @@ -51,7 +68,7 @@ main (int argc, char **argv) | |||
| 51 | my_free(optstr); | 68 | my_free(optstr); |
| 52 | */ | 69 | */ |
| 53 | 70 | ||
| 54 | optstr=np_get_defaults("Section Two@./config-tiny.ini", "check_disk"); | 71 | optstr=list2str(np_get_defaults("Section Two@./config-tiny.ini", "check_disk")); |
| 55 | ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected"); | 72 | ok( !strcmp(optstr, "--something else=blah --remove=whitespace"), "config-tiny.ini's Section Two as expected"); |
| 56 | my_free(optstr); | 73 | my_free(optstr); |
| 57 | 74 | ||
| @@ -70,7 +87,7 @@ main (int argc, char **argv) | |||
| 70 | my_free(optstr); | 87 | my_free(optstr); |
| 71 | */ | 88 | */ |
| 72 | 89 | ||
| 73 | optstr=np_get_defaults("check_mysql@./plugin.ini", "check_disk"); | 90 | optstr=list2str(np_get_defaults("check_mysql@./plugin.ini", "check_disk")); |
| 74 | ok( !strcmp(optstr, "--username=operator --password=secret"), "plugin.ini's check_mysql as expected"); | 91 | ok( !strcmp(optstr, "--username=operator --password=secret"), "plugin.ini's check_mysql as expected"); |
| 75 | my_free(optstr); | 92 | my_free(optstr); |
| 76 | 93 | ||
diff --git a/lib/tests/test_ini.t b/lib/tests/test_ini.t new file mode 100755 index 00000000..b130a01b --- /dev/null +++ b/lib/tests/test_ini.t | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #!/usr/bin/perl | ||
| 2 | use Test::More; | ||
| 3 | if (! -e "./test_ini") { | ||
| 4 | plan skip_all => "./test_ini not compiled - please install tap library to test"; | ||
| 5 | } | ||
| 6 | exec "./test_ini"; | ||
