summaryrefslogtreecommitdiffstatsabout
path: root/utility/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'utility/config.c')
-rw-r--r--utility/config.c305
1 files changed, 305 insertions, 0 deletions
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 @@
1#include "apr.h"
2#include "apr_file_info.h"
3#include "apr_file_io.h"
4#include "apr_strings.h"
5#include "apr_hash.h"
6#include "apr_lib.h"
7#include "shell.h"
8#include "config.h"
9
10apr_hash_t *g_config_opts;
11
12apr_status_t config_set_string(config_t *cfg, config_opt_t *opt, int argc,
13 const char **argv)
14{
15 int offset = (int)(long)opt->data;
16 char **data = (char **)((void *)cfg + offset);
17 if (argc != 2) return APR_EINVAL;
18 *data = apr_pstrdup(cfg->pool, argv[1]);
19 return APR_SUCCESS;
20}
21
22apr_status_t config_set_int(config_t *cfg, config_opt_t *opt, int argc,
23 const char **argv)
24{
25 int offset = (int)(long)opt->data;
26 int *data = (int *)((void *)cfg + offset);
27 if (argc != 2) return APR_EINVAL;
28 *data = apr_atoi64(argv[1]);
29 return APR_SUCCESS;
30}
31
32apr_status_t config_set_flag(config_t *cfg, config_opt_t *opt, int argc,
33 const char **argv)
34{
35 int offset = (int)(long)opt->data;
36 int *data = (int *)((void *)cfg + offset);
37 if (argc != 2) return APR_EINVAL;
38 *data = CHECK_YESNO(argv[1]);
39 return APR_SUCCESS;
40}
41
42apr_status_t config_set_loglevel(config_t *cfg, config_opt_t *opt, int argc,
43 const char **argv)
44{
45 if (argc != 2) return APR_EINVAL;
46 if (!strcasecmp(argv[1],"error")) {
47 cfg->loglevel = LOGLEVEL_ERROR;
48 } else if (!strcasecmp(argv[1],"warn")) {
49 cfg->loglevel = LOGLEVEL_WARN;
50 } else if (!strcasecmp(argv[1],"debug")) {
51 cfg->loglevel = LOGLEVEL_DEBUG;
52 } else if (!strcasecmp(argv[1],"quiet")) {
53 cfg->loglevel = LOGLEVEL_QUIET;
54 } else {
55 cfg->loglevel = LOGLEVEL_ERROR;
56 }
57 return APR_SUCCESS;
58}
59
60apr_status_t config_set_dbconnect(config_t *cfg, config_opt_t *opt, int argc,
61 const char **argv)
62{
63 return APR_SUCCESS;
64}
65
66apr_status_t config_set_dbparam(config_t *cfg, config_opt_t *opt, int argc,
67 const char **argv)
68{
69 return APR_SUCCESS;
70}
71
72apr_status_t config_set_inputfile(config_t *cfg, config_opt_t *opt, int argc,
73 const char **argv)
74{
75 char **newp;
76 if (argc != 2) return APR_EINVAL;
77 newp = (char **)apr_array_push(cfg->input_files);
78 *newp = apr_pstrdup(cfg->pool, argv[1]);
79 return APR_SUCCESS;
80}
81
82apr_status_t config_set_dummy(config_t *cfg, config_opt_t *opt, int argc,
83 const char **argv)
84{
85 return APR_SUCCESS;
86}
87
88apr_status_t config_set_logformat(config_t *cfg, config_opt_t *opt, int argc,
89 const char **argv)
90{
91 config_logformat_t *format;
92 config_logformat_field_t *field;
93
94 if (argc != 4) return APR_EINVAL;
95
96 format = apr_hash_get(cfg->log_formats,argv[1],APR_HASH_KEY_STRING);
97 if (!format) {
98 format = apr_palloc(cfg->pool, sizeof(config_logformat_t));
99 format->name = apr_pstrdup(cfg->pool, argv[1]);
100 format->fields = apr_array_make(cfg->pool, 5,
101 sizeof(config_logformat_field_t));
102 apr_hash_set(cfg->log_formats, argv[1], APR_HASH_KEY_STRING, format);
103 }
104 field = (config_logformat_field_t *)apr_array_push(format->fields);
105 field->name = apr_pstrdup(cfg->pool, argv[2]);
106 field->datatype = apr_pstrdup(cfg->pool, argv[3]);
107 return APR_SUCCESS;
108}
109
110void config_dump(config_t *cfg)
111{
112 apr_hash_index_t *hi;
113
114 printf("ErrorLog: %s\n",cfg->errorlog);
115 printf("LogLevel: %d\n",cfg->loglevel);
116
117 printf("InputDir: %s\n",cfg->input_dir);
118
119 printf("Table: %s\n",cfg->table);
120 printf("Transactions: %d\n",cfg->transactions);
121 printf("MachineID: %s\n",cfg->machineid);
122
123 printf("Log formats:\n");
124 for (hi = apr_hash_first(cfg->pool, cfg->log_formats); hi; hi
125 = apr_hash_next(hi)) {
126 config_logformat_t *format;
127 config_logformat_field_t *fields;
128 int i;
129
130 apr_hash_this(hi, NULL, NULL, (void **)&format);
131 printf(">> %s\n",format->name);
132 fields = (config_logformat_field_t *)format->fields->elts;
133 for (i=0; i<format->fields->nelts; i++) {
134 printf(">>>> %s:%s\n", fields[i].name, fields[i].datatype);
135 }
136 }
137 printf("Log Format: %s\n",cfg->logformat);
138
139 printf("DryRun: %d\n",cfg->dryrun);
140 printf("Summary: %d\n",cfg->summary);
141}
142
143static char *lowerstr(apr_pool_t *pool, const char *input) {
144 char *temp;
145 char *itr;
146 temp = apr_pstrdup(pool, input);
147 for (itr=temp; *itr!='\0'; itr++) {
148 *itr = apr_tolower(*itr);
149 }
150 return temp;
151}
152
153#define config_get_option(name) apr_hash_get(g_config_opts, name, APR_HASH_KEY_STRING)
154
155void config_add_option(apr_pool_t *p, const char *const name,
156 const char *const help, config_func_t func, void *data)
157{
158 config_opt_t *opt;
159 if (!g_config_opts) {
160 g_config_opts = apr_hash_make(p);
161 }
162 opt = apr_palloc(p, sizeof(config_opt_t));
163 opt->name = name;
164 opt->help = help;
165 opt->func = func;
166 opt->data = data;
167 apr_hash_set(g_config_opts, lowerstr(p,name), APR_HASH_KEY_STRING, opt);
168}
169
170void config_init(apr_pool_t *p)
171{
172 config_add_option(p, "ErrorLog", "File to log errors",
173 config_set_string, (void *)APR_OFFSETOF(config_t, errorlog));
174 config_add_option(p, "LogLevel", "Set Log Level (error, warn, debug, quiet)",
175 config_set_loglevel, NULL);
176
177 config_add_option(p, "InputDirectory", "Directory to scan for log files",
178 config_set_string, (void *)APR_OFFSETOF(config_t, input_dir));
179 config_add_option(p, "InputFile", "Parse only this file",
180 config_set_inputfile, NULL);
181
182 config_add_option(p, "DBConnect", "DB Connection information type://user:pass@hostname/database",
183 config_set_dbconnect, NULL);
184 config_add_option(p, "DBParam", "DB Connection Parameter",
185 config_set_dbparam, NULL);
186 config_add_option(p, "Table", "Table to import the log to",
187 config_set_string, (void *)APR_OFFSETOF(config_t, table));
188 config_add_option(p, "UseTransactions", "Enable Transactions?",
189 config_set_flag, (void *)APR_OFFSETOF(config_t, transactions));
190 config_add_option(p, "MachineID", "Machine ID to set",
191 config_set_string, (void *)APR_OFFSETOF(config_t, machineid));
192
193 config_add_option(p, "LogFormatConfig", "Define input log formats",
194 config_set_logformat, NULL);
195 config_add_option(p, "LogFormat", "Use this logformat when parsing files",
196 config_set_string, (void *)APR_OFFSETOF(config_t, logformat));
197
198 config_add_option(p, "DryRun", "Don't perform any actual database changes",
199 config_set_flag, (void *)APR_OFFSETOF(config_t, dryrun));
200 config_add_option(p, "Config", "Dummy to handle config directive",
201 config_set_dummy, NULL);
202 config_add_option(p, "Summary", "Show the summary before exit?",
203 config_set_flag, (void *)APR_OFFSETOF(config_t, summary));
204}
205
206config_t *config_create(apr_pool_t *p)
207{
208 config_t *cfg;
209 apr_pool_t *sp;
210 apr_pool_create(&sp, p);
211 cfg = apr_pcalloc(sp, sizeof(config_t));
212 cfg->pool = sp;
213 cfg->loglevel = LOGLEVEL_WARN;
214 cfg->summary = 1;
215 cfg->transactions = 1;
216 cfg->input_files = apr_array_make(cfg->pool, 10, sizeof(char *));
217 cfg->dbconfig = apr_table_make(cfg->pool, 5);
218 cfg->log_formats = apr_hash_make(cfg->pool);
219
220 return cfg;
221}
222
223int config_merge(void *rec, const char *key, const char *value) {
224 config_t *cfg = (config_t *)rec;
225
226 config_opt_t *opt = config_get_option(key);
227 if (opt) {
228 const char *args[] = {key, value};
229 opt->func(cfg, opt, 2, args);
230 } else {
231 printf("Unhandled: %s\n", key);
232 }
233 return 1;
234}
235
236apr_status_t config_read(config_t *cfg, const char *filename,
237 apr_table_t *merge)
238{
239 apr_finfo_t finfo;
240 apr_file_t *file;
241 apr_status_t rv, ret = APR_SUCCESS;
242 apr_pool_t *tp, *targp;
243 config_opt_t *opt;
244 char buff[1024];
245 char *ptr, *ptr2;
246 char **targv;
247 int targc;
248 int line;
249
250 apr_pool_create(&tp, cfg->pool);
251 apr_pool_create(&targp, tp);
252
253 if (apr_stat(&finfo, filename, APR_FINFO_MIN, tp) != APR_SUCCESS) {
254 return APR_ENOENT;
255 }
256 rv = apr_file_open(&file, filename, APR_FOPEN_READ | APR_BUFFERED,
257 APR_OS_DEFAULT, tp);
258 if (rv != APR_SUCCESS)
259 return rv;
260
261 line = 0;
262 do {
263 rv = apr_file_gets(buff, 1024, file);
264 if (rv == APR_SUCCESS) { // we read data
265 line++;
266
267 // skip leading white space
268 for (ptr = buff; *ptr == ' ' || *ptr == '\t'; ptr++)
269 ;
270 // chomp off newline
271 for (ptr2 = ptr + strlen(ptr); *ptr2 != '\r' && *ptr2 != '\n'; ptr2--)
272 ;
273 *ptr2 = '\0';
274
275 // skip comments
276 if (*ptr == '#')
277 continue;
278 if (*ptr == '\0')
279 continue;
280 apr_pool_clear(targp);
281 apr_tokenize_to_argv(buff, &targv, targp);
282 targc = 0;
283 while (targv[targc]) targc++;
284 opt = config_get_option(lowerstr(targp,targv[0]));
285 if (opt) {
286 rv = opt->func(cfg, opt, targc, (const char **)targv);
287 if (APR_STATUS_IS_EINVAL(rv)) {
288 printf("Config Error: Invalid Arguments for %s\n\t%s\n",
289 opt->name, opt->help);
290 ret = rv;
291 }
292 } else {
293 printf("Unhandled: %s\n", targv[0]);
294 }
295 }
296 } while (rv == APR_SUCCESS);
297
298 // Apply merges
299 apr_table_do(config_merge,(void *)cfg,merge,NULL);
300
301 apr_file_close(file);
302 apr_pool_destroy(tp);
303 return ret;
304}
305