Use err in dnet_io_process(), although it is not really needed
[elliptics.git] / example / config.c
blob9e1383411e9f46ff97fad41b3f067e4ddf515d27
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 #ifndef __unused
47 #define __unused __attribute__ ((unused))
48 #endif
51 * Config parser is single-threaded.
52 * No locks and simultaneous access from different threads.
55 #define DNET_CONF_COMMENT '#'
56 #define DNET_CONF_DELIMITER '='
58 static char *dnet_skip_line(char *line)
60 int len = strlen(line), i;
62 for (i=0; i<len; ++i) {
63 if (line[i] == DNET_CONF_COMMENT)
64 return NULL;
65 if (isspace(line[i]))
66 continue;
68 return &line[i];
71 return NULL;
74 static struct dnet_log dnet_backend_logger;
75 char *dnet_logger_value;
77 static struct dnet_config dnet_cfg_state;
78 static char *dnet_cfg_remotes;
79 static int dnet_daemon_mode;
81 static int dnet_simple_set(struct dnet_config_backend *b __unused, char *key, char *str)
83 unsigned long value = strtoul(str, NULL, 0);
85 if (!strcmp(key, "log_level"))
86 dnet_backend_logger.log_level = value;
87 else if (!strcmp(key, "wait_timeout"))
88 dnet_cfg_state.wait_timeout = value;
89 else if (!strcmp(key, "check_timeout"))
90 dnet_cfg_state.check_timeout = value;
91 else if (!strcmp(key, "stall_count"))
92 dnet_cfg_state.stall_count = value;
93 else if (!strcmp(key, "join"))
94 dnet_cfg_state.flags |= value ? DNET_CFG_JOIN_NETWORK : 0;
95 else if (!strcmp(key, "flags"))
96 dnet_cfg_state.flags |= (value & ~DNET_CFG_JOIN_NETWORK);
97 else if (!strcmp(key, "daemon"))
98 dnet_daemon_mode = value;
99 else if (!strcmp(key, "io_thread_num"))
100 dnet_cfg_state.io_thread_num = value;
101 else if (!strcmp(key, "nonblocking_io_thread_num"))
102 dnet_cfg_state.nonblocking_io_thread_num = value;
103 else if (!strcmp(key, "net_thread_num"))
104 dnet_cfg_state.net_thread_num = value;
105 else if (!strcmp(key, "bg_ionice_class"))
106 dnet_cfg_state.bg_ionice_class = value;
107 else if (!strcmp(key, "bg_ionice_prio"))
108 dnet_cfg_state.bg_ionice_prio = value;
109 else if (!strcmp(key, "removal_delay"))
110 dnet_cfg_state.removal_delay = value;
111 else if (!strcmp(key, "server_net_prio"))
112 dnet_cfg_state.server_prio = value;
113 else if (!strcmp(key, "client_net_prio"))
114 dnet_cfg_state.client_prio = value;
115 else if (!strcmp(key, "oplock_num"))
116 dnet_cfg_state.oplock_num = value;
117 else
118 return -1;
120 return 0;
123 static int dnet_set_group(struct dnet_config_backend *b __unused, char *key __unused, char *value)
125 dnet_cfg_state.group_id = strtoul(value, NULL, 0);
126 return 0;
129 static int dnet_set_addr(struct dnet_config_backend *b __unused, char *key __unused, char *value)
131 return dnet_parse_addr(value, &dnet_cfg_state);
134 static int dnet_set_remote_addrs(struct dnet_config_backend *b __unused, char *key __unused, char *value)
136 dnet_cfg_remotes = strdup(value);
137 if (!dnet_cfg_remotes)
138 return -ENOMEM;
140 return 0;
143 static int dnet_set_srw(struct dnet_config_backend *b __unused, char *key, char *value)
145 char **ptr = NULL;
147 if (!strcmp(key, "srw_config"))
148 ptr = &dnet_cfg_state.srw.config;
150 if (ptr) {
151 free(*ptr);
152 *ptr = strdup(value);
153 if (!*ptr)
154 return -ENOMEM;
157 return 0;
160 static int dnet_set_malloc_options(struct dnet_config_backend *b __unused, char *key __unused, char *value)
162 int err, thr = atoi(value);
164 err = mallopt(M_MMAP_THRESHOLD, thr);
165 if (err < 0) {
166 dnet_backend_log(DNET_LOG_ERROR, "Failed to set mmap threshold to %d: %s\n", thr, strerror(errno));
167 return err;
170 dnet_backend_log(DNET_LOG_INFO, "Set mmap threshold to %d.\n", thr);
171 return 0;
174 static int dnet_set_auth_cookie(struct dnet_config_backend *b __unused, char *key __unused, char *value)
176 snprintf(dnet_cfg_state.cookie, DNET_AUTH_COOKIE_SIZE, "%s", value);
177 return 0;
180 static int dnet_set_backend(struct dnet_config_backend *b, char *key __unused, char *value);
182 int dnet_set_log(struct dnet_config_backend *b __unused, char *key __unused, char *value)
184 char *tmp;
186 tmp = strdup(value);
187 if (!tmp)
188 return -ENOMEM;
190 if (dnet_logger_value)
191 free(dnet_logger_value);
193 dnet_logger_value = tmp;
195 if (!strcmp(dnet_logger_value, "syslog")) {
196 openlog("elliptics", 0, LOG_USER);
198 dnet_backend_logger.log_private = NULL;
199 dnet_backend_logger.log = dnet_syslog;
200 } else {
201 FILE *log, *old = dnet_backend_logger.log_private;
202 int err;
204 log = fopen(dnet_logger_value, "a");
205 if (!log) {
206 err = -errno;
207 fprintf(stderr, "cnf: failed to open log file '%s': %s\n", dnet_logger_value, strerror(errno));
208 return err;
211 dnet_backend_logger.log_private = log;
212 dnet_backend_logger.log = dnet_common_log;
214 dnet_common_log(log, 0xff, "Reopened log file\n");
216 if (old) {
217 dnet_common_log(old, 0xff, "Reopened log file\n");
218 fclose(old);
222 dnet_cfg_state.log = &dnet_backend_logger;
223 return 0;
226 static int dnet_set_history_env(struct dnet_config_backend *b __unused, char *key __unused, char *value)
228 snprintf(dnet_cfg_state.history_env, sizeof(dnet_cfg_state.history_env), "%s", value);
229 return 0;
232 static int dnet_set_cache_size(struct dnet_config_backend *b __unused, char *key __unused, char *value)
234 dnet_cfg_state.cache_size = strtoull(value, NULL, 0);
235 return 0;
238 static struct dnet_config_entry dnet_cfg_entries[] = {
239 {"mallopt_mmap_threshold", dnet_set_malloc_options},
240 {"log_level", dnet_simple_set},
241 {"wait_timeout", dnet_simple_set},
242 {"check_timeout", dnet_simple_set},
243 {"stall_count", dnet_simple_set},
244 {"group", dnet_set_group},
245 {"addr", dnet_set_addr},
246 {"remote", dnet_set_remote_addrs},
247 {"join", dnet_simple_set},
248 {"flags", dnet_simple_set},
249 {"backend", dnet_set_backend},
250 {"daemon", dnet_simple_set},
251 {"log", dnet_set_log},
252 {"history", dnet_set_history_env},
253 {"io_thread_num", dnet_simple_set},
254 {"nonblocking_io_thread_num", dnet_simple_set},
255 {"net_thread_num", dnet_simple_set},
256 {"bg_ionice_class", dnet_simple_set},
257 {"bg_ionice_prio", dnet_simple_set},
258 {"removal_delay", dnet_simple_set},
259 {"auth_cookie", dnet_set_auth_cookie},
260 {"server_net_prio", dnet_simple_set},
261 {"client_net_prio", dnet_simple_set},
262 {"oplock_num", dnet_simple_set},
263 {"srw_config", dnet_set_srw},
264 {"cache_size", dnet_set_cache_size},
267 static struct dnet_config_entry *dnet_cur_cfg_entries = dnet_cfg_entries;
268 static int dnet_cur_cfg_size = ARRAY_SIZE(dnet_cfg_entries);
270 static struct dnet_config_backend *dnet_cfg_backend, *dnet_cfg_current_backend;
271 static int dnet_cfg_backend_num;
273 static int dnet_set_backend(struct dnet_config_backend *current_backend __unused, char *key __unused, char *value)
275 struct dnet_config_backend *b;
276 int i;
278 for (i=0; i<dnet_cfg_backend_num; ++i) {
279 b = &dnet_cfg_backend[i];
281 if (!strcmp(value, b->name)) {
282 if (b->size) {
283 b->data = malloc(b->size);
284 if (!b->data)
285 return -ENOMEM;
286 memset(b->data, 0, b->size);
289 b->log = dnet_cfg_state.log;
291 dnet_cur_cfg_entries = b->ent;
292 dnet_cur_cfg_size = b->num;
293 dnet_cfg_current_backend = b;
295 return 0;
299 return -ENOENT;
302 int dnet_backend_register(struct dnet_config_backend *b)
304 dnet_cfg_backend = realloc(dnet_cfg_backend, (dnet_cfg_backend_num + 1) * sizeof(struct dnet_config_backend));
305 if (!dnet_cfg_backend)
306 return -ENOMEM;
308 memcpy(&dnet_cfg_backend[dnet_cfg_backend_num], b, sizeof(struct dnet_config_backend));
309 dnet_cfg_backend_num++;
311 return 0;
314 struct dnet_node *dnet_parse_config(char *file, int mon)
316 FILE *f;
317 int buf_size = 1024 * 1024;
318 char *buf, *ptr, *value, *key;
319 int err, i, len;
320 int line_num = 0;
321 struct dnet_node *n;
323 sigset_t sig;
324 sigfillset(&sig);
325 pthread_sigmask(SIG_BLOCK, &sig, NULL);
326 sigprocmask(SIG_BLOCK, &sig, NULL);
328 f = fopen(file, "r");
329 if (!f) {
330 err = -errno;
331 fprintf(stderr, "cnf: failed to open config file '%s': %s.\n", file, strerror(errno));
332 goto err_out_exit;
335 buf = malloc(buf_size);
336 if (!buf) {
337 err = -ENOMEM;
338 goto err_out_close;
341 dnet_backend_logger.log_level = DNET_LOG_ERROR;
342 dnet_backend_logger.log = dnet_common_log;
343 dnet_cfg_state.log = &dnet_backend_logger;
345 err = dnet_file_backend_init();
346 if (err)
347 goto err_out_free_buf;
349 err = dnet_eblob_backend_init();
350 if (err)
351 goto err_out_file_exit;
353 #ifdef HAVE_SMACK_SUPPORT
354 err = dnet_smack_backend_init();
355 if (err)
356 goto err_out_eblob_exit;
357 #endif
358 while (1) {
359 ptr = fgets(buf, buf_size, f);
360 if (!ptr) {
361 if (feof(f))
362 break;
364 err = -errno;
365 dnet_backend_log(DNET_LOG_ERROR, "cnf: failed to read config file '%s': %s.\n", file, strerror(errno));
366 goto err_out_free;
369 line_num++;
371 ptr = dnet_skip_line(ptr);
372 if (!ptr)
373 continue;
375 len = strlen(ptr);
377 if (len > 1) {
378 if (ptr[len - 1] == '\r' || ptr[len - 1] == '\n') {
379 ptr[len - 1] = '\0';
380 len--;
384 if (len > 2) {
385 if (ptr[len - 2] == '\r' || ptr[len - 2] == '\n') {
386 ptr[len - 2] = '\0';
387 len--;
391 key = value = NULL;
392 err = 0;
393 for (i=0; i<len; ++i) {
394 if (isspace(ptr[i])) {
395 if (key)
396 ptr[i] = '\0';
397 continue;
400 if (!key) {
401 key = ptr + i;
402 continue;
405 if (!value) {
406 if (ptr[i] == DNET_CONF_DELIMITER) {
407 value = ptr;
408 ptr[i] = '\0';
409 continue;
412 if (ptr[i] == DNET_CONF_COMMENT) {
413 key = value = NULL;
414 break;
417 continue;
418 } else {
419 value = ptr + i;
420 break;
423 key = value = NULL;
424 err = -EINVAL;
425 fprintf(stderr, "cnf: error in line %d: %s.\n", line_num, ptr);
426 goto err_out_free;
429 if (err)
430 goto err_out_free;
431 if (!key || !value)
432 continue;
434 for (i=0; i<dnet_cur_cfg_size; ++i) {
435 if (!strcmp(key, dnet_cur_cfg_entries[i].key)) {
436 err = dnet_cur_cfg_entries[i].callback(dnet_cfg_current_backend, key, value);
437 dnet_backend_log(DNET_LOG_INFO, "backend: %s, key: %s, value: %s, err: %d\n",
438 (dnet_cfg_current_backend) ? dnet_cfg_current_backend->name : "root level",
439 ptr, value, err);
440 if (err)
441 goto err_out_free;
443 break;
448 if (!dnet_cfg_current_backend) {
449 err = -EINVAL;
450 goto err_out_free;
453 if (dnet_daemon_mode && !mon)
454 dnet_background();
456 err = dnet_cfg_current_backend->init(dnet_cfg_current_backend, &dnet_cfg_state);
457 if (err)
458 goto err_out_free;
460 fclose(f);
461 f = NULL;
463 n = dnet_server_node_create(&dnet_cfg_state);
464 if (!n) {
465 /* backend cleanup is already called */
466 goto err_out_free;
469 err = dnet_common_add_remote_addr(n, &dnet_cfg_state, dnet_cfg_remotes);
470 if (err)
471 goto err_out_node_destroy;
473 return n;
475 err_out_node_destroy:
476 dnet_server_node_destroy(n);
477 err_out_free:
478 free(dnet_cfg_remotes);
480 #ifdef HAVE_SMACK_SUPPORT
481 dnet_smack_backend_exit();
482 err_out_eblob_exit:
483 #endif
484 dnet_eblob_backend_exit();
485 err_out_file_exit:
486 dnet_file_backend_exit();
487 err_out_free_buf:
488 free(buf);
489 err_out_close:
490 if (f)
491 fclose(f);
492 err_out_exit:
493 return NULL;
496 int dnet_backend_check_log_level(int level)
498 struct dnet_log *l = dnet_cfg_state.log;
500 return (l->log && (l->log_level >= level));
503 void dnet_backend_log_raw(int level, const char *format, ...)
505 va_list args;
506 char buf[1024];
507 struct dnet_log *l = dnet_cfg_state.log;
508 int buflen = sizeof(buf);
510 if (!l->log || !(l->log_level < level))
511 return;
513 va_start(args, format);
514 vsnprintf(buf, buflen, format, args);
515 buf[buflen-1] = '\0';
516 l->log(l->log_private, level, buf);
517 va_end(args);