1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #include "common/ceph_argparse.h"
16 #include "common/common_init.h"
17 #include "common/config.h"
18 #include "common/config_validators.h"
19 #include "include/str_list.h"
20 #include "include/stringify.h"
21 #include "osd/osd_types.h"
22 #include "common/errno.h"
23 #include "common/hostname.h"
25 #include <boost/type_traits.hpp>
27 /* Don't use standard Ceph logging in this file.
28 * We can't use logging until it's initialized, and a lot of the necessary
29 * initialization happens here.
41 using std::ostringstream
;
45 const char *CEPH_CONF_FILE_DEFAULT
= "$data_dir/config, /etc/ceph/$cluster.conf, ~/.ceph/$cluster.conf, $cluster.conf"
46 #if defined(__FreeBSD__)
47 ", /usr/local/etc/ceph/$cluster.conf"
52 #define STRINGIFY(x) _STR(x)
54 int ceph_resolve_file_search(const std::string
& filename_list
,
58 get_str_list(filename_list
, ls
);
61 list
<string
>::iterator iter
;
62 for (iter
= ls
.begin(); iter
!= ls
.end(); ++iter
) {
63 int fd
= ::open(iter
->c_str(), O_RDONLY
);
76 #define OPTION(name, type, def_val)
77 #define OPTION_VALIDATOR(name) \
78 struct md_config_t::option_##name##_t { \
79 typedef decltype(md_config_t::name) type; \
81 #define SAFE_OPTION(name, type, def_val)
82 #define SUBSYS(name, log, gather)
83 #define DEFAULT_SUBSYS(log, gather)
84 #include "common/config_opts.h"
86 #undef OPTION_VALIDATOR
94 typename
std::enable_if
<!std::is_destructible
<T
>::value
,
95 md_config_t::validator_t
>::type
create_validator() {
96 return md_config_t::validator_t();
100 typename
std::enable_if
<std::is_destructible
<T
>::value
,
101 md_config_t::validator_t
>::type
create_validator() {
102 // if T is defined (and not just forward declared), it implies
103 // that a validator function exists. use a dummy typed pointer to
104 // pick the correct validator function
105 return [](std::string
*value
, std::string
*error_message
) {
106 return ::validate(reinterpret_cast<T
*>(0), value
, error_message
);
110 } // anonymous namespace
112 md_config_t::md_config_t()
115 #define OPTION_OPT_INT(name, def_val) name(def_val),
116 #define OPTION_OPT_LONGLONG(name, def_val) name((1LL) * def_val),
117 #define OPTION_OPT_STR(name, def_val) name(def_val),
118 #define OPTION_OPT_DOUBLE(name, def_val) name(def_val),
119 #define OPTION_OPT_FLOAT(name, def_val) name(def_val),
120 #define OPTION_OPT_BOOL(name, def_val) name(def_val),
121 #define OPTION_OPT_ADDR(name, def_val) name(def_val),
122 #define OPTION_OPT_U32(name, def_val) name(def_val),
123 #define OPTION_OPT_U64(name, def_val) name(((uint64_t)1) * def_val),
124 #define OPTION_OPT_UUID(name, def_val) name(def_val),
125 #define OPTION(name, type, def_val) OPTION_##type(name, def_val)
126 #define OPTION_VALIDATOR(name)
127 #define SAFE_OPTION(name, type, def_val) OPTION(name, type, def_val)
128 #define SUBSYS(name, log, gather)
129 #define DEFAULT_SUBSYS(log, gather)
130 #include "common/config_opts.h"
131 #undef OPTION_OPT_INT
132 #undef OPTION_OPT_LONGLONG
133 #undef OPTION_OPT_STR
134 #undef OPTION_OPT_DOUBLE
135 #undef OPTION_OPT_FLOAT
136 #undef OPTION_OPT_BOOL
137 #undef OPTION_OPT_ADDR
138 #undef OPTION_OPT_U32
139 #undef OPTION_OPT_U64
140 #undef OPTION_OPT_UUID
142 #undef OPTION_VALIDATOR
145 #undef DEFAULT_SUBSYS
146 lock("md_config_t", true, false)
148 static const std::vector
<md_config_t::config_option
> s_config_options
= {
149 #define OPTION4(name, type, def_val, safe) \
150 config_option{ STRINGIFY(name), type, &md_config_t::name, safe, \
151 create_validator<option_##name##_t>() },
152 #define OPTION(name, type, def_val) OPTION4(name, type, def_val, false)
153 #define OPTION_VALIDATOR(name)
154 #define SAFE_OPTION(name, type, def_val) OPTION4(name, type, def_val, true)
155 #define SUBSYS(name, log, gather)
156 #define DEFAULT_SUBSYS(log, gather)
157 #include "common/config_opts.h"
160 #undef OPTION_VALIDATOR
163 #undef DEFAULT_SUBSYS
165 static std::shared_ptr
<decltype(s_config_options
)>
166 s_tbl(new std::vector
<md_config_t::config_option
>(std::move(s_config_options
)));
167 config_options
= s_tbl
;
169 validate_default_settings();
173 void md_config_t::init_subsys()
175 #define SUBSYS(name, log, gather) \
176 subsys.add(ceph_subsys_##name, STRINGIFY(name), log, gather);
177 #define DEFAULT_SUBSYS(log, gather) \
178 subsys.add(ceph_subsys_, "none", log, gather);
179 #define OPTION(a, b, c)
180 #define OPTION_VALIDATOR(a)
181 #define SAFE_OPTION(a, b, c)
182 #include "common/config_opts.h"
184 #undef OPTION_VALIDATOR
187 #undef DEFAULT_SUBSYS
190 md_config_t::~md_config_t()
194 void md_config_t::add_observer(md_config_obs_t
* observer_
)
196 Mutex::Locker
l(lock
);
197 const char **keys
= observer_
->get_tracked_conf_keys();
198 for (const char ** k
= keys
; *k
; ++k
) {
199 obs_map_t::value_type
val(*k
, observer_
);
200 observers
.insert(val
);
204 void md_config_t::remove_observer(md_config_obs_t
* observer_
)
206 Mutex::Locker
l(lock
);
207 bool found_obs
= false;
208 for (obs_map_t::iterator o
= observers
.begin(); o
!= observers
.end(); ) {
209 if (o
->second
== observer_
) {
210 observers
.erase(o
++);
220 int md_config_t::parse_config_files(const char *conf_files
,
221 std::ostream
*warnings
,
224 Mutex::Locker
l(lock
);
226 if (internal_safe_to_start_threads
)
229 if (!cluster
.size() && !conf_files
) {
231 * set the cluster name to 'ceph' when neither cluster name nor
232 * configuration file are specified.
238 const char *c
= getenv("CEPH_CONF");
243 if (flags
& CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
)
245 conf_files
= CEPH_CONF_FILE_DEFAULT
;
249 std::list
<std::string
> cfl
;
250 get_str_list(conf_files
, cfl
);
252 auto p
= cfl
.begin();
253 while (p
!= cfl
.end()) {
256 if (s
.find("$data_dir") != string::npos
) {
257 if (data_dir_option
.length()) {
258 list
<config_option
const *> stack
;
259 expand_meta(s
, NULL
, stack
, warnings
);
262 cfl
.erase(p
++); // ignore this item
268 return parse_config_files_impl(cfl
, warnings
);
271 int md_config_t::parse_config_files_impl(const std::list
<std::string
> &conf_files
,
272 std::ostream
*warnings
)
274 assert(lock
.is_locked());
277 list
<string
>::const_iterator c
;
278 for (c
= conf_files
.begin(); c
!= conf_files
.end(); ++c
) {
281 expand_meta(fn
, warnings
);
282 int ret
= cf
.parse_file(fn
.c_str(), &parse_errors
, warnings
);
285 else if (ret
!= -ENOENT
)
288 // it must have been all ENOENTs, that's the only way we got here
289 if (c
== conf_files
.end())
292 if (cluster
.size() == 0) {
294 * If cluster name is not set yet, use the prefix of the
295 * basename of configuration file as cluster name.
297 auto start
= c
->rfind('/') + 1;
298 auto end
= c
->find(".conf", start
);
299 if (end
== c
->npos
) {
301 * If the configuration file does not follow $cluster.conf
302 * convention, we do the last try and assign the cluster to
307 cluster
= c
->substr(start
, end
- start
);
311 std::vector
<std::string
> my_sections
;
312 _get_my_sections(my_sections
);
313 for (auto& opt
: *config_options
) {
315 int ret
= _get_val_from_conf_file(my_sections
, opt
.name
, val
, false);
317 std::string error_message
;
318 int r
= set_val_impl(val
, &opt
, &error_message
);
319 if (warnings
!= nullptr && (r
!= 0 || !error_message
.empty())) {
320 *warnings
<< "parse error setting '" << opt
.name
<< "' to '" << val
322 if (!error_message
.empty()) {
323 *warnings
<< " (" << error_message
<< ")";
325 *warnings
<< std::endl
;
331 for (int o
= 0; o
< subsys
.get_num(); o
++) {
332 std::string
as_option("debug_");
333 as_option
+= subsys
.get_name(o
);
335 int ret
= _get_val_from_conf_file(my_sections
, as_option
.c_str(), val
, false);
338 int r
= sscanf(val
.c_str(), "%d/%d", &log
, &gather
);
342 // cout << "config subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl;
343 subsys
.set_log_level(o
, log
);
344 subsys
.set_gather_level(o
, gather
);
349 // Warn about section names that look like old-style section names
350 std::deque
< std::string
> old_style_section_names
;
351 for (ConfFile::const_section_iter_t s
= cf
.sections_begin();
352 s
!= cf
.sections_end(); ++s
) {
353 const string
&str(s
->first
);
354 if (((str
.find("mds") == 0) || (str
.find("mon") == 0) ||
355 (str
.find("osd") == 0)) && (str
.size() > 3) && (str
[3] != '.')) {
356 old_style_section_names
.push_back(str
);
359 if (!old_style_section_names
.empty()) {
361 cerr
<< "ERROR! old-style section name(s) found: ";
363 for (std::deque
< std::string
>::const_iterator os
= old_style_section_names
.begin();
364 os
!= old_style_section_names
.end(); ++os
) {
368 cerr
<< ". Please use the new style section names that include a period.";
373 void md_config_t::parse_env()
375 Mutex::Locker
l(lock
);
376 if (internal_safe_to_start_threads
)
378 if (getenv("CEPH_KEYRING")) {
379 set_val_or_die("keyring", getenv("CEPH_KEYRING"));
383 void md_config_t::show_config(std::ostream
& out
)
385 Mutex::Locker
l(lock
);
386 _show_config(&out
, NULL
);
389 void md_config_t::show_config(Formatter
*f
)
391 Mutex::Locker
l(lock
);
392 _show_config(NULL
, f
);
395 void md_config_t::_show_config(std::ostream
*out
, Formatter
*f
)
398 *out
<< "name = " << name
<< std::endl
;
399 *out
<< "cluster = " << cluster
<< std::endl
;
402 f
->dump_string("name", stringify(name
));
403 f
->dump_string("cluster", cluster
);
405 for (int o
= 0; o
< subsys
.get_num(); o
++) {
407 *out
<< "debug_" << subsys
.get_name(o
)
408 << " = " << subsys
.get_log_level(o
)
409 << "/" << subsys
.get_gather_level(o
) << std::endl
;
412 std::string debug_name
= "debug_";
413 debug_name
+= subsys
.get_name(o
);
414 ss
<< subsys
.get_log_level(o
)
415 << "/" << subsys
.get_gather_level(o
);
416 f
->dump_string(debug_name
.c_str(), ss
.str());
419 for (auto& opt
: *config_options
) {
421 _get_val(opt
.name
, &buf
, -1);
423 *out
<< opt
.name
<< " = " << buf
<< std::endl
;
425 f
->dump_string(opt
.name
, buf
);
430 int md_config_t::parse_argv(std::vector
<const char*>& args
)
432 Mutex::Locker
l(lock
);
433 if (internal_safe_to_start_threads
) {
437 bool show_config
= false;
438 bool show_config_value
= false;
439 string show_config_value_arg
;
441 // In this function, don't change any parts of the configuration directly.
442 // Instead, use set_val to set them. This will allow us to send the proper
443 // observer notifications later.
445 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ) {
446 if (strcmp(*i
, "--") == 0) {
447 /* Normally we would use ceph_argparse_double_dash. However, in this
448 * function we *don't* want to remove the double dash, because later
449 * argument parses will still need to see it. */
452 else if (ceph_argparse_flag(args
, i
, "--show_conf", (char*)NULL
)) {
453 cerr
<< cf
<< std::endl
;
456 else if (ceph_argparse_flag(args
, i
, "--show_config", (char*)NULL
)) {
459 else if (ceph_argparse_witharg(args
, i
, &val
, "--show_config_value", (char*)NULL
)) {
460 show_config_value
= true;
461 show_config_value_arg
= val
;
463 else if (ceph_argparse_flag(args
, i
, "--foreground", "-f", (char*)NULL
)) {
464 set_val_or_die("daemonize", "false");
466 else if (ceph_argparse_flag(args
, i
, "-d", (char*)NULL
)) {
467 set_val_or_die("daemonize", "false");
468 set_val_or_die("log_file", "");
469 set_val_or_die("log_to_stderr", "true");
470 set_val_or_die("err_to_stderr", "true");
471 set_val_or_die("log_to_syslog", "false");
473 // Some stuff that we wanted to give universal single-character options for
474 // Careful: you can burn through the alphabet pretty quickly by adding
476 else if (ceph_argparse_witharg(args
, i
, &val
, "--monmap", "-M", (char*)NULL
)) {
477 set_val_or_die("monmap", val
.c_str());
479 else if (ceph_argparse_witharg(args
, i
, &val
, "--mon_host", "-m", (char*)NULL
)) {
480 set_val_or_die("mon_host", val
.c_str());
482 else if (ceph_argparse_witharg(args
, i
, &val
, "--bind", (char*)NULL
)) {
483 set_val_or_die("public_addr", val
.c_str());
485 else if (ceph_argparse_witharg(args
, i
, &val
, "--keyfile", "-K", (char*)NULL
)) {
486 set_val_or_die("keyfile", val
.c_str());
488 else if (ceph_argparse_witharg(args
, i
, &val
, "--keyring", "-k", (char*)NULL
)) {
489 set_val_or_die("keyring", val
.c_str());
491 else if (ceph_argparse_witharg(args
, i
, &val
, "--client_mountpoint", "-r", (char*)NULL
)) {
492 set_val_or_die("client_mountpoint", val
.c_str());
495 parse_option(args
, i
, NULL
);
501 _show_config(&cout
, NULL
);
505 if (show_config_value
) {
507 int r
= _get_val(show_config_value_arg
.c_str(), &buf
, -1);
510 std::cerr
<< "failed to get config option '" <<
511 show_config_value_arg
<< "': option not found" << std::endl
;
513 std::cerr
<< "failed to get config option '" <<
514 show_config_value_arg
<< "': " << cpp_strerror(r
) << std::endl
;
518 expand_meta(s
, &std::cerr
);
519 std::cout
<< s
<< std::endl
;
526 int md_config_t::parse_option(std::vector
<const char*>& args
,
527 std::vector
<const char*>::iterator
& i
,
535 for (o
= 0; o
< subsys
.get_num(); o
++) {
536 std::string
as_option("--");
537 as_option
+= "debug_";
538 as_option
+= subsys
.get_name(o
);
539 if (ceph_argparse_witharg(args
, i
, &val
,
540 as_option
.c_str(), (char*)NULL
)) {
542 int r
= sscanf(val
.c_str(), "%d/%d", &log
, &gather
);
546 // cout << "subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl;
547 subsys
.set_log_level(o
, log
);
548 subsys
.set_gather_level(o
, gather
);
550 *oss
<< "debug_" << subsys
.get_name(o
) << "=" << log
<< "/" << gather
<< " ";
555 if (o
< subsys
.get_num()) {
559 const char *option_name
= nullptr;
560 std::string error_message
;
562 for (auto& opt_ref
: *config_options
) {
564 config_option
const *opt
= &opt_ref
;
565 std::string
as_option("--");
566 as_option
+= opt
->name
;
567 option_name
= opt
->name
;
568 if (opt
->type
== OPT_BOOL
) {
570 if (ceph_argparse_binary_flag(args
, i
, &res
, oss
, as_option
.c_str(),
573 ret
= set_val_impl("false", opt
, &error_message
);
575 ret
= set_val_impl("true", opt
, &error_message
);
580 std::string
no("--no-");
582 if (ceph_argparse_flag(args
, i
, no
.c_str(), (char*)NULL
)) {
583 ret
= set_val_impl("false", opt
, &error_message
);
587 } else if (ceph_argparse_witharg(args
, i
, &val
, err
,
588 as_option
.c_str(), (char*)NULL
)) {
589 if (!err
.str().empty()) {
590 error_message
= err
.str();
594 if (oss
&& ((!opt
->is_safe()) &&
595 (observers
.find(opt
->name
) == observers
.end()))) {
596 *oss
<< "You cannot change " << opt
->name
<< " using injectargs.\n";
599 ret
= set_val_impl(val
, opt
, &error_message
);
605 if (ret
!= 0 || !error_message
.empty()) {
607 *oss
<< "Parse error setting " << option_name
<< " to '"
608 << val
<< "' using injectargs";
609 if (!error_message
.empty()) {
610 *oss
<< " (" << error_message
<< ")";
614 cerr
<< "parse error setting '" << option_name
<< "' to '"
616 if (!error_message
.empty()) {
617 cerr
<< " (" << error_message
<< ")";
619 cerr
<< "\n" << std::endl
;
623 if (o
== (int)config_options
->size()) {
630 int md_config_t::parse_injectargs(std::vector
<const char*>& args
,
633 assert(lock
.is_locked());
635 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ) {
636 int r
= parse_option(args
, i
, oss
);
643 void md_config_t::apply_changes(std::ostream
*oss
)
645 Mutex::Locker
l(lock
);
647 * apply changes until the cluster name is assigned
653 bool md_config_t::_internal_field(const string
& s
)
655 if (s
== "internal_safe_to_start_threads")
660 void md_config_t::_apply_changes(std::ostream
*oss
)
662 /* Maps observers to the configuration options that they care about which
664 typedef std::map
< md_config_obs_t
*, std::set
<std::string
> > rev_obs_map_t
;
668 // create the reverse observer mapping, mapping observers to the set of
669 // changed keys that they'll get.
671 std::set
<std::string
> empty_set
;
673 char *bufptr
= (char*)buf
;
674 for (changed_set_t::const_iterator c
= changed
.begin();
675 c
!= changed
.end(); ++c
) {
676 const std::string
&key(*c
);
677 pair
< obs_map_t::iterator
, obs_map_t::iterator
>
678 range(observers
.equal_range(key
));
680 (!_get_val(key
.c_str(), &bufptr
, sizeof(buf
))) &&
681 !_internal_field(key
)) {
682 (*oss
) << key
<< " = '" << buf
<< "' ";
683 if (range
.first
== range
.second
) {
684 (*oss
) << "(not observed, change may require restart) ";
687 for (obs_map_t::iterator r
= range
.first
; r
!= range
.second
; ++r
) {
688 rev_obs_map_t::value_type
robs_val(r
->second
, empty_set
);
689 pair
< rev_obs_map_t::iterator
, bool > robs_ret(robs
.insert(robs_val
));
690 std::set
<std::string
> &keys(robs_ret
.first
->second
);
697 // Make any pending observer callbacks
698 for (rev_obs_map_t::const_iterator r
= robs
.begin(); r
!= robs
.end(); ++r
) {
699 md_config_obs_t
*obs
= r
->first
;
700 obs
->handle_conf_change(this, r
->second
);
705 void md_config_t::call_all_observers()
707 std::map
<md_config_obs_t
*,std::set
<std::string
> > obs
;
709 Mutex::Locker
l(lock
);
713 for (obs_map_t::iterator r
= observers
.begin(); r
!= observers
.end(); ++r
) {
714 obs
[r
->second
].insert(r
->first
);
717 for (std::map
<md_config_obs_t
*,std::set
<std::string
> >::iterator p
= obs
.begin();
720 p
->first
->handle_conf_change(this, p
->second
);
724 int md_config_t::injectargs(const std::string
& s
, std::ostream
*oss
)
727 Mutex::Locker
l(lock
);
728 char b
[s
.length()+1];
729 strcpy(b
, s
.c_str());
730 std::vector
<const char*> nargs
;
734 while (*p
&& *p
!= ' ') p
++;
738 while (*p
&& *p
== ' ') p
++;
740 ret
= parse_injectargs(nargs
, oss
);
741 if (!nargs
.empty()) {
742 *oss
<< " failed to parse arguments: ";
744 for (std::vector
<const char*>::const_iterator i
= nargs
.begin();
745 i
!= nargs
.end(); ++i
) {
746 *oss
<< prefix
<< *i
;
756 void md_config_t::set_val_or_die(const char *key
, const char *val
)
758 int ret
= set_val(key
, val
);
762 struct is_integer_member
: public boost::static_visitor
<bool> {
764 typename
boost::enable_if
<boost::is_integral
<T
>, int>::type
= 0>
765 bool operator()(const T
md_config_t::* /* member_ptr */) const {
769 typename
boost::enable_if_c
<!boost::is_integral
<T
>::value
, int>::type
= 0>
770 bool operator()(const T
md_config_t::* /* member_ptr */) const {
775 struct is_float_member
: public boost::static_visitor
<bool> {
777 typename
boost::enable_if
<boost::is_float
<T
>, int>::type
= 0>
778 bool operator()(const T
md_config_t::* /* member_ptr */) const {
782 typename
boost::enable_if_c
<!boost::is_float
<T
>::value
, int>::type
= 0>
783 bool operator()(const T
md_config_t::* /* member_ptr */) const {
788 bool md_config_t::config_option::is_safe() const {
789 // for now integer and floating point options considered thread safe
791 boost::apply_visitor(is_integer_member(), md_member_ptr
) ||
792 boost::apply_visitor(is_float_member(), md_member_ptr
);
795 md_config_t::config_option
const *md_config_t::find_config_option(const std::string
&normalized_key
) const
797 auto opt_it
= std::find_if(config_options
->begin(),
798 config_options
->end(),
799 [normalized_key
](const config_option
&opt
) -> bool {
800 return strcmp(normalized_key
.c_str(), opt
.name
) == 0;
802 return config_options
->end() == opt_it
? nullptr : &(*opt_it
);
805 int md_config_t::set_val(const char *key
, const char *val
, bool meta
)
807 Mutex::Locker
l(lock
);
815 expand_meta(v
, &std::cerr
);
817 string
k(ConfFile::normalize_key_name(key
));
820 if (strncmp(k
.c_str(), "debug_", 6) == 0) {
821 for (int o
= 0; o
< subsys
.get_num(); o
++) {
822 std::string as_option
= "debug_" + subsys
.get_name(o
);
823 if (k
== as_option
) {
825 int r
= sscanf(v
.c_str(), "%d/%d", &log
, &gather
);
829 // cout << "subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl;
830 subsys
.set_log_level(o
, log
);
831 subsys
.set_gather_level(o
, gather
);
839 config_option
const *opt
= find_config_option(k
);
841 if ((!opt
->is_safe()) && internal_safe_to_start_threads
) {
842 // If threads have been started and the option is not thread safe
843 if (observers
.find(opt
->name
) == observers
.end()) {
844 // And there is no observer to safely change it...
850 std::string error_message
;
851 int r
= set_val_impl(v
, opt
, &error_message
);
855 // couldn't find a configuration option with key 'key'
860 int md_config_t::get_val(const char *key
, char **buf
, int len
) const
862 Mutex::Locker
l(lock
);
863 return _get_val(key
, buf
,len
);
866 md_config_t::config_value_t
md_config_t::get_val_generic(const char *key
) const
868 Mutex::Locker
l(lock
);
869 return _get_val(key
);
872 class get_value_generic_visitor
: public boost::static_visitor
<md_config_t::config_value_t
> {
873 md_config_t
const *conf
;
875 explicit get_value_generic_visitor(md_config_t
const *conf_
) : conf(conf_
) { }
876 template<typename T
> md_config_t::config_value_t
operator()(const T
md_config_t::* member_ptr
) {
877 return md_config_t::config_value_t(conf
->*member_ptr
);
881 md_config_t::config_value_t
md_config_t::_get_val(const char *key
) const
883 assert(lock
.is_locked());
886 return config_value_t(invalid_config_value_t());
888 // In key names, leading and trailing whitespace are not significant.
889 string
k(ConfFile::normalize_key_name(key
));
891 config_option
const *opt
= find_config_option(k
);
893 return config_value_t(invalid_config_value_t());
895 get_value_generic_visitor
gvv(this);
896 return boost::apply_visitor(gvv
, opt
->md_member_ptr
);
899 int md_config_t::_get_val(const char *key
, std::string
*value
) const {
900 assert(lock
.is_locked());
902 std::string
normalized_key(ConfFile::normalize_key_name(key
));
903 config_value_t config_value
= _get_val(normalized_key
.c_str());
904 if (!boost::get
<invalid_config_value_t
>(&config_value
)) {
906 if (bool *flag
= boost::get
<bool>(&config_value
)) {
907 oss
<< (*flag
? "true" : "false");
917 int md_config_t::_get_val(const char *key
, char **buf
, int len
) const
919 assert(lock
.is_locked());
924 string
k(ConfFile::normalize_key_name(key
));
926 config_value_t cval
= _get_val(k
.c_str());
927 if (!boost::get
<invalid_config_value_t
>(&cval
)) {
929 if (bool *flagp
= boost::get
<bool>(&cval
)) {
930 oss
<< (*flagp
? "true" : "false");
934 string
str(oss
.str());
935 int l
= strlen(str
.c_str()) + 1;
937 *buf
= (char*)malloc(l
);
940 strcpy(*buf
, str
.c_str());
943 snprintf(*buf
, len
, "%s", str
.c_str());
944 return (l
> len
) ? -ENAMETOOLONG
: 0;
948 for (int o
= 0; o
< subsys
.get_num(); o
++) {
949 std::string as_option
= "debug_" + subsys
.get_name(o
);
950 if (k
== as_option
) {
952 *buf
= (char*)malloc(20);
955 int l
= snprintf(*buf
, len
, "%d/%d", subsys
.get_log_level(o
), subsys
.get_gather_level(o
));
956 return (l
== len
) ? -ENAMETOOLONG
: 0;
960 // couldn't find a configuration option with key 'k'
964 void md_config_t::get_all_keys(std::vector
<std::string
> *keys
) const {
965 const std::string
negative_flag_prefix("no_");
968 keys
->reserve(config_options
->size());
969 for (auto& opt
: *config_options
) {
970 keys
->push_back(opt
.name
);
971 if (opt
.type
== OPT_BOOL
) {
972 keys
->push_back(negative_flag_prefix
+ opt
.name
);
975 for (int i
= 0; i
< subsys
.get_num(); ++i
) {
976 keys
->push_back("debug_" + subsys
.get_name(i
));
980 /* The order of the sections here is important. The first section in the
981 * vector is the "highest priority" section; if we find it there, we'll stop
982 * looking. The lowest priority section is the one we look in only if all
983 * others had nothing. This should always be the global section.
985 void md_config_t::get_my_sections(std::vector
<std::string
> §ions
) const
987 Mutex::Locker
l(lock
);
988 _get_my_sections(sections
);
991 void md_config_t::_get_my_sections(std::vector
<std::string
> §ions
) const
993 assert(lock
.is_locked());
994 sections
.push_back(name
.to_str());
996 sections
.push_back(name
.get_type_name());
998 sections
.push_back("global");
1001 // Return a list of all sections
1002 int md_config_t::get_all_sections(std::vector
<std::string
> §ions
) const
1004 Mutex::Locker
l(lock
);
1005 for (ConfFile::const_section_iter_t s
= cf
.sections_begin();
1006 s
!= cf
.sections_end(); ++s
) {
1007 sections
.push_back(s
->first
);
1012 int md_config_t::get_val_from_conf_file(const std::vector
<std::string
> §ions
,
1013 const char *key
, std::string
&out
, bool emeta
) const
1015 Mutex::Locker
l(lock
);
1016 return _get_val_from_conf_file(sections
, key
, out
, emeta
);
1019 int md_config_t::_get_val_from_conf_file(const std::vector
<std::string
> §ions
,
1020 const char *key
, std::string
&out
, bool emeta
) const
1022 assert(lock
.is_locked());
1023 std::vector
<std::string
>::const_iterator s
= sections
.begin();
1024 std::vector
<std::string
>::const_iterator s_end
= sections
.end();
1025 for (; s
!= s_end
; ++s
) {
1026 int ret
= cf
.read(s
->c_str(), key
, out
);
1029 expand_meta(out
, &std::cerr
);
1032 else if (ret
!= -ENOENT
)
1038 int md_config_t::set_val_impl(const std::string
&val
, config_option
const *opt
,
1039 std::string
*error_message
)
1041 assert(lock
.is_locked());
1042 std::string
value(val
);
1043 if (opt
->validator
) {
1044 int r
= opt
->validator(&value
, error_message
);
1050 int ret
= set_val_raw(value
.c_str(), opt
);
1053 changed
.insert(opt
->name
);
1057 template<typename T
> struct strtox_helper
;
1059 template<> struct strtox_helper
<float> {
1060 static inline void apply(const char *val
, float &x
, std::string
&err
) {
1061 x
= strict_strtof(val
, &err
);
1065 template<> struct strtox_helper
<double> {
1066 static inline void apply(const char *val
, double &x
, std::string
&err
) {
1067 x
= strict_strtod(val
, &err
);
1071 template<typename T
> static inline int strict_strtox(const char *val
, T
&x
) {
1073 strtox_helper
<T
>::apply(val
, x
, err
);
1074 return err
.empty() ? 0 : -EINVAL
;
1077 class set_value_visitor
: public boost::static_visitor
<int> {
1078 md_config_t
const *conf
;
1081 explicit set_value_visitor(md_config_t
const *conf_
, const char *val_
) :
1082 conf(conf_
), val(val_
) { }
1084 int operator()(const std::string
md_config_t::* member_ptr
) {
1085 auto *ptr
= const_cast<std::string
*>(&(conf
->*member_ptr
));
1086 *ptr
= val
? val
: "";
1090 int operator()(const bool md_config_t::* member_ptr
) {
1091 bool *ptr
= const_cast<bool *>(&(conf
->*member_ptr
));
1092 if (strcasecmp(val
, "false") == 0) {
1094 } else if (strcasecmp(val
, "true") == 0) {
1098 int b
= strict_strtol(val
, 10, &err
);
1107 // type has parse() member function
1108 template<typename T
,
1109 typename
boost::enable_if
<boost::is_member_function_pointer
<decltype(&T::parse
)>, int>::type
= 0>
1110 int operator()(const T
md_config_t::* member_ptr
) {
1111 T
*obj
= const_cast<T
*>(&(conf
->*member_ptr
));
1112 if (!obj
->parse(val
)) {
1119 template<typename T
,
1120 typename
boost::enable_if
<boost::is_floating_point
<T
>, int>::type
= 0>
1121 int operator()(const T
md_config_t::* member_ptr
) {
1122 T
* ptr
= const_cast<T
*>(&(conf
->*member_ptr
));
1123 return strict_strtox(val
, *ptr
);
1127 template<typename T
,
1128 typename
boost::enable_if_c
<boost::is_integral
<T
>::value
&&
1129 !boost::is_same
<T
, bool>::value
, int>::type
= 0>
1130 int operator()(const T
md_config_t::* member_ptr
) {
1132 T f
= strict_si_cast
<T
>(val
, &err
);
1136 T
*ptr
= const_cast<T
*>(&(conf
->*member_ptr
));
1142 int md_config_t::set_val_raw(const char *val
, config_option
const *opt
)
1144 assert(lock
.is_locked());
1145 set_value_visitor
svv(this, val
);
1146 return boost::apply_visitor(svv
, opt
->md_member_ptr
);
1149 static const char *CONF_METAVARIABLES
[] = {
1150 "data_dir", // put this first: it may contain some of the others
1151 "cluster", "type", "name", "host", "num", "id", "pid", "cctid"
1153 static const int NUM_CONF_METAVARIABLES
=
1154 (sizeof(CONF_METAVARIABLES
) / sizeof(CONF_METAVARIABLES
[0]));
1156 void md_config_t::expand_all_meta()
1158 // Expand all metavariables
1160 for (auto& opt
: *config_options
) {
1162 opt
.conf_ptr(str
, this);
1164 list
<config_option
const *> stack
;
1165 expand_meta(*str
, &opt
, stack
, &oss
);
1171 bool md_config_t::expand_meta(std::string
&origval
,
1172 std::ostream
*oss
) const
1174 list
<config_option
const *> stack
;
1175 return expand_meta(origval
, NULL
, stack
, oss
);
1178 bool md_config_t::expand_meta(std::string
&origval
,
1179 config_option
const *opt
,
1180 std::list
<config_option
const *> stack
,
1181 std::ostream
*oss
) const
1183 assert(lock
.is_locked());
1185 // no $ means no variable expansion is necessary
1186 if (origval
.find("$") == string::npos
)
1189 // ignore an expansion loop and create a human readable
1192 for (list
<config_option
const *>::iterator i
= stack
.begin();
1195 if (strcmp(opt
->name
, (*i
)->name
) == 0) {
1196 *oss
<< "variable expansion loop at "
1197 << opt
->name
<< "=" << origval
<< std::endl
;
1198 *oss
<< "expansion stack: " << std::endl
;
1199 for (list
<config_option
const *>::iterator j
= stack
.begin();
1202 *oss
<< (*j
)->name
<< "=" << *((*j
)->conf_ptr
<std::string
>(this)) << std::endl
;
1210 stack
.push_front(opt
);
1212 bool found_meta
= false;
1214 string val
= origval
;
1215 for (string::size_type s
= 0; s
< val
.size(); ) {
1216 if (val
[s
] != '$') {
1221 // try to parse the variable name into var, either \$\{(.+)\} or
1223 const char *valid_chars
= "abcdefghijklmnopqrstuvwxyz_";
1226 if (val
[s
+1] == '{') {
1228 endpos
= val
.find_first_not_of(valid_chars
, s
+2);
1229 if (endpos
!= std::string::npos
&&
1230 val
[endpos
] == '}') {
1231 var
= val
.substr(s
+2, endpos
-s
-2);
1236 endpos
= val
.find_first_not_of(valid_chars
, s
+1);
1237 if (endpos
!= std::string::npos
)
1238 var
= val
.substr(s
+1, endpos
-s
-1);
1240 var
= val
.substr(s
+1);
1243 bool expanded
= false;
1245 // special metavariable?
1246 for (int i
= 0; i
< NUM_CONF_METAVARIABLES
; ++i
) {
1247 if (var
!= CONF_METAVARIABLES
[i
])
1249 //cout << " meta match of " << var << " " << CONF_METAVARIABLES[i] << std::endl;
1251 out
+= name
.get_type_name();
1252 else if (var
== "cluster")
1254 else if (var
== "name")
1255 out
+= name
.to_cstr();
1256 else if (var
== "host")
1259 out
+= ceph_get_short_hostname();
1263 else if (var
== "num")
1264 out
+= name
.get_id().c_str();
1265 else if (var
== "id")
1266 out
+= name
.get_id().c_str();
1267 else if (var
== "pid")
1268 out
+= stringify(getpid());
1269 else if (var
== "cctid")
1270 out
+= stringify((unsigned long long)this);
1271 else if (var
== "data_dir") {
1272 if (data_dir_option
.length()) {
1274 _get_val(data_dir_option
.c_str(), &vv
, -1);
1277 expand_meta(tmp
, NULL
, stack
, oss
);
1280 // this isn't really right, but it'll result in a mangled
1281 // non-existent path that will fail any search list
1285 ceph_abort(); // unreachable
1291 for (auto& opt
: *config_options
) {
1292 if (var
== opt
.name
) {
1294 opt
.conf_ptr(origval
, const_cast<md_config_t
*>(this));
1296 expand_meta(*origval
, &opt
, stack
, oss
);
1300 _get_val(opt
.name
, &vv
, -1);
1318 // override the original value with the expanded value
1323 void md_config_t::diff(
1324 const md_config_t
*other
,
1325 map
<string
, pair
<string
, string
> > *diff
,
1326 set
<string
> *unknown
)
1328 diff_helper(other
, diff
, unknown
);
1330 void md_config_t::diff(
1331 const md_config_t
*other
,
1332 map
<string
, pair
<string
, string
> > *diff
,
1333 set
<string
> *unknown
, const string
& setting
)
1335 diff_helper(other
, diff
, unknown
, setting
);
1338 void md_config_t::diff_helper(
1339 const md_config_t
*other
,
1340 map
<string
,pair
<string
,string
> > *diff
,
1341 set
<string
> *unknown
, const string
& setting
)
1343 Mutex::Locker
l(lock
);
1345 char local_buf
[4096];
1346 char other_buf
[4096];
1347 for (auto& opt
: *config_options
) {
1348 if (!setting
.empty()) {
1349 if (setting
!= opt
.name
) {
1353 memset(local_buf
, 0, sizeof(local_buf
));
1354 memset(other_buf
, 0, sizeof(other_buf
));
1356 char *other_val
= other_buf
;
1357 int err
= other
->get_val(opt
.name
, &other_val
, sizeof(other_buf
));
1359 if (err
== -ENOENT
) {
1360 unknown
->insert(opt
.name
);
1365 char *local_val
= local_buf
;
1366 err
= _get_val(opt
.name
, &local_val
, sizeof(local_buf
));
1370 if (strcmp(local_val
, other_val
))
1371 diff
->insert(make_pair(opt
.name
, make_pair(local_val
, other_val
)));
1372 else if (!setting
.empty()) {
1373 diff
->insert(make_pair(opt
.name
, make_pair(local_val
, other_val
)));
1379 void md_config_t::complain_about_parse_errors(CephContext
*cct
)
1381 ::complain_about_parse_errors(cct
, &parse_errors
);
1384 void md_config_t::validate_default_settings() {
1385 Mutex::Locker
l(lock
);
1386 for (auto &opt
: *config_options
) {
1387 // normalize config defaults using their validator
1388 if (opt
.validator
) {
1390 int r
= _get_val(opt
.name
, &value
);
1393 std::string error_message
;
1394 r
= set_val_impl(value
.c_str(), &opt
, &error_message
);