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()) {
608 *oss
<< "Parse error setting " << option_name
<< " to '"
609 << val
<< "' using injectargs";
610 if (!error_message
.empty()) {
611 *oss
<< " (" << error_message
<< ")";
615 cerr
<< "parse error setting '" << option_name
<< "' to '"
617 if (!error_message
.empty()) {
618 cerr
<< " (" << error_message
<< ")";
620 cerr
<< "\n" << std::endl
;
624 if (o
== (int)config_options
->size()) {
631 int md_config_t::parse_injectargs(std::vector
<const char*>& args
,
634 assert(lock
.is_locked());
636 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ) {
637 int r
= parse_option(args
, i
, oss
);
644 void md_config_t::apply_changes(std::ostream
*oss
)
646 Mutex::Locker
l(lock
);
648 * apply changes until the cluster name is assigned
654 bool md_config_t::_internal_field(const string
& s
)
656 if (s
== "internal_safe_to_start_threads")
661 void md_config_t::_apply_changes(std::ostream
*oss
)
663 /* Maps observers to the configuration options that they care about which
665 typedef std::map
< md_config_obs_t
*, std::set
<std::string
> > rev_obs_map_t
;
669 // create the reverse observer mapping, mapping observers to the set of
670 // changed keys that they'll get.
672 std::set
<std::string
> empty_set
;
674 char *bufptr
= (char*)buf
;
675 for (changed_set_t::const_iterator c
= changed
.begin();
676 c
!= changed
.end(); ++c
) {
677 const std::string
&key(*c
);
678 pair
< obs_map_t::iterator
, obs_map_t::iterator
>
679 range(observers
.equal_range(key
));
681 (!_get_val(key
.c_str(), &bufptr
, sizeof(buf
))) &&
682 !_internal_field(key
)) {
683 (*oss
) << key
<< " = '" << buf
<< "' ";
684 if (range
.first
== range
.second
) {
685 (*oss
) << "(not observed, change may require restart) ";
688 for (obs_map_t::iterator r
= range
.first
; r
!= range
.second
; ++r
) {
689 rev_obs_map_t::value_type
robs_val(r
->second
, empty_set
);
690 pair
< rev_obs_map_t::iterator
, bool > robs_ret(robs
.insert(robs_val
));
691 std::set
<std::string
> &keys(robs_ret
.first
->second
);
698 // Make any pending observer callbacks
699 for (rev_obs_map_t::const_iterator r
= robs
.begin(); r
!= robs
.end(); ++r
) {
700 md_config_obs_t
*obs
= r
->first
;
701 obs
->handle_conf_change(this, r
->second
);
706 void md_config_t::call_all_observers()
708 std::map
<md_config_obs_t
*,std::set
<std::string
> > obs
;
710 Mutex::Locker
l(lock
);
714 for (auto r
= observers
.begin(); r
!= observers
.end(); ++r
) {
715 obs
[r
->second
].insert(r
->first
);
718 for (auto p
= obs
.begin();
721 p
->first
->handle_conf_change(this, p
->second
);
725 int md_config_t::injectargs(const std::string
& s
, std::ostream
*oss
)
728 Mutex::Locker
l(lock
);
729 char b
[s
.length()+1];
730 strcpy(b
, s
.c_str());
731 std::vector
<const char*> nargs
;
735 while (*p
&& *p
!= ' ') p
++;
739 while (*p
&& *p
== ' ') p
++;
741 ret
= parse_injectargs(nargs
, oss
);
742 if (!nargs
.empty()) {
743 *oss
<< " failed to parse arguments: ";
745 for (std::vector
<const char*>::const_iterator i
= nargs
.begin();
746 i
!= nargs
.end(); ++i
) {
747 *oss
<< prefix
<< *i
;
757 void md_config_t::set_val_or_die(const char *key
, const char *val
)
759 int ret
= set_val(key
, val
);
763 struct is_integer_member
: public boost::static_visitor
<bool> {
765 typename
boost::enable_if
<boost::is_integral
<T
>, int>::type
= 0>
766 bool operator()(const T
md_config_t::* /* member_ptr */) const {
770 typename
boost::enable_if_c
<!boost::is_integral
<T
>::value
, int>::type
= 0>
771 bool operator()(const T
md_config_t::* /* member_ptr */) const {
776 struct is_float_member
: public boost::static_visitor
<bool> {
778 typename
boost::enable_if
<boost::is_float
<T
>, int>::type
= 0>
779 bool operator()(const T
md_config_t::* /* member_ptr */) const {
783 typename
boost::enable_if_c
<!boost::is_float
<T
>::value
, int>::type
= 0>
784 bool operator()(const T
md_config_t::* /* member_ptr */) const {
789 bool md_config_t::config_option::is_safe() const {
790 // for now integer and floating point options considered thread safe
792 boost::apply_visitor(is_integer_member(), md_member_ptr
) ||
793 boost::apply_visitor(is_float_member(), md_member_ptr
);
796 md_config_t::config_option
const *md_config_t::find_config_option(const std::string
&normalized_key
) const
798 auto opt_it
= std::find_if(config_options
->begin(),
799 config_options
->end(),
800 [normalized_key
](const config_option
&opt
) -> bool {
801 return strcmp(normalized_key
.c_str(), opt
.name
) == 0;
803 return config_options
->end() == opt_it
? nullptr : &(*opt_it
);
806 int md_config_t::set_val(const char *key
, const char *val
, bool meta
)
808 Mutex::Locker
l(lock
);
816 expand_meta(v
, &std::cerr
);
818 string
k(ConfFile::normalize_key_name(key
));
821 if (strncmp(k
.c_str(), "debug_", 6) == 0) {
822 for (int o
= 0; o
< subsys
.get_num(); o
++) {
823 std::string as_option
= "debug_" + subsys
.get_name(o
);
824 if (k
== as_option
) {
826 int r
= sscanf(v
.c_str(), "%d/%d", &log
, &gather
);
830 // cout << "subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl;
831 subsys
.set_log_level(o
, log
);
832 subsys
.set_gather_level(o
, gather
);
840 config_option
const *opt
= find_config_option(k
);
842 if ((!opt
->is_safe()) && internal_safe_to_start_threads
) {
843 // If threads have been started and the option is not thread safe
844 if (observers
.find(opt
->name
) == observers
.end()) {
845 // And there is no observer to safely change it...
851 std::string error_message
;
852 int r
= set_val_impl(v
, opt
, &error_message
);
856 // couldn't find a configuration option with key 'key'
861 int md_config_t::get_val(const char *key
, char **buf
, int len
) const
863 Mutex::Locker
l(lock
);
864 return _get_val(key
, buf
,len
);
867 md_config_t::config_value_t
md_config_t::get_val_generic(const char *key
) const
869 Mutex::Locker
l(lock
);
870 return _get_val(key
);
873 class get_value_generic_visitor
: public boost::static_visitor
<md_config_t::config_value_t
> {
874 md_config_t
const *conf
;
876 explicit get_value_generic_visitor(md_config_t
const *conf_
) : conf(conf_
) { }
877 template<typename T
> md_config_t::config_value_t
operator()(const T
md_config_t::* member_ptr
) {
878 return md_config_t::config_value_t(conf
->*member_ptr
);
882 md_config_t::config_value_t
md_config_t::_get_val(const char *key
) const
884 assert(lock
.is_locked());
887 return config_value_t(invalid_config_value_t());
889 // In key names, leading and trailing whitespace are not significant.
890 string
k(ConfFile::normalize_key_name(key
));
892 config_option
const *opt
= find_config_option(k
);
894 return config_value_t(invalid_config_value_t());
896 get_value_generic_visitor
gvv(this);
897 return boost::apply_visitor(gvv
, opt
->md_member_ptr
);
900 int md_config_t::_get_val(const char *key
, std::string
*value
) const {
901 assert(lock
.is_locked());
903 std::string
normalized_key(ConfFile::normalize_key_name(key
));
904 config_value_t config_value
= _get_val(normalized_key
.c_str());
905 if (!boost::get
<invalid_config_value_t
>(&config_value
)) {
907 if (bool *flag
= boost::get
<bool>(&config_value
)) {
908 oss
<< (*flag
? "true" : "false");
909 } else if (float *fp
= boost::get
<float>(&config_value
)) {
910 oss
<< std::fixed
<< *fp
;
911 } else if (double *dp
= boost::get
<double>(&config_value
)) {
912 oss
<< std::fixed
<< *dp
;
922 int md_config_t::_get_val(const char *key
, char **buf
, int len
) const
924 assert(lock
.is_locked());
930 if (!_get_val(key
, &val
)) {
931 int l
= val
.length() + 1;
933 *buf
= (char*)malloc(l
);
936 strncpy(*buf
, val
.c_str(), l
);
939 snprintf(*buf
, len
, "%s", val
.c_str());
940 return (l
> len
) ? -ENAMETOOLONG
: 0;
943 string
k(ConfFile::normalize_key_name(key
));
945 for (int o
= 0; o
< subsys
.get_num(); o
++) {
946 std::string as_option
= "debug_" + subsys
.get_name(o
);
947 if (k
== as_option
) {
949 *buf
= (char*)malloc(20);
952 int l
= snprintf(*buf
, len
, "%d/%d", subsys
.get_log_level(o
), subsys
.get_gather_level(o
));
953 return (l
== len
) ? -ENAMETOOLONG
: 0;
957 // couldn't find a configuration option with key 'k'
961 void md_config_t::get_all_keys(std::vector
<std::string
> *keys
) const {
962 const std::string
negative_flag_prefix("no_");
965 keys
->reserve(config_options
->size());
966 for (auto& opt
: *config_options
) {
967 keys
->push_back(opt
.name
);
968 if (opt
.type
== OPT_BOOL
) {
969 keys
->push_back(negative_flag_prefix
+ opt
.name
);
972 for (int i
= 0; i
< subsys
.get_num(); ++i
) {
973 keys
->push_back("debug_" + subsys
.get_name(i
));
977 /* The order of the sections here is important. The first section in the
978 * vector is the "highest priority" section; if we find it there, we'll stop
979 * looking. The lowest priority section is the one we look in only if all
980 * others had nothing. This should always be the global section.
982 void md_config_t::get_my_sections(std::vector
<std::string
> §ions
) const
984 Mutex::Locker
l(lock
);
985 _get_my_sections(sections
);
988 void md_config_t::_get_my_sections(std::vector
<std::string
> §ions
) const
990 assert(lock
.is_locked());
991 sections
.push_back(name
.to_str());
993 sections
.push_back(name
.get_type_name());
995 sections
.push_back("global");
998 // Return a list of all sections
999 int md_config_t::get_all_sections(std::vector
<std::string
> §ions
) const
1001 Mutex::Locker
l(lock
);
1002 for (ConfFile::const_section_iter_t s
= cf
.sections_begin();
1003 s
!= cf
.sections_end(); ++s
) {
1004 sections
.push_back(s
->first
);
1009 int md_config_t::get_val_from_conf_file(const std::vector
<std::string
> §ions
,
1010 const char *key
, std::string
&out
, bool emeta
) const
1012 Mutex::Locker
l(lock
);
1013 return _get_val_from_conf_file(sections
, key
, out
, emeta
);
1016 int md_config_t::_get_val_from_conf_file(const std::vector
<std::string
> §ions
,
1017 const char *key
, std::string
&out
, bool emeta
) const
1019 assert(lock
.is_locked());
1020 std::vector
<std::string
>::const_iterator s
= sections
.begin();
1021 std::vector
<std::string
>::const_iterator s_end
= sections
.end();
1022 for (; s
!= s_end
; ++s
) {
1023 int ret
= cf
.read(s
->c_str(), key
, out
);
1026 expand_meta(out
, &std::cerr
);
1029 else if (ret
!= -ENOENT
)
1035 int md_config_t::set_val_impl(const std::string
&val
, config_option
const *opt
,
1036 std::string
*error_message
)
1038 assert(lock
.is_locked());
1039 std::string
value(val
);
1040 if (opt
->validator
) {
1041 int r
= opt
->validator(&value
, error_message
);
1047 int ret
= set_val_raw(value
.c_str(), opt
);
1050 changed
.insert(opt
->name
);
1054 template<typename T
> struct strtox_helper
;
1056 template<> struct strtox_helper
<float> {
1057 static inline void apply(const char *val
, float &x
, std::string
&err
) {
1058 x
= strict_strtof(val
, &err
);
1062 template<> struct strtox_helper
<double> {
1063 static inline void apply(const char *val
, double &x
, std::string
&err
) {
1064 x
= strict_strtod(val
, &err
);
1068 template<typename T
> static inline int strict_strtox(const char *val
, T
&x
) {
1070 strtox_helper
<T
>::apply(val
, x
, err
);
1071 return err
.empty() ? 0 : -EINVAL
;
1074 class set_value_visitor
: public boost::static_visitor
<int> {
1075 md_config_t
const *conf
;
1078 explicit set_value_visitor(md_config_t
const *conf_
, const char *val_
) :
1079 conf(conf_
), val(val_
) { }
1081 int operator()(const std::string
md_config_t::* member_ptr
) {
1082 auto *ptr
= const_cast<std::string
*>(&(conf
->*member_ptr
));
1083 *ptr
= val
? val
: "";
1087 int operator()(const bool md_config_t::* member_ptr
) {
1088 bool *ptr
= const_cast<bool *>(&(conf
->*member_ptr
));
1089 if (strcasecmp(val
, "false") == 0) {
1091 } else if (strcasecmp(val
, "true") == 0) {
1095 int b
= strict_strtol(val
, 10, &err
);
1104 // type has parse() member function
1105 template<typename T
,
1106 typename
boost::enable_if
<boost::is_member_function_pointer
<decltype(&T::parse
)>, int>::type
= 0>
1107 int operator()(const T
md_config_t::* member_ptr
) {
1108 T
*obj
= const_cast<T
*>(&(conf
->*member_ptr
));
1109 if (!obj
->parse(val
)) {
1116 template<typename T
,
1117 typename
boost::enable_if
<boost::is_floating_point
<T
>, int>::type
= 0>
1118 int operator()(const T
md_config_t::* member_ptr
) {
1119 T
* ptr
= const_cast<T
*>(&(conf
->*member_ptr
));
1120 return strict_strtox(val
, *ptr
);
1124 template<typename T
,
1125 typename
boost::enable_if_c
<boost::is_integral
<T
>::value
&&
1126 !boost::is_same
<T
, bool>::value
, int>::type
= 0>
1127 int operator()(const T
md_config_t::* member_ptr
) {
1129 T f
= strict_si_cast
<T
>(val
, &err
);
1133 T
*ptr
= const_cast<T
*>(&(conf
->*member_ptr
));
1139 int md_config_t::set_val_raw(const char *val
, config_option
const *opt
)
1141 assert(lock
.is_locked());
1142 set_value_visitor
svv(this, val
);
1143 return boost::apply_visitor(svv
, opt
->md_member_ptr
);
1146 static const char *CONF_METAVARIABLES
[] = {
1147 "data_dir", // put this first: it may contain some of the others
1148 "cluster", "type", "name", "host", "num", "id", "pid", "cctid"
1150 static const int NUM_CONF_METAVARIABLES
=
1151 (sizeof(CONF_METAVARIABLES
) / sizeof(CONF_METAVARIABLES
[0]));
1153 void md_config_t::expand_all_meta()
1155 // Expand all metavariables
1157 for (auto& opt
: *config_options
) {
1159 opt
.conf_ptr(str
, this);
1161 list
<config_option
const *> stack
;
1162 expand_meta(*str
, &opt
, stack
, &oss
);
1168 bool md_config_t::expand_meta(std::string
&origval
,
1169 std::ostream
*oss
) const
1171 list
<config_option
const *> stack
;
1172 return expand_meta(origval
, NULL
, stack
, oss
);
1175 bool md_config_t::expand_meta(std::string
&origval
,
1176 config_option
const *opt
,
1177 std::list
<config_option
const *> stack
,
1178 std::ostream
*oss
) const
1180 assert(lock
.is_locked());
1182 // no $ means no variable expansion is necessary
1183 if (origval
.find("$") == string::npos
)
1186 // ignore an expansion loop and create a human readable
1189 for (list
<config_option
const *>::iterator i
= stack
.begin();
1192 if (strcmp(opt
->name
, (*i
)->name
) == 0) {
1193 *oss
<< "variable expansion loop at "
1194 << opt
->name
<< "=" << origval
<< std::endl
;
1195 *oss
<< "expansion stack: " << std::endl
;
1196 for (list
<config_option
const *>::iterator j
= stack
.begin();
1199 *oss
<< (*j
)->name
<< "=" << *((*j
)->conf_ptr
<std::string
>(this)) << std::endl
;
1207 stack
.push_front(opt
);
1209 bool found_meta
= false;
1211 string val
= origval
;
1212 for (string::size_type s
= 0; s
< val
.size(); ) {
1213 if (val
[s
] != '$') {
1218 // try to parse the variable name into var, either \$\{(.+)\} or
1220 const char *valid_chars
= "abcdefghijklmnopqrstuvwxyz_";
1223 if (val
[s
+1] == '{') {
1225 endpos
= val
.find_first_not_of(valid_chars
, s
+2);
1226 if (endpos
!= std::string::npos
&&
1227 val
[endpos
] == '}') {
1228 var
= val
.substr(s
+2, endpos
-s
-2);
1233 endpos
= val
.find_first_not_of(valid_chars
, s
+1);
1234 if (endpos
!= std::string::npos
)
1235 var
= val
.substr(s
+1, endpos
-s
-1);
1237 var
= val
.substr(s
+1);
1240 bool expanded
= false;
1242 // special metavariable?
1243 for (int i
= 0; i
< NUM_CONF_METAVARIABLES
; ++i
) {
1244 if (var
!= CONF_METAVARIABLES
[i
])
1246 //cout << " meta match of " << var << " " << CONF_METAVARIABLES[i] << std::endl;
1248 out
+= name
.get_type_name();
1249 else if (var
== "cluster")
1251 else if (var
== "name")
1252 out
+= name
.to_cstr();
1253 else if (var
== "host")
1256 out
+= ceph_get_short_hostname();
1260 else if (var
== "num")
1261 out
+= name
.get_id().c_str();
1262 else if (var
== "id")
1263 out
+= name
.get_id().c_str();
1264 else if (var
== "pid")
1265 out
+= stringify(getpid());
1266 else if (var
== "cctid")
1267 out
+= stringify((unsigned long long)this);
1268 else if (var
== "data_dir") {
1269 if (data_dir_option
.length()) {
1271 _get_val(data_dir_option
.c_str(), &vv
, -1);
1274 expand_meta(tmp
, NULL
, stack
, oss
);
1277 // this isn't really right, but it'll result in a mangled
1278 // non-existent path that will fail any search list
1282 ceph_abort(); // unreachable
1288 for (auto& opt
: *config_options
) {
1289 if (var
== opt
.name
) {
1291 opt
.conf_ptr(origval
, const_cast<md_config_t
*>(this));
1293 expand_meta(*origval
, &opt
, stack
, oss
);
1297 _get_val(opt
.name
, &vv
, -1);
1315 // override the original value with the expanded value
1320 void md_config_t::diff(
1321 const md_config_t
*other
,
1322 map
<string
, pair
<string
, string
> > *diff
,
1323 set
<string
> *unknown
)
1325 diff_helper(other
, diff
, unknown
);
1327 void md_config_t::diff(
1328 const md_config_t
*other
,
1329 map
<string
, pair
<string
, string
> > *diff
,
1330 set
<string
> *unknown
, const string
& setting
)
1332 diff_helper(other
, diff
, unknown
, setting
);
1335 void md_config_t::diff_helper(
1336 const md_config_t
*other
,
1337 map
<string
,pair
<string
,string
> > *diff
,
1338 set
<string
> *unknown
, const string
& setting
)
1340 Mutex::Locker
l(lock
);
1342 char local_buf
[4096];
1343 char other_buf
[4096];
1344 for (auto& opt
: *config_options
) {
1345 if (!setting
.empty()) {
1346 if (setting
!= opt
.name
) {
1350 memset(local_buf
, 0, sizeof(local_buf
));
1351 memset(other_buf
, 0, sizeof(other_buf
));
1353 char *other_val
= other_buf
;
1354 int err
= other
->get_val(opt
.name
, &other_val
, sizeof(other_buf
));
1356 if (err
== -ENOENT
) {
1357 unknown
->insert(opt
.name
);
1362 char *local_val
= local_buf
;
1363 err
= _get_val(opt
.name
, &local_val
, sizeof(local_buf
));
1367 if (strcmp(local_val
, other_val
))
1368 diff
->insert(make_pair(opt
.name
, make_pair(local_val
, other_val
)));
1369 else if (!setting
.empty()) {
1370 diff
->insert(make_pair(opt
.name
, make_pair(local_val
, other_val
)));
1376 void md_config_t::complain_about_parse_errors(CephContext
*cct
)
1378 ::complain_about_parse_errors(cct
, &parse_errors
);
1381 void md_config_t::validate_default_settings() {
1382 Mutex::Locker
l(lock
);
1383 for (auto &opt
: *config_options
) {
1384 // normalize config defaults using their validator
1385 if (opt
.validator
) {
1387 int r
= _get_val(opt
.name
, &value
);
1390 std::string error_message
;
1391 r
= set_val_impl(value
.c_str(), &opt
, &error_message
);