/* * Soft: Keepalived is a failover program for the LVS project * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * * Part: Configuration file parser/reader. Place into the dynamic * data structure representation the conf file representing * the loadbalanced server pool. * * Version: $Id: parser.c,v 1.1.1.1 2005/03/01 00:22:44 clement Exp $ * * Author: Alexandre Cassen, * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Copyright (C) 2001-2005 Alexandre Cassen, */ #include "parser.h" #include "memory.h" /* global vars */ vector keywords; FILE *stream; int reload = 0; /* local vars */ static int sublevel = 0; void keyword_alloc(vector keywords_vec, char *string, void (*handler) (vector)) { struct keyword *keyword; vector_alloc_slot(keywords_vec); keyword = (struct keyword *) MALLOC(sizeof (struct keyword)); keyword->string = string; keyword->handler = handler; vector_set_slot(keywords_vec, keyword); } void keyword_alloc_sub(vector keywords_vec, char *string, void (*handler) (vector)) { int i = 0; struct keyword *keyword; /* fetch last keyword */ keyword = VECTOR_SLOT(keywords_vec, VECTOR_SIZE(keywords_vec) - 1); /* position to last sub level */ for (i = 0; i < sublevel; i++) keyword = VECTOR_SLOT(keyword->sub, VECTOR_SIZE(keyword->sub) - 1); /* First sub level allocation */ if (!keyword->sub) keyword->sub = vector_alloc(); /* add new sub keyword */ keyword_alloc(keyword->sub, string, handler); } /* Exported helpers */ void install_sublevel(void) { sublevel++; } void install_sublevel_end(void) { sublevel--; } void install_keyword_root(char *string, void (*handler) (vector)) { keyword_alloc(keywords, string, handler); } void install_keyword(char *string, void (*handler) (vector)) { keyword_alloc_sub(keywords, string, handler); } void dump_keywords(vector keydump, int level) { int i, j; struct keyword *keyword_vec; for (i = 0; i < VECTOR_SIZE(keydump); i++) { keyword_vec = VECTOR_SLOT(keydump, i); for (j = 0; j < level; j++) printf(" "); printf("Keyword : %s\n", keyword_vec->string); if (keyword_vec->sub) dump_keywords(keyword_vec->sub, level + 1); } } void free_keywords(vector keywords_vec) { struct keyword *keyword_vec; int i; for (i = 0; i < VECTOR_SIZE(keywords_vec); i++) { keyword_vec = VECTOR_SLOT(keywords_vec, i); if (keyword_vec->sub) free_keywords(keyword_vec->sub); FREE(keyword_vec); } vector_free(keywords_vec); } vector alloc_strvec(char *string) { char *cp, *start, *token; int str_len; vector strvec; if (!string) return NULL; cp = string; /* Skip white spaces */ while (isspace((int) *cp) && *cp != '\0') cp++; /* Return if there is only white spaces */ if (*cp == '\0') return NULL; /* Return if string begin with a comment */ if (*cp == '!' || *cp == '#') return NULL; /* Create a vector and alloc each command piece */ strvec = vector_alloc(); while (1) { start = cp; if (*cp == '"') { cp++; token = MALLOC(2); *(token) = '"'; *(token + 1) = '\0'; } else { while (!isspace((int) *cp) && *cp != '\0' && *cp != '"') cp++; str_len = cp - start; token = MALLOC(str_len + 1); memcpy(token, start, str_len); *(token + str_len) = '\0'; } /* Alloc & set the slot */ vector_alloc_slot(strvec); vector_set_slot(strvec, token); while (isspace((int) *cp) && *cp != '\0') cp++; if (*cp == '\0' || *cp == '!' || *cp == '#') return strvec; } } int read_line(char *buf, int size) { int ch; int count = 0; while ((ch = fgetc(stream)) != EOF && (int) ch != '\n' && (int) ch != '\r') { if (count < size) buf[count] = (int) ch; else break; count++; } return (ch == EOF) ? 0 : 1; } vector read_value_block(void) { char *buf; int i; char *str = NULL; char *dup; vector vec = NULL; vector elements = vector_alloc(); buf = (char *) MALLOC(MAXBUF); while (read_line(buf, MAXBUF)) { vec = alloc_strvec(buf); if (vec) { str = VECTOR_SLOT(vec, 0); if (!strcmp(str, EOB)) { free_strvec(vec); break; } if (VECTOR_SIZE(vec)) for (i = 0; i < VECTOR_SIZE(vec); i++) { str = VECTOR_SLOT(vec, i); dup = (char *) MALLOC(strlen(str) + 1); memcpy(dup, str, strlen(str)); vector_alloc_slot(elements); vector_set_slot(elements, dup); } free_strvec(vec); } memset(buf, 0, MAXBUF); } FREE(buf); return elements; } void alloc_value_block(vector strvec, void (*alloc_func) (vector)) { char *buf; char *str = NULL; vector vec = NULL; buf = (char *) MALLOC(MAXBUF); while (read_line(buf, MAXBUF)) { vec = alloc_strvec(buf); if (vec) { str = VECTOR_SLOT(vec, 0); if (!strcmp(str, EOB)) { free_strvec(vec); break; } if (VECTOR_SIZE(vec)) (*alloc_func) (vec); free_strvec(vec); } memset(buf, 0, MAXBUF); } FREE(buf); } void * set_value(vector strvec) { char *str = VECTOR_SLOT(strvec, 1); int size = strlen(str); int i = 0; int len = 0; char *alloc = NULL; char *tmp; if (*str == '"') { for (i = 2; i < VECTOR_SIZE(strvec); i++) { str = VECTOR_SLOT(strvec, i); len += strlen(str); if (!alloc) alloc = (char *) MALLOC(sizeof (char *) * (len + 1)); else { alloc = REALLOC(alloc, sizeof (char *) * (len + 1)); tmp = VECTOR_SLOT(strvec, i-1); if (*str != '"' && *tmp != '"') strncat(alloc, " ", 1); } if (i != VECTOR_SIZE(strvec)-1) strncat(alloc, str, strlen(str)); } } else { alloc = MALLOC(sizeof (char *) * (size + 1)); memcpy(alloc, str, size); } return alloc; } /* recursive configuration stream handler */ static int kw_level = 0; void process_stream(vector keywords_vec) { int i; struct keyword *keyword_vec; char *str; char *buf; vector strvec; buf = zalloc(MAXBUF); while (read_line(buf, MAXBUF)) { strvec = alloc_strvec(buf); memset(buf,0, MAXBUF); if (!strvec) continue; str = VECTOR_SLOT(strvec, 0); if (!strcmp(str, EOB) && kw_level > 0) { free_strvec(strvec); break; } for (i = 0; i < VECTOR_SIZE(keywords_vec); i++) { keyword_vec = VECTOR_SLOT(keywords_vec, i); if (!strcmp(keyword_vec->string, str)) { if (keyword_vec->handler) (*keyword_vec->handler) (strvec); if (keyword_vec->sub) { kw_level++; process_stream(keyword_vec->sub); kw_level--; } break; } } free_strvec(strvec); } free(buf); return; } /* Data initialization */ void init_data(char *conf_file, vector (*init_keywords) (void)) { stream = fopen((conf_file) ? conf_file : CONF, "r"); if (!stream) { syslog(LOG_INFO, "Configuration file open problem...\n"); return; } /* Init Keywords structure */ keywords = vector_alloc(); (*init_keywords) (); /* Dump configuration * vector_dump(keywords); dump_keywords(keywords, 0); */ /* Stream handling */ process_stream(keywords); fclose(stream); free_keywords(keywords); }