2 * 2008+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
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>
18 #include <sys/socket.h>
20 #include <sys/syscall.h>
35 #include "elliptics/packet.h"
36 #include "elliptics/interface.h"
41 #ifdef HAVE_SMACK_SUPPORT
42 int dnet_smack_backend_init(void);
43 void dnet_smack_backend_exit(void);
47 #define __unused __attribute__ ((unused))
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
)
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
;
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);
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
)
143 static int dnet_set_srw(struct dnet_config_backend
*b __unused
, char *key
, char *value
)
147 if (!strcmp(key
, "srw_config"))
148 ptr
= &dnet_cfg_state
.srw
.config
;
152 *ptr
= strdup(value
);
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
);
166 dnet_backend_log(DNET_LOG_ERROR
, "Failed to set mmap threshold to %d: %s\n", thr
, strerror(errno
));
170 dnet_backend_log(DNET_LOG_INFO
, "Set mmap threshold to %d.\n", thr
);
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
);
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
)
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
;
201 FILE *log
, *old
= dnet_backend_logger
.log_private
;
204 log
= fopen(dnet_logger_value
, "a");
207 fprintf(stderr
, "cnf: failed to open log file '%s': %s\n", dnet_logger_value
, strerror(errno
));
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");
217 dnet_common_log(old
, 0xff, "Reopened log file\n");
222 dnet_cfg_state
.log
= &dnet_backend_logger
;
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
);
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);
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
;
278 for (i
=0; i
<dnet_cfg_backend_num
; ++i
) {
279 b
= &dnet_cfg_backend
[i
];
281 if (!strcmp(value
, b
->name
)) {
283 b
->data
= malloc(b
->size
);
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
;
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
)
308 memcpy(&dnet_cfg_backend
[dnet_cfg_backend_num
], b
, sizeof(struct dnet_config_backend
));
309 dnet_cfg_backend_num
++;
314 struct dnet_node
*dnet_parse_config(char *file
, int mon
)
317 int buf_size
= 1024 * 1024;
318 char *buf
, *ptr
, *value
, *key
;
325 pthread_sigmask(SIG_BLOCK
, &sig
, NULL
);
326 sigprocmask(SIG_BLOCK
, &sig
, NULL
);
328 f
= fopen(file
, "r");
331 fprintf(stderr
, "cnf: failed to open config file '%s': %s.\n", file
, strerror(errno
));
335 buf
= malloc(buf_size
);
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();
347 goto err_out_free_buf
;
349 err
= dnet_eblob_backend_init();
351 goto err_out_file_exit
;
353 #ifdef HAVE_SMACK_SUPPORT
354 err
= dnet_smack_backend_init();
356 goto err_out_eblob_exit
;
359 ptr
= fgets(buf
, buf_size
, f
);
365 dnet_backend_log(DNET_LOG_ERROR
, "cnf: failed to read config file '%s': %s.\n", file
, strerror(errno
));
371 ptr
= dnet_skip_line(ptr
);
378 if (ptr
[len
- 1] == '\r' || ptr
[len
- 1] == '\n') {
385 if (ptr
[len
- 2] == '\r' || ptr
[len
- 2] == '\n') {
393 for (i
=0; i
<len
; ++i
) {
394 if (isspace(ptr
[i
])) {
406 if (ptr
[i
] == DNET_CONF_DELIMITER
) {
412 if (ptr
[i
] == DNET_CONF_COMMENT
) {
425 fprintf(stderr
, "cnf: error in line %d: %s.\n", line_num
, ptr
);
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",
448 if (!dnet_cfg_current_backend
) {
453 if (dnet_daemon_mode
&& !mon
)
456 err
= dnet_cfg_current_backend
->init(dnet_cfg_current_backend
, &dnet_cfg_state
);
463 n
= dnet_server_node_create(&dnet_cfg_state
);
465 /* backend cleanup is already called */
469 err
= dnet_common_add_remote_addr(n
, &dnet_cfg_state
, dnet_cfg_remotes
);
471 goto err_out_node_destroy
;
475 err_out_node_destroy
:
476 dnet_server_node_destroy(n
);
478 free(dnet_cfg_remotes
);
480 #ifdef HAVE_SMACK_SUPPORT
481 dnet_smack_backend_exit();
484 dnet_eblob_backend_exit();
486 dnet_file_backend_exit();
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
, ...)
507 struct dnet_log
*l
= dnet_cfg_state
.log
;
508 int buflen
= sizeof(buf
);
510 if (!dnet_backend_check_log_level(level
))
513 va_start(args
, format
);
514 vsnprintf(buf
, buflen
, format
, args
);
515 buf
[buflen
-1] = '\0';
516 l
->log(l
->log_private
, level
, buf
);