Elliptics version update: 2.19.2.7
[elliptics.git] / example / config.c
blobebddca0bb964c44618e2de4d077054b0eee2f71c
1 /*
2 * 2008+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/socket.h>
19 #include <sys/time.h>
20 #include <sys/syscall.h>
22 #include <ctype.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <malloc.h>
26 #include <signal.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <syslog.h>
32 #include <time.h>
33 #include <unistd.h>
35 #include "elliptics/packet.h"
36 #include "elliptics/interface.h"
38 #include "common.h"
39 #include "backends.h"
41 #ifdef HAVE_SMACK_SUPPORT
42 int dnet_smack_backend_init(void);
43 void dnet_smack_backend_exit(void);
44 #endif
46 #ifdef HAVE_LEVELDB_SUPPORT
47 int dnet_leveldb_backend_init(void);
48 void dnet_leveldb_backend_exit(void);
49 #endif
52 #ifndef __unused
53 #define __unused __attribute__ ((unused))
54 #endif
57 * Config parser is single-threaded.
58 * No locks and simultaneous access from different threads.
61 #define DNET_CONF_COMMENT '#'
62 #define DNET_CONF_DELIMITER '='
64 static char *dnet_skip_line(char *line)
66 int len = strlen(line), i;
68 for (i=0; i<len; ++i) {
69 if (line[i] == DNET_CONF_COMMENT)
70 return NULL;
71 if (isspace(line[i]))
72 continue;
74 return &line[i];
77 return NULL;
80 static struct dnet_log dnet_backend_logger;
81 char *dnet_logger_value;
83 static struct dnet_config dnet_cfg_state;
84 static char *dnet_cfg_remotes;
85 static int dnet_daemon_mode;
87 static int dnet_simple_set(struct dnet_config_backend *b __unused, char *key, char *str)
89 unsigned long value = strtoul(str, NULL, 0);
91 if (!strcmp(key, "log_level"))
92 dnet_backend_logger.log_level = value;
93 else if (!strcmp(key, "wait_timeout"))
94 dnet_cfg_state.wait_timeout = value;
95 else if (!strcmp(key, "check_timeout"))
96 dnet_cfg_state.check_timeout = value;
97 else if (!strcmp(key, "stall_count"))
98 dnet_cfg_state.stall_count = value;
99 else if (!strcmp(key, "join"))
100 dnet_cfg_state.flags |= value ? DNET_CFG_JOIN_NETWORK : 0;
101 else if (!strcmp(key, "flags"))
102 dnet_cfg_state.flags |= (value & ~DNET_CFG_JOIN_NETWORK);
103 else if (!strcmp(key, "daemon"))
104 dnet_daemon_mode = value;
105 else if (!strcmp(key, "io_thread_num"))
106 dnet_cfg_state.io_thread_num = value;
107 else if (!strcmp(key, "nonblocking_io_thread_num"))
108 dnet_cfg_state.nonblocking_io_thread_num = value;
109 else if (!strcmp(key, "net_thread_num"))
110 dnet_cfg_state.net_thread_num = value;
111 else if (!strcmp(key, "bg_ionice_class"))
112 dnet_cfg_state.bg_ionice_class = value;
113 else if (!strcmp(key, "bg_ionice_prio"))
114 dnet_cfg_state.bg_ionice_prio = value;
115 else if (!strcmp(key, "removal_delay"))
116 dnet_cfg_state.removal_delay = value;
117 else if (!strcmp(key, "server_net_prio"))
118 dnet_cfg_state.server_prio = value;
119 else if (!strcmp(key, "client_net_prio"))
120 dnet_cfg_state.client_prio = value;
121 else if (!strcmp(key, "oplock_num"))
122 dnet_cfg_state.oplock_num = value;
123 else
124 return -1;
126 return 0;
129 static int dnet_set_group(struct dnet_config_backend *b __unused, char *key __unused, char *value)
131 dnet_cfg_state.group_id = strtoul(value, NULL, 0);
132 return 0;
135 static int dnet_set_addr(struct dnet_config_backend *b __unused, char *key __unused, char *value)
137 return dnet_parse_addr(value, &dnet_cfg_state);
140 static int dnet_set_remote_addrs(struct dnet_config_backend *b __unused, char *key __unused, char *value)
142 dnet_cfg_remotes = strdup(value);
143 if (!dnet_cfg_remotes)
144 return -ENOMEM;
146 return 0;
149 static int dnet_set_srw(struct dnet_config_backend *b __unused, char *key, char *value)
151 char **ptr = NULL;
153 if (!strcmp(key, "srw_config"))
154 ptr = &dnet_cfg_state.srw.config;
156 if (ptr) {
157 free(*ptr);
158 *ptr = strdup(value);
159 if (!*ptr)
160 return -ENOMEM;
163 return 0;
166 static int dnet_set_malloc_options(struct dnet_config_backend *b __unused, char *key __unused, char *value)
168 int err, thr = atoi(value);
170 err = mallopt(M_MMAP_THRESHOLD, thr);
171 if (err < 0) {
172 dnet_backend_log(DNET_LOG_ERROR, "Failed to set mmap threshold to %d: %s\n", thr, strerror(errno));
173 return err;
176 dnet_backend_log(DNET_LOG_INFO, "Set mmap threshold to %d.\n", thr);
177 return 0;
180 static int dnet_set_auth_cookie(struct dnet_config_backend *b __unused, char *key __unused, char *value)
182 snprintf(dnet_cfg_state.cookie, DNET_AUTH_COOKIE_SIZE, "%s", value);
183 return 0;
186 static int dnet_set_backend(struct dnet_config_backend *b, char *key __unused, char *value);
188 int dnet_set_log(struct dnet_config_backend *b __unused, char *key __unused, char *value)
190 char *tmp;
192 tmp = strdup(value);
193 if (!tmp)
194 return -ENOMEM;
196 if (dnet_logger_value)
197 free(dnet_logger_value);
199 dnet_logger_value = tmp;
201 if (!strcmp(dnet_logger_value, "syslog")) {
202 openlog("elliptics", 0, LOG_USER);
204 dnet_backend_logger.log_private = NULL;
205 dnet_backend_logger.log = dnet_syslog;
206 } else {
207 FILE *log, *old = dnet_backend_logger.log_private;
208 int err;
210 log = fopen(dnet_logger_value, "a");
211 if (!log) {
212 err = -errno;
213 fprintf(stderr, "cnf: failed to open log file '%s': %s\n", dnet_logger_value, strerror(errno));
214 return err;
217 dnet_backend_logger.log_private = log;
218 dnet_backend_logger.log = dnet_common_log;
220 dnet_common_log(log, 0xff, "Reopened log file\n");
222 if (old) {
223 dnet_common_log(old, 0xff, "Reopened log file\n");
224 fclose(old);
228 dnet_cfg_state.log = &dnet_backend_logger;
229 return 0;
232 static int dnet_set_history_env(struct dnet_config_backend *b __unused, char *key __unused, char *value)
234 snprintf(dnet_cfg_state.history_env, sizeof(dnet_cfg_state.history_env), "%s", value);
235 return 0;
238 static int dnet_set_cache_size(struct dnet_config_backend *b __unused, char *key __unused, char *value)
240 dnet_cfg_state.cache_size = strtoull(value, NULL, 0);
241 return 0;
244 static struct dnet_config_entry dnet_cfg_entries[] = {
245 {"mallopt_mmap_threshold", dnet_set_malloc_options},
246 {"log_level", dnet_simple_set},
247 {"wait_timeout", dnet_simple_set},
248 {"check_timeout", dnet_simple_set},
249 {"stall_count", dnet_simple_set},
250 {"group", dnet_set_group},
251 {"addr", dnet_set_addr},
252 {"remote", dnet_set_remote_addrs},
253 {"join", dnet_simple_set},
254 {"flags", dnet_simple_set},
255 {"backend", dnet_set_backend},
256 {"daemon", dnet_simple_set},
257 {"log", dnet_set_log},
258 {"history", dnet_set_history_env},
259 {"io_thread_num", dnet_simple_set},
260 {"nonblocking_io_thread_num", dnet_simple_set},
261 {"net_thread_num", dnet_simple_set},
262 {"bg_ionice_class", dnet_simple_set},
263 {"bg_ionice_prio", dnet_simple_set},
264 {"removal_delay", dnet_simple_set},
265 {"auth_cookie", dnet_set_auth_cookie},
266 {"server_net_prio", dnet_simple_set},
267 {"client_net_prio", dnet_simple_set},
268 {"oplock_num", dnet_simple_set},
269 {"srw_config", dnet_set_srw},
270 {"cache_size", dnet_set_cache_size},
273 static struct dnet_config_entry *dnet_cur_cfg_entries = dnet_cfg_entries;
274 static int dnet_cur_cfg_size = ARRAY_SIZE(dnet_cfg_entries);
276 static struct dnet_config_backend *dnet_cfg_backend, *dnet_cfg_current_backend;
277 static int dnet_cfg_backend_num;
279 static int dnet_set_backend(struct dnet_config_backend *current_backend __unused, char *key __unused, char *value)
281 struct dnet_config_backend *b;
282 int i;
284 for (i=0; i<dnet_cfg_backend_num; ++i) {
285 b = &dnet_cfg_backend[i];
287 if (!strcmp(value, b->name)) {
288 if (b->size) {
289 b->data = malloc(b->size);
290 if (!b->data)
291 return -ENOMEM;
292 memset(b->data, 0, b->size);
295 b->log = dnet_cfg_state.log;
297 dnet_cur_cfg_entries = b->ent;
298 dnet_cur_cfg_size = b->num;
299 dnet_cfg_current_backend = b;
301 return 0;
305 return -ENOENT;
308 int dnet_backend_register(struct dnet_config_backend *b)
310 dnet_cfg_backend = realloc(dnet_cfg_backend, (dnet_cfg_backend_num + 1) * sizeof(struct dnet_config_backend));
311 if (!dnet_cfg_backend)
312 return -ENOMEM;
314 memcpy(&dnet_cfg_backend[dnet_cfg_backend_num], b, sizeof(struct dnet_config_backend));
315 dnet_cfg_backend_num++;
317 return 0;
320 struct dnet_node *dnet_parse_config(char *file, int mon)
322 FILE *f;
323 int buf_size = 1024 * 1024;
324 char *buf, *ptr, *value, *key;
325 int err, i, len;
326 int line_num = 0;
327 struct dnet_node *n;
329 sigset_t sig;
330 sigfillset(&sig);
331 pthread_sigmask(SIG_BLOCK, &sig, NULL);
332 sigprocmask(SIG_BLOCK, &sig, NULL);
334 f = fopen(file, "r");
335 if (!f) {
336 err = -errno;
337 fprintf(stderr, "cnf: failed to open config file '%s': %s.\n", file, strerror(errno));
338 goto err_out_exit;
341 buf = malloc(buf_size);
342 if (!buf) {
343 err = -ENOMEM;
344 goto err_out_close;
347 dnet_backend_logger.log_level = DNET_LOG_DEBUG;
348 dnet_backend_logger.log = dnet_common_log;
349 dnet_cfg_state.log = &dnet_backend_logger;
351 err = dnet_file_backend_init();
352 if (err)
353 goto err_out_free_buf;
355 err = dnet_eblob_backend_init();
356 if (err)
357 goto err_out_file_exit;
359 #ifdef HAVE_SMACK_SUPPORT
360 err = dnet_smack_backend_init();
361 if (err)
362 goto err_out_eblob_exit;
363 #endif
364 #ifdef HAVE_LEVELDB_SUPPORT
365 err = dnet_leveldb_backend_init();
366 if (err)
367 goto err_out_smack_exit;
368 #endif
369 while (1) {
370 ptr = fgets(buf, buf_size, f);
371 if (!ptr) {
372 if (feof(f))
373 break;
375 err = -errno;
376 dnet_backend_log(DNET_LOG_ERROR, "cnf: failed to read config file '%s': %s.\n", file, strerror(errno));
377 goto err_out_free;
380 line_num++;
382 ptr = dnet_skip_line(ptr);
383 if (!ptr)
384 continue;
386 len = strlen(ptr);
388 if (len > 1) {
389 if (ptr[len - 1] == '\r' || ptr[len - 1] == '\n') {
390 ptr[len - 1] = '\0';
391 len--;
395 if (len > 2) {
396 if (ptr[len - 2] == '\r' || ptr[len - 2] == '\n') {
397 ptr[len - 2] = '\0';
398 len--;
402 key = value = NULL;
403 err = 0;
404 for (i=0; i<len; ++i) {
405 if (isspace(ptr[i])) {
406 if (key)
407 ptr[i] = '\0';
408 continue;
411 if (!key) {
412 key = ptr + i;
413 continue;
416 if (!value) {
417 if (ptr[i] == DNET_CONF_DELIMITER) {
418 value = ptr;
419 ptr[i] = '\0';
420 continue;
423 if (ptr[i] == DNET_CONF_COMMENT) {
424 key = value = NULL;
425 break;
428 continue;
429 } else {
430 value = ptr + i;
431 break;
434 key = value = NULL;
435 err = -EINVAL;
436 fprintf(stderr, "cnf: error in line %d: %s.\n", line_num, ptr);
437 goto err_out_free;
440 if (err)
441 goto err_out_free;
442 if (!key || !value)
443 continue;
445 for (i=0; i<dnet_cur_cfg_size; ++i) {
446 if (!strcmp(key, dnet_cur_cfg_entries[i].key)) {
447 err = dnet_cur_cfg_entries[i].callback(dnet_cfg_current_backend, key, value);
448 dnet_backend_log(DNET_LOG_INFO, "backend: %s, key: %s, value: %s, err: %d\n",
449 (dnet_cfg_current_backend) ? dnet_cfg_current_backend->name : "root level",
450 ptr, value, err);
451 if (err)
452 goto err_out_free;
454 break;
459 if (!dnet_cfg_current_backend) {
460 err = -EINVAL;
461 goto err_out_free;
464 if (dnet_daemon_mode && !mon)
465 dnet_background();
467 err = dnet_cfg_current_backend->init(dnet_cfg_current_backend, &dnet_cfg_state);
468 if (err)
469 goto err_out_free;
471 fclose(f);
472 f = NULL;
474 n = dnet_server_node_create(&dnet_cfg_state);
475 if (!n) {
476 /* backend cleanup is already called */
477 goto err_out_free;
480 err = dnet_common_add_remote_addr(n, &dnet_cfg_state, dnet_cfg_remotes);
481 if (err)
482 goto err_out_node_destroy;
484 return n;
486 err_out_node_destroy:
487 dnet_server_node_destroy(n);
488 err_out_free:
489 free(dnet_cfg_remotes);
491 #ifdef HAVE_LEVELDB_SUPPORT
492 dnet_leveldb_backend_exit();
493 err_out_smack_exit:
494 #endif
495 #ifdef HAVE_SMACK_SUPPORT
496 dnet_smack_backend_exit();
497 err_out_eblob_exit:
498 #endif
499 dnet_eblob_backend_exit();
500 err_out_file_exit:
501 dnet_file_backend_exit();
502 err_out_free_buf:
503 free(buf);
504 err_out_close:
505 if (f)
506 fclose(f);
507 err_out_exit:
508 return NULL;
511 int dnet_backend_check_log_level(int level)
513 struct dnet_log *l = dnet_cfg_state.log;
515 return (l->log && (l->log_level >= level));
518 void dnet_backend_log_raw(int level, const char *format, ...)
520 va_list args;
521 char buf[1024];
522 struct dnet_log *l = dnet_cfg_state.log;
523 int buflen = sizeof(buf);
525 if (!dnet_backend_check_log_level(level))
526 return;
528 va_start(args, format);
529 vsnprintf(buf, buflen, format, args);
530 buf[buflen-1] = '\0';
531 l->log(l->log_private, level, buf);
532 va_end(args);