From cc75ebf7e8560a69a6847f0260cce4772fff440a Mon Sep 17 00:00:00 2001 From: Edward Rudd Date: Wed, 01 Oct 2008 03:57:58 +0000 Subject: Initial revision of command line importer. --- (limited to 'utility/config.c') diff --git a/utility/config.c b/utility/config.c new file mode 100644 index 0000000..6b3dce1 --- /dev/null +++ b/utility/config.c @@ -0,0 +1,305 @@ +#include "apr.h" +#include "apr_file_info.h" +#include "apr_file_io.h" +#include "apr_strings.h" +#include "apr_hash.h" +#include "apr_lib.h" +#include "shell.h" +#include "config.h" + +apr_hash_t *g_config_opts; + +apr_status_t config_set_string(config_t *cfg, config_opt_t *opt, int argc, + const char **argv) +{ + int offset = (int)(long)opt->data; + char **data = (char **)((void *)cfg + offset); + if (argc != 2) return APR_EINVAL; + *data = apr_pstrdup(cfg->pool, argv[1]); + return APR_SUCCESS; +} + +apr_status_t config_set_int(config_t *cfg, config_opt_t *opt, int argc, + const char **argv) +{ + int offset = (int)(long)opt->data; + int *data = (int *)((void *)cfg + offset); + if (argc != 2) return APR_EINVAL; + *data = apr_atoi64(argv[1]); + return APR_SUCCESS; +} + +apr_status_t config_set_flag(config_t *cfg, config_opt_t *opt, int argc, + const char **argv) +{ + int offset = (int)(long)opt->data; + int *data = (int *)((void *)cfg + offset); + if (argc != 2) return APR_EINVAL; + *data = CHECK_YESNO(argv[1]); + return APR_SUCCESS; +} + +apr_status_t config_set_loglevel(config_t *cfg, config_opt_t *opt, int argc, + const char **argv) +{ + if (argc != 2) return APR_EINVAL; + if (!strcasecmp(argv[1],"error")) { + cfg->loglevel = LOGLEVEL_ERROR; + } else if (!strcasecmp(argv[1],"warn")) { + cfg->loglevel = LOGLEVEL_WARN; + } else if (!strcasecmp(argv[1],"debug")) { + cfg->loglevel = LOGLEVEL_DEBUG; + } else if (!strcasecmp(argv[1],"quiet")) { + cfg->loglevel = LOGLEVEL_QUIET; + } else { + cfg->loglevel = LOGLEVEL_ERROR; + } + return APR_SUCCESS; +} + +apr_status_t config_set_dbconnect(config_t *cfg, config_opt_t *opt, int argc, + const char **argv) +{ + return APR_SUCCESS; +} + +apr_status_t config_set_dbparam(config_t *cfg, config_opt_t *opt, int argc, + const char **argv) +{ + return APR_SUCCESS; +} + +apr_status_t config_set_inputfile(config_t *cfg, config_opt_t *opt, int argc, + const char **argv) +{ + char **newp; + if (argc != 2) return APR_EINVAL; + newp = (char **)apr_array_push(cfg->input_files); + *newp = apr_pstrdup(cfg->pool, argv[1]); + return APR_SUCCESS; +} + +apr_status_t config_set_dummy(config_t *cfg, config_opt_t *opt, int argc, + const char **argv) +{ + return APR_SUCCESS; +} + +apr_status_t config_set_logformat(config_t *cfg, config_opt_t *opt, int argc, + const char **argv) +{ + config_logformat_t *format; + config_logformat_field_t *field; + + if (argc != 4) return APR_EINVAL; + + format = apr_hash_get(cfg->log_formats,argv[1],APR_HASH_KEY_STRING); + if (!format) { + format = apr_palloc(cfg->pool, sizeof(config_logformat_t)); + format->name = apr_pstrdup(cfg->pool, argv[1]); + format->fields = apr_array_make(cfg->pool, 5, + sizeof(config_logformat_field_t)); + apr_hash_set(cfg->log_formats, argv[1], APR_HASH_KEY_STRING, format); + } + field = (config_logformat_field_t *)apr_array_push(format->fields); + field->name = apr_pstrdup(cfg->pool, argv[2]); + field->datatype = apr_pstrdup(cfg->pool, argv[3]); + return APR_SUCCESS; +} + +void config_dump(config_t *cfg) +{ + apr_hash_index_t *hi; + + printf("ErrorLog: %s\n",cfg->errorlog); + printf("LogLevel: %d\n",cfg->loglevel); + + printf("InputDir: %s\n",cfg->input_dir); + + printf("Table: %s\n",cfg->table); + printf("Transactions: %d\n",cfg->transactions); + printf("MachineID: %s\n",cfg->machineid); + + printf("Log formats:\n"); + for (hi = apr_hash_first(cfg->pool, cfg->log_formats); hi; hi + = apr_hash_next(hi)) { + config_logformat_t *format; + config_logformat_field_t *fields; + int i; + + apr_hash_this(hi, NULL, NULL, (void **)&format); + printf(">> %s\n",format->name); + fields = (config_logformat_field_t *)format->fields->elts; + for (i=0; ifields->nelts; i++) { + printf(">>>> %s:%s\n", fields[i].name, fields[i].datatype); + } + } + printf("Log Format: %s\n",cfg->logformat); + + printf("DryRun: %d\n",cfg->dryrun); + printf("Summary: %d\n",cfg->summary); +} + +static char *lowerstr(apr_pool_t *pool, const char *input) { + char *temp; + char *itr; + temp = apr_pstrdup(pool, input); + for (itr=temp; *itr!='\0'; itr++) { + *itr = apr_tolower(*itr); + } + return temp; +} + +#define config_get_option(name) apr_hash_get(g_config_opts, name, APR_HASH_KEY_STRING) + +void config_add_option(apr_pool_t *p, const char *const name, + const char *const help, config_func_t func, void *data) +{ + config_opt_t *opt; + if (!g_config_opts) { + g_config_opts = apr_hash_make(p); + } + opt = apr_palloc(p, sizeof(config_opt_t)); + opt->name = name; + opt->help = help; + opt->func = func; + opt->data = data; + apr_hash_set(g_config_opts, lowerstr(p,name), APR_HASH_KEY_STRING, opt); +} + +void config_init(apr_pool_t *p) +{ + config_add_option(p, "ErrorLog", "File to log errors", + config_set_string, (void *)APR_OFFSETOF(config_t, errorlog)); + config_add_option(p, "LogLevel", "Set Log Level (error, warn, debug, quiet)", + config_set_loglevel, NULL); + + config_add_option(p, "InputDirectory", "Directory to scan for log files", + config_set_string, (void *)APR_OFFSETOF(config_t, input_dir)); + config_add_option(p, "InputFile", "Parse only this file", + config_set_inputfile, NULL); + + config_add_option(p, "DBConnect", "DB Connection information type://user:pass@hostname/database", + config_set_dbconnect, NULL); + config_add_option(p, "DBParam", "DB Connection Parameter", + config_set_dbparam, NULL); + config_add_option(p, "Table", "Table to import the log to", + config_set_string, (void *)APR_OFFSETOF(config_t, table)); + config_add_option(p, "UseTransactions", "Enable Transactions?", + config_set_flag, (void *)APR_OFFSETOF(config_t, transactions)); + config_add_option(p, "MachineID", "Machine ID to set", + config_set_string, (void *)APR_OFFSETOF(config_t, machineid)); + + config_add_option(p, "LogFormatConfig", "Define input log formats", + config_set_logformat, NULL); + config_add_option(p, "LogFormat", "Use this logformat when parsing files", + config_set_string, (void *)APR_OFFSETOF(config_t, logformat)); + + config_add_option(p, "DryRun", "Don't perform any actual database changes", + config_set_flag, (void *)APR_OFFSETOF(config_t, dryrun)); + config_add_option(p, "Config", "Dummy to handle config directive", + config_set_dummy, NULL); + config_add_option(p, "Summary", "Show the summary before exit?", + config_set_flag, (void *)APR_OFFSETOF(config_t, summary)); +} + +config_t *config_create(apr_pool_t *p) +{ + config_t *cfg; + apr_pool_t *sp; + apr_pool_create(&sp, p); + cfg = apr_pcalloc(sp, sizeof(config_t)); + cfg->pool = sp; + cfg->loglevel = LOGLEVEL_WARN; + cfg->summary = 1; + cfg->transactions = 1; + cfg->input_files = apr_array_make(cfg->pool, 10, sizeof(char *)); + cfg->dbconfig = apr_table_make(cfg->pool, 5); + cfg->log_formats = apr_hash_make(cfg->pool); + + return cfg; +} + +int config_merge(void *rec, const char *key, const char *value) { + config_t *cfg = (config_t *)rec; + + config_opt_t *opt = config_get_option(key); + if (opt) { + const char *args[] = {key, value}; + opt->func(cfg, opt, 2, args); + } else { + printf("Unhandled: %s\n", key); + } + return 1; +} + +apr_status_t config_read(config_t *cfg, const char *filename, + apr_table_t *merge) +{ + apr_finfo_t finfo; + apr_file_t *file; + apr_status_t rv, ret = APR_SUCCESS; + apr_pool_t *tp, *targp; + config_opt_t *opt; + char buff[1024]; + char *ptr, *ptr2; + char **targv; + int targc; + int line; + + apr_pool_create(&tp, cfg->pool); + apr_pool_create(&targp, tp); + + if (apr_stat(&finfo, filename, APR_FINFO_MIN, tp) != APR_SUCCESS) { + return APR_ENOENT; + } + rv = apr_file_open(&file, filename, APR_FOPEN_READ | APR_BUFFERED, + APR_OS_DEFAULT, tp); + if (rv != APR_SUCCESS) + return rv; + + line = 0; + do { + rv = apr_file_gets(buff, 1024, file); + if (rv == APR_SUCCESS) { // we read data + line++; + + // skip leading white space + for (ptr = buff; *ptr == ' ' || *ptr == '\t'; ptr++) + ; + // chomp off newline + for (ptr2 = ptr + strlen(ptr); *ptr2 != '\r' && *ptr2 != '\n'; ptr2--) + ; + *ptr2 = '\0'; + + // skip comments + if (*ptr == '#') + continue; + if (*ptr == '\0') + continue; + apr_pool_clear(targp); + apr_tokenize_to_argv(buff, &targv, targp); + targc = 0; + while (targv[targc]) targc++; + opt = config_get_option(lowerstr(targp,targv[0])); + if (opt) { + rv = opt->func(cfg, opt, targc, (const char **)targv); + if (APR_STATUS_IS_EINVAL(rv)) { + printf("Config Error: Invalid Arguments for %s\n\t%s\n", + opt->name, opt->help); + ret = rv; + } + } else { + printf("Unhandled: %s\n", targv[0]); + } + } + } while (rv == APR_SUCCESS); + + // Apply merges + apr_table_do(config_merge,(void *)cfg,merge,NULL); + + apr_file_close(file); + apr_pool_destroy(tp); + return ret; +} + -- cgit v0.9.2