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 "auth/Auth.h"
16 #include "common/ConfUtils.h"
17 #include "common/ceph_argparse.h"
18 #include "common/common_init.h"
19 #include "common/config.h"
20 #include "common/config_validators.h"
21 #include "common/static_assert.h"
22 #include "common/strtol.h"
23 #include "common/version.h"
24 #include "include/str_list.h"
25 #include "include/types.h"
26 #include "include/stringify.h"
27 #include "msg/msg_types.h"
28 #include "osd/osd_types.h"
29 #include "common/errno.h"
30 #include "common/hostname.h"
32 #include "include/assert.h"
39 #include <sys/types.h>
41 #include <type_traits>
43 #include <boost/type_traits.hpp>
44 #include <boost/utility/enable_if.hpp>
46 /* Don't use standard Ceph logging in this file.
47 * We can't use logging until it's initialized, and a lot of the necessary
48 * initialization happens here.
61 using std::ostringstream
;
66 const char *CEPH_CONF_FILE_DEFAULT
= "$data_dir/config, /etc/ceph/$cluster.conf, ~/.ceph/$cluster.conf, $cluster.conf"
67 #if defined(__FreeBSD__)
68 ", /usr/local/etc/ceph/$cluster.conf"
73 #define STRINGIFY(x) _STR(x)
75 int ceph_resolve_file_search(const std::string
& filename_list
,
79 get_str_list(filename_list
, ls
);
82 list
<string
>::iterator iter
;
83 for (iter
= ls
.begin(); iter
!= ls
.end(); ++iter
) {
84 int fd
= ::open(iter
->c_str(), O_RDONLY
);
97 #define OPTION(name, type, def_val)
98 #define OPTION_VALIDATOR(name) \
99 struct md_config_t::option_##name##_t { \
100 typedef decltype(md_config_t::name) type; \
102 #define SAFE_OPTION(name, type, def_val)
103 #define SUBSYS(name, log, gather)
104 #define DEFAULT_SUBSYS(log, gather)
105 #include "common/config_opts.h"
107 #undef OPTION_VALIDATOR
110 #undef DEFAULT_SUBSYS
114 template <typename T
>
115 typename
std::enable_if
<!std::is_destructible
<T
>::value
,
116 md_config_t::validator_t
>::type
create_validator() {
117 return md_config_t::validator_t();
120 template <typename T
>
121 typename
std::enable_if
<std::is_destructible
<T
>::value
,
122 md_config_t::validator_t
>::type
create_validator() {
123 // if T is defined (and not just forward declared), it implies
124 // that a validator function exists. use a dummy typed pointer to
125 // pick the correct validator function
126 return [](std::string
*value
, std::string
*error_message
) {
127 return ::validate(reinterpret_cast<T
*>(0), value
, error_message
);
131 } // anonymous namespace
133 md_config_t::md_config_t()
136 #define OPTION_OPT_INT(name, def_val) name(def_val),
137 #define OPTION_OPT_LONGLONG(name, def_val) name((1LL) * def_val),
138 #define OPTION_OPT_STR(name, def_val) name(def_val),
139 #define OPTION_OPT_DOUBLE(name, def_val) name(def_val),
140 #define OPTION_OPT_FLOAT(name, def_val) name(def_val),
141 #define OPTION_OPT_BOOL(name, def_val) name(def_val),
142 #define OPTION_OPT_ADDR(name, def_val) name(def_val),
143 #define OPTION_OPT_U32(name, def_val) name(def_val),
144 #define OPTION_OPT_U64(name, def_val) name(((uint64_t)1) * def_val),
145 #define OPTION_OPT_UUID(name, def_val) name(def_val),
146 #define OPTION(name, type, def_val) OPTION_##type(name, def_val)
147 #define OPTION_VALIDATOR(name)
148 #define SAFE_OPTION(name, type, def_val) OPTION(name, type, def_val)
149 #define SUBSYS(name, log, gather)
150 #define DEFAULT_SUBSYS(log, gather)
151 #include "common/config_opts.h"
152 #undef OPTION_OPT_INT
153 #undef OPTION_OPT_LONGLONG
154 #undef OPTION_OPT_STR
155 #undef OPTION_OPT_DOUBLE
156 #undef OPTION_OPT_FLOAT
157 #undef OPTION_OPT_BOOL
158 #undef OPTION_OPT_ADDR
159 #undef OPTION_OPT_U32
160 #undef OPTION_OPT_U64
161 #undef OPTION_OPT_UUID
163 #undef OPTION_VALIDATOR
166 #undef DEFAULT_SUBSYS
167 lock("md_config_t", true, false)
169 static const std::vector
<md_config_t::config_option
> s_config_options
= {
170 #define OPTION4(name, type, def_val, safe) \
171 config_option{ STRINGIFY(name), type, &md_config_t::name, safe, \
172 create_validator<option_##name##_t>() },
173 #define OPTION(name, type, def_val) OPTION4(name, type, def_val, false)
174 #define OPTION_VALIDATOR(name)
175 #define SAFE_OPTION(name, type, def_val) OPTION4(name, type, def_val, true)
176 #define SUBSYS(name, log, gather)
177 #define DEFAULT_SUBSYS(log, gather)
178 #include "common/config_opts.h"
181 #undef OPTION_VALIDATOR
184 #undef DEFAULT_SUBSYS
186 static std::shared_ptr
<decltype(s_config_options
)>
187 s_tbl(new std::vector
<md_config_t::config_option
>(std::move(s_config_options
)));
188 config_options
= s_tbl
;
190 validate_default_settings();
194 void md_config_t::init_subsys()
196 #define SUBSYS(name, log, gather) \
197 subsys.add(ceph_subsys_##name, STRINGIFY(name), log, gather);
198 #define DEFAULT_SUBSYS(log, gather) \
199 subsys.add(ceph_subsys_, "none", log, gather);
200 #define OPTION(a, b, c)
201 #define OPTION_VALIDATOR(a)
202 #define SAFE_OPTION(a, b, c)
203 #include "common/config_opts.h"
205 #undef OPTION_VALIDATOR
208 #undef DEFAULT_SUBSYS
211 md_config_t::~md_config_t()
215 void md_config_t::add_observer(md_config_obs_t
* observer_
)
217 Mutex::Locker
l(lock
);
218 const char **keys
= observer_
->get_tracked_conf_keys();
219 for (const char ** k
= keys
; *k
; ++k
) {
220 obs_map_t::value_type
val(*k
, observer_
);
221 observers
.insert(val
);
225 void md_config_t::remove_observer(md_config_obs_t
* observer_
)
227 Mutex::Locker
l(lock
);
228 bool found_obs
= false;
229 for (obs_map_t::iterator o
= observers
.begin(); o
!= observers
.end(); ) {
230 if (o
->second
== observer_
) {
231 observers
.erase(o
++);
241 int md_config_t::parse_config_files(const char *conf_files
,
242 std::ostream
*warnings
,
245 Mutex::Locker
l(lock
);
247 if (internal_safe_to_start_threads
)
250 if (!cluster
.size() && !conf_files
) {
252 * set the cluster name to 'ceph' when neither cluster name nor
253 * configuration file are specified.
259 const char *c
= getenv("CEPH_CONF");
264 if (flags
& CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
)
266 conf_files
= CEPH_CONF_FILE_DEFAULT
;
270 std::list
<std::string
> cfl
;
271 get_str_list(conf_files
, cfl
);
273 auto p
= cfl
.begin();
274 while (p
!= cfl
.end()) {
277 if (s
.find("$data_dir") != string::npos
) {
278 if (data_dir_option
.length()) {
279 list
<config_option
const *> stack
;
280 expand_meta(s
, NULL
, stack
, warnings
);
283 cfl
.erase(p
++); // ignore this item
289 return parse_config_files_impl(cfl
, warnings
);
292 int md_config_t::parse_config_files_impl(const std::list
<std::string
> &conf_files
,
293 std::ostream
*warnings
)
295 assert(lock
.is_locked());
298 list
<string
>::const_iterator c
;
299 for (c
= conf_files
.begin(); c
!= conf_files
.end(); ++c
) {
302 expand_meta(fn
, warnings
);
303 int ret
= cf
.parse_file(fn
.c_str(), &parse_errors
, warnings
);
306 else if (ret
!= -ENOENT
)
309 // it must have been all ENOENTs, that's the only way we got here
310 if (c
== conf_files
.end())
313 if (cluster
.size() == 0) {
315 * If cluster name is not set yet, use the prefix of the
316 * basename of configuration file as cluster name.
318 auto start
= c
->rfind('/') + 1;
319 auto end
= c
->find(".conf", start
);
320 if (end
== c
->npos
) {
322 * If the configuration file does not follow $cluster.conf
323 * convention, we do the last try and assign the cluster to
328 cluster
= c
->substr(start
, end
- start
);
332 std::vector
<std::string
> my_sections
;
333 _get_my_sections(my_sections
);
334 for (auto& opt
: *config_options
) {
336 int ret
= _get_val_from_conf_file(my_sections
, opt
.name
, val
, false);
338 std::string error_message
;
339 int r
= set_val_impl(val
, &opt
, &error_message
);
340 if (warnings
!= nullptr && (r
!= 0 || !error_message
.empty())) {
341 *warnings
<< "parse error setting '" << opt
.name
<< "' to '" << val
343 if (!error_message
.empty()) {
344 *warnings
<< " (" << error_message
<< ")";
346 *warnings
<< std::endl
;
352 for (int o
= 0; o
< subsys
.get_num(); o
++) {
353 std::string
as_option("debug_");
354 as_option
+= subsys
.get_name(o
);
356 int ret
= _get_val_from_conf_file(my_sections
, as_option
.c_str(), val
, false);
359 int r
= sscanf(val
.c_str(), "%d/%d", &log
, &gather
);
363 // cout << "config subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl;
364 subsys
.set_log_level(o
, log
);
365 subsys
.set_gather_level(o
, gather
);
370 // Warn about section names that look like old-style section names
371 std::deque
< std::string
> old_style_section_names
;
372 for (ConfFile::const_section_iter_t s
= cf
.sections_begin();
373 s
!= cf
.sections_end(); ++s
) {
374 const string
&str(s
->first
);
375 if (((str
.find("mds") == 0) || (str
.find("mon") == 0) ||
376 (str
.find("osd") == 0)) && (str
.size() > 3) && (str
[3] != '.')) {
377 old_style_section_names
.push_back(str
);
380 if (!old_style_section_names
.empty()) {
382 cerr
<< "ERROR! old-style section name(s) found: ";
384 for (std::deque
< std::string
>::const_iterator os
= old_style_section_names
.begin();
385 os
!= old_style_section_names
.end(); ++os
) {
389 cerr
<< ". Please use the new style section names that include a period.";
394 void md_config_t::parse_env()
396 Mutex::Locker
l(lock
);
397 if (internal_safe_to_start_threads
)
399 if (getenv("CEPH_KEYRING")) {
400 set_val_or_die("keyring", getenv("CEPH_KEYRING"));
404 void md_config_t::show_config(std::ostream
& out
)
406 Mutex::Locker
l(lock
);
407 _show_config(&out
, NULL
);
410 void md_config_t::show_config(Formatter
*f
)
412 Mutex::Locker
l(lock
);
413 _show_config(NULL
, f
);
416 void md_config_t::_show_config(std::ostream
*out
, Formatter
*f
)
419 *out
<< "name = " << name
<< std::endl
;
420 *out
<< "cluster = " << cluster
<< std::endl
;
423 f
->dump_string("name", stringify(name
));
424 f
->dump_string("cluster", cluster
);
426 for (int o
= 0; o
< subsys
.get_num(); o
++) {
428 *out
<< "debug_" << subsys
.get_name(o
)
429 << " = " << subsys
.get_log_level(o
)
430 << "/" << subsys
.get_gather_level(o
) << std::endl
;
433 std::string debug_name
= "debug_";
434 debug_name
+= subsys
.get_name(o
);
435 ss
<< subsys
.get_log_level(o
)
436 << "/" << subsys
.get_gather_level(o
);
437 f
->dump_string(debug_name
.c_str(), ss
.str());
440 for (auto& opt
: *config_options
) {
442 _get_val(opt
.name
, &buf
, -1);
444 *out
<< opt
.name
<< " = " << buf
<< std::endl
;
446 f
->dump_string(opt
.name
, buf
);
451 int md_config_t::parse_argv(std::vector
<const char*>& args
)
453 Mutex::Locker
l(lock
);
454 if (internal_safe_to_start_threads
) {
458 bool show_config
= false;
459 bool show_config_value
= false;
460 string show_config_value_arg
;
462 // In this function, don't change any parts of the configuration directly.
463 // Instead, use set_val to set them. This will allow us to send the proper
464 // observer notifications later.
466 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ) {
467 if (strcmp(*i
, "--") == 0) {
468 /* Normally we would use ceph_argparse_double_dash. However, in this
469 * function we *don't* want to remove the double dash, because later
470 * argument parses will still need to see it. */
473 else if (ceph_argparse_flag(args
, i
, "--show_conf", (char*)NULL
)) {
474 cerr
<< cf
<< std::endl
;
477 else if (ceph_argparse_flag(args
, i
, "--show_config", (char*)NULL
)) {
480 else if (ceph_argparse_witharg(args
, i
, &val
, "--show_config_value", (char*)NULL
)) {
481 show_config_value
= true;
482 show_config_value_arg
= val
;
484 else if (ceph_argparse_flag(args
, i
, "--foreground", "-f", (char*)NULL
)) {
485 set_val_or_die("daemonize", "false");
487 else if (ceph_argparse_flag(args
, i
, "-d", (char*)NULL
)) {
488 set_val_or_die("daemonize", "false");
489 set_val_or_die("log_file", "");
490 set_val_or_die("log_to_stderr", "true");
491 set_val_or_die("err_to_stderr", "true");
492 set_val_or_die("log_to_syslog", "false");
494 // Some stuff that we wanted to give universal single-character options for
495 // Careful: you can burn through the alphabet pretty quickly by adding
497 else if (ceph_argparse_witharg(args
, i
, &val
, "--monmap", "-M", (char*)NULL
)) {
498 set_val_or_die("monmap", val
.c_str());
500 else if (ceph_argparse_witharg(args
, i
, &val
, "--mon_host", "-m", (char*)NULL
)) {
501 set_val_or_die("mon_host", val
.c_str());
503 else if (ceph_argparse_witharg(args
, i
, &val
, "--bind", (char*)NULL
)) {
504 set_val_or_die("public_addr", val
.c_str());
506 else if (ceph_argparse_witharg(args
, i
, &val
, "--keyfile", "-K", (char*)NULL
)) {
507 set_val_or_die("keyfile", val
.c_str());
509 else if (ceph_argparse_witharg(args
, i
, &val
, "--keyring", "-k", (char*)NULL
)) {
510 set_val_or_die("keyring", val
.c_str());
512 else if (ceph_argparse_witharg(args
, i
, &val
, "--client_mountpoint", "-r", (char*)NULL
)) {
513 set_val_or_die("client_mountpoint", val
.c_str());
516 parse_option(args
, i
, NULL
);
522 _show_config(&cout
, NULL
);
526 if (show_config_value
) {
528 int r
= _get_val(show_config_value_arg
.c_str(), &buf
, -1);
531 std::cerr
<< "failed to get config option '" <<
532 show_config_value_arg
<< "': option not found" << std::endl
;
534 std::cerr
<< "failed to get config option '" <<
535 show_config_value_arg
<< "': " << cpp_strerror(r
) << std::endl
;
539 expand_meta(s
, &std::cerr
);
540 std::cout
<< s
<< std::endl
;
547 int md_config_t::parse_option(std::vector
<const char*>& args
,
548 std::vector
<const char*>::iterator
& i
,
556 for (o
= 0; o
< subsys
.get_num(); o
++) {
557 std::string
as_option("--");
558 as_option
+= "debug_";
559 as_option
+= subsys
.get_name(o
);
560 if (ceph_argparse_witharg(args
, i
, &val
,
561 as_option
.c_str(), (char*)NULL
)) {
563 int r
= sscanf(val
.c_str(), "%d/%d", &log
, &gather
);
567 // cout << "subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl;
568 subsys
.set_log_level(o
, log
);
569 subsys
.set_gather_level(o
, gather
);
571 *oss
<< "debug_" << subsys
.get_name(o
) << "=" << log
<< "/" << gather
<< " ";
576 if (o
< subsys
.get_num()) {
580 const char *option_name
= nullptr;
581 std::string error_message
;
583 for (auto& opt_ref
: *config_options
) {
585 config_option
const *opt
= &opt_ref
;
586 std::string
as_option("--");
587 as_option
+= opt
->name
;
588 option_name
= opt
->name
;
589 if (opt
->type
== OPT_BOOL
) {
591 if (ceph_argparse_binary_flag(args
, i
, &res
, oss
, as_option
.c_str(),
594 ret
= set_val_impl("false", opt
, &error_message
);
596 ret
= set_val_impl("true", opt
, &error_message
);
601 std::string
no("--no-");
603 if (ceph_argparse_flag(args
, i
, no
.c_str(), (char*)NULL
)) {
604 ret
= set_val_impl("false", opt
, &error_message
);
608 } else if (ceph_argparse_witharg(args
, i
, &val
, err
,
609 as_option
.c_str(), (char*)NULL
)) {
610 if (!err
.str().empty()) {
611 error_message
= err
.str();
615 if (oss
&& ((!opt
->is_safe()) &&
616 (observers
.find(opt
->name
) == observers
.end()))) {
617 *oss
<< "You cannot change " << opt
->name
<< " using injectargs.\n";
620 ret
= set_val_impl(val
, opt
, &error_message
);
626 if (ret
!= 0 || !error_message
.empty()) {
628 *oss
<< "Parse error setting " << option_name
<< " to '"
629 << val
<< "' using injectargs";
630 if (!error_message
.empty()) {
631 *oss
<< " (" << error_message
<< ")";
635 cerr
<< "parse error setting '" << option_name
<< "' to '"
637 if (!error_message
.empty()) {
638 cerr
<< " (" << error_message
<< ")";
640 cerr
<< "\n" << std::endl
;
644 if (o
== (int)config_options
->size()) {
651 int md_config_t::parse_injectargs(std::vector
<const char*>& args
,
654 assert(lock
.is_locked());
656 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ) {
657 int r
= parse_option(args
, i
, oss
);
664 void md_config_t::apply_changes(std::ostream
*oss
)
666 Mutex::Locker
l(lock
);
668 * apply changes until the cluster name is assigned
674 bool md_config_t::_internal_field(const string
& s
)
676 if (s
== "internal_safe_to_start_threads")
681 void md_config_t::_apply_changes(std::ostream
*oss
)
683 /* Maps observers to the configuration options that they care about which
685 typedef std::map
< md_config_obs_t
*, std::set
<std::string
> > rev_obs_map_t
;
689 // create the reverse observer mapping, mapping observers to the set of
690 // changed keys that they'll get.
692 std::set
<std::string
> empty_set
;
694 char *bufptr
= (char*)buf
;
695 for (changed_set_t::const_iterator c
= changed
.begin();
696 c
!= changed
.end(); ++c
) {
697 const std::string
&key(*c
);
698 pair
< obs_map_t::iterator
, obs_map_t::iterator
>
699 range(observers
.equal_range(key
));
701 (!_get_val(key
.c_str(), &bufptr
, sizeof(buf
))) &&
702 !_internal_field(key
)) {
703 (*oss
) << key
<< " = '" << buf
<< "' ";
704 if (range
.first
== range
.second
) {
705 (*oss
) << "(not observed, change may require restart) ";
708 for (obs_map_t::iterator r
= range
.first
; r
!= range
.second
; ++r
) {
709 rev_obs_map_t::value_type
robs_val(r
->second
, empty_set
);
710 pair
< rev_obs_map_t::iterator
, bool > robs_ret(robs
.insert(robs_val
));
711 std::set
<std::string
> &keys(robs_ret
.first
->second
);
718 // Make any pending observer callbacks
719 for (rev_obs_map_t::const_iterator r
= robs
.begin(); r
!= robs
.end(); ++r
) {
720 md_config_obs_t
*obs
= r
->first
;
721 obs
->handle_conf_change(this, r
->second
);
726 void md_config_t::call_all_observers()
728 std::map
<md_config_obs_t
*,std::set
<std::string
> > obs
;
730 Mutex::Locker
l(lock
);
734 for (obs_map_t::iterator r
= observers
.begin(); r
!= observers
.end(); ++r
) {
735 obs
[r
->second
].insert(r
->first
);
738 for (std::map
<md_config_obs_t
*,std::set
<std::string
> >::iterator p
= obs
.begin();
741 p
->first
->handle_conf_change(this, p
->second
);
745 int md_config_t::injectargs(const std::string
& s
, std::ostream
*oss
)
748 Mutex::Locker
l(lock
);
749 char b
[s
.length()+1];
750 strcpy(b
, s
.c_str());
751 std::vector
<const char*> nargs
;
755 while (*p
&& *p
!= ' ') p
++;
759 while (*p
&& *p
== ' ') p
++;
761 ret
= parse_injectargs(nargs
, oss
);
762 if (!nargs
.empty()) {
763 *oss
<< " failed to parse arguments: ";
765 for (std::vector
<const char*>::const_iterator i
= nargs
.begin();
766 i
!= nargs
.end(); ++i
) {
767 *oss
<< prefix
<< *i
;
777 void md_config_t::set_val_or_die(const char *key
, const char *val
)
779 int ret
= set_val(key
, val
);
783 struct is_integer_member
: public boost::static_visitor
<bool> {
785 typename
boost::enable_if
<boost::is_integral
<T
>, int>::type
= 0>
786 bool operator()(const T
md_config_t::* /* member_ptr */) const {
790 typename
boost::enable_if_c
<!boost::is_integral
<T
>::value
, int>::type
= 0>
791 bool operator()(const T
md_config_t::* /* member_ptr */) const {
796 struct is_float_member
: public boost::static_visitor
<bool> {
798 typename
boost::enable_if
<boost::is_float
<T
>, int>::type
= 0>
799 bool operator()(const T
md_config_t::* /* member_ptr */) const {
803 typename
boost::enable_if_c
<!boost::is_float
<T
>::value
, int>::type
= 0>
804 bool operator()(const T
md_config_t::* /* member_ptr */) const {
809 bool md_config_t::config_option::is_safe() const {
810 // for now integer and floating point options considered thread safe
812 boost::apply_visitor(is_integer_member(), md_member_ptr
) ||
813 boost::apply_visitor(is_float_member(), md_member_ptr
);
816 md_config_t::config_option
const *md_config_t::find_config_option(const std::string
&normalized_key
) const
818 auto opt_it
= std::find_if(config_options
->begin(),
819 config_options
->end(),
820 [normalized_key
](const config_option
&opt
) -> bool {
821 return strcmp(normalized_key
.c_str(), opt
.name
) == 0;
823 return config_options
->end() == opt_it
? nullptr : &(*opt_it
);
826 int md_config_t::set_val(const char *key
, const char *val
, bool meta
)
828 Mutex::Locker
l(lock
);
836 expand_meta(v
, &std::cerr
);
838 string
k(ConfFile::normalize_key_name(key
));
841 if (strncmp(k
.c_str(), "debug_", 6) == 0) {
842 for (int o
= 0; o
< subsys
.get_num(); o
++) {
843 std::string as_option
= "debug_" + subsys
.get_name(o
);
844 if (k
== as_option
) {
846 int r
= sscanf(v
.c_str(), "%d/%d", &log
, &gather
);
850 // cout << "subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl;
851 subsys
.set_log_level(o
, log
);
852 subsys
.set_gather_level(o
, gather
);
860 config_option
const *opt
= find_config_option(k
);
862 if ((!opt
->is_safe()) && internal_safe_to_start_threads
) {
863 // If threads have been started and the option is not thread safe
864 if (observers
.find(opt
->name
) == observers
.end()) {
865 // And there is no observer to safely change it...
871 std::string error_message
;
872 int r
= set_val_impl(v
, opt
, &error_message
);
876 // couldn't find a configuration option with key 'key'
881 int md_config_t::get_val(const char *key
, char **buf
, int len
) const
883 Mutex::Locker
l(lock
);
884 return _get_val(key
, buf
,len
);
887 md_config_t::config_value_t
md_config_t::get_val_generic(const char *key
) const
889 Mutex::Locker
l(lock
);
890 return _get_val(key
);
893 class get_value_generic_visitor
: public boost::static_visitor
<md_config_t::config_value_t
> {
894 md_config_t
const *conf
;
896 explicit get_value_generic_visitor(md_config_t
const *conf_
) : conf(conf_
) { }
897 template<typename T
> md_config_t::config_value_t
operator()(const T
md_config_t::* member_ptr
) {
898 return md_config_t::config_value_t(conf
->*member_ptr
);
902 md_config_t::config_value_t
md_config_t::_get_val(const char *key
) const
904 assert(lock
.is_locked());
907 return config_value_t(invalid_config_value_t());
909 // In key names, leading and trailing whitespace are not significant.
910 string
k(ConfFile::normalize_key_name(key
));
912 config_option
const *opt
= find_config_option(k
);
914 return config_value_t(invalid_config_value_t());
916 get_value_generic_visitor
gvv(this);
917 return boost::apply_visitor(gvv
, opt
->md_member_ptr
);
920 int md_config_t::_get_val(const char *key
, std::string
*value
) const {
921 assert(lock
.is_locked());
923 std::string
normalized_key(ConfFile::normalize_key_name(key
));
924 config_value_t config_value
= _get_val(normalized_key
.c_str());
925 if (!boost::get
<invalid_config_value_t
>(&config_value
)) {
927 if (bool *flag
= boost::get
<bool>(&config_value
)) {
928 oss
<< (*flag
? "true" : "false");
938 int md_config_t::_get_val(const char *key
, char **buf
, int len
) const
940 assert(lock
.is_locked());
945 string
k(ConfFile::normalize_key_name(key
));
947 config_value_t cval
= _get_val(k
.c_str());
948 if (!boost::get
<invalid_config_value_t
>(&cval
)) {
950 if (bool *flagp
= boost::get
<bool>(&cval
)) {
951 oss
<< (*flagp
? "true" : "false");
955 string
str(oss
.str());
956 int l
= strlen(str
.c_str()) + 1;
958 *buf
= (char*)malloc(l
);
961 strcpy(*buf
, str
.c_str());
964 snprintf(*buf
, len
, "%s", str
.c_str());
965 return (l
> len
) ? -ENAMETOOLONG
: 0;
969 for (int o
= 0; o
< subsys
.get_num(); o
++) {
970 std::string as_option
= "debug_" + subsys
.get_name(o
);
971 if (k
== as_option
) {
973 *buf
= (char*)malloc(20);
976 int l
= snprintf(*buf
, len
, "%d/%d", subsys
.get_log_level(o
), subsys
.get_gather_level(o
));
977 return (l
== len
) ? -ENAMETOOLONG
: 0;
981 // couldn't find a configuration option with key 'k'
985 void md_config_t::get_all_keys(std::vector
<std::string
> *keys
) const {
986 const std::string
negative_flag_prefix("no_");
989 keys
->reserve(config_options
->size());
990 for (auto& opt
: *config_options
) {
991 keys
->push_back(opt
.name
);
992 if (opt
.type
== OPT_BOOL
) {
993 keys
->push_back(negative_flag_prefix
+ opt
.name
);
996 for (int i
= 0; i
< subsys
.get_num(); ++i
) {
997 keys
->push_back("debug_" + subsys
.get_name(i
));
1001 /* The order of the sections here is important. The first section in the
1002 * vector is the "highest priority" section; if we find it there, we'll stop
1003 * looking. The lowest priority section is the one we look in only if all
1004 * others had nothing. This should always be the global section.
1006 void md_config_t::get_my_sections(std::vector
<std::string
> §ions
) const
1008 Mutex::Locker
l(lock
);
1009 _get_my_sections(sections
);
1012 void md_config_t::_get_my_sections(std::vector
<std::string
> §ions
) const
1014 assert(lock
.is_locked());
1015 sections
.push_back(name
.to_str());
1017 sections
.push_back(name
.get_type_name());
1019 sections
.push_back("global");
1022 // Return a list of all sections
1023 int md_config_t::get_all_sections(std::vector
<std::string
> §ions
) const
1025 Mutex::Locker
l(lock
);
1026 for (ConfFile::const_section_iter_t s
= cf
.sections_begin();
1027 s
!= cf
.sections_end(); ++s
) {
1028 sections
.push_back(s
->first
);
1033 int md_config_t::get_val_from_conf_file(const std::vector
<std::string
> §ions
,
1034 const char *key
, std::string
&out
, bool emeta
) const
1036 Mutex::Locker
l(lock
);
1037 return _get_val_from_conf_file(sections
, key
, out
, emeta
);
1040 int md_config_t::_get_val_from_conf_file(const std::vector
<std::string
> §ions
,
1041 const char *key
, std::string
&out
, bool emeta
) const
1043 assert(lock
.is_locked());
1044 std::vector
<std::string
>::const_iterator s
= sections
.begin();
1045 std::vector
<std::string
>::const_iterator s_end
= sections
.end();
1046 for (; s
!= s_end
; ++s
) {
1047 int ret
= cf
.read(s
->c_str(), key
, out
);
1050 expand_meta(out
, &std::cerr
);
1053 else if (ret
!= -ENOENT
)
1059 int md_config_t::set_val_impl(const std::string
&val
, config_option
const *opt
,
1060 std::string
*error_message
)
1062 assert(lock
.is_locked());
1063 std::string
value(val
);
1064 if (opt
->validator
) {
1065 int r
= opt
->validator(&value
, error_message
);
1071 int ret
= set_val_raw(value
.c_str(), opt
);
1074 changed
.insert(opt
->name
);
1078 template<typename T
> struct strtox_helper
;
1080 template<> struct strtox_helper
<float> {
1081 static inline void apply(const char *val
, float &x
, std::string
&err
) {
1082 x
= strict_strtof(val
, &err
);
1086 template<> struct strtox_helper
<double> {
1087 static inline void apply(const char *val
, double &x
, std::string
&err
) {
1088 x
= strict_strtod(val
, &err
);
1092 template<typename T
> static inline int strict_strtox(const char *val
, T
&x
) {
1094 strtox_helper
<T
>::apply(val
, x
, err
);
1095 return err
.empty() ? 0 : -EINVAL
;
1098 class set_value_visitor
: public boost::static_visitor
<int> {
1099 md_config_t
const *conf
;
1102 explicit set_value_visitor(md_config_t
const *conf_
, const char *val_
) :
1103 conf(conf_
), val(val_
) { }
1105 int operator()(const std::string
md_config_t::* member_ptr
) {
1106 auto *ptr
= const_cast<std::string
*>(&(conf
->*member_ptr
));
1107 *ptr
= val
? val
: "";
1111 int operator()(const bool md_config_t::* member_ptr
) {
1112 bool *ptr
= const_cast<bool *>(&(conf
->*member_ptr
));
1113 if (strcasecmp(val
, "false") == 0) {
1115 } else if (strcasecmp(val
, "true") == 0) {
1119 int b
= strict_strtol(val
, 10, &err
);
1128 // type has parse() member function
1129 template<typename T
,
1130 typename
boost::enable_if
<boost::is_member_function_pointer
<decltype(&T::parse
)>, int>::type
= 0>
1131 int operator()(const T
md_config_t::* member_ptr
) {
1132 T
*obj
= const_cast<T
*>(&(conf
->*member_ptr
));
1133 if (!obj
->parse(val
)) {
1140 template<typename T
,
1141 typename
boost::enable_if
<boost::is_floating_point
<T
>, int>::type
= 0>
1142 int operator()(const T
md_config_t::* member_ptr
) {
1143 T
* ptr
= const_cast<T
*>(&(conf
->*member_ptr
));
1144 return strict_strtox(val
, *ptr
);
1148 template<typename T
,
1149 typename
boost::enable_if_c
<boost::is_integral
<T
>::value
&&
1150 !boost::is_same
<T
, bool>::value
, int>::type
= 0>
1151 int operator()(const T
md_config_t::* member_ptr
) {
1153 T f
= strict_si_cast
<T
>(val
, &err
);
1157 T
*ptr
= const_cast<T
*>(&(conf
->*member_ptr
));
1163 int md_config_t::set_val_raw(const char *val
, config_option
const *opt
)
1165 assert(lock
.is_locked());
1166 set_value_visitor
svv(this, val
);
1167 return boost::apply_visitor(svv
, opt
->md_member_ptr
);
1170 static const char *CONF_METAVARIABLES
[] = {
1171 "data_dir", // put this first: it may contain some of the others
1172 "cluster", "type", "name", "host", "num", "id", "pid", "cctid"
1174 static const int NUM_CONF_METAVARIABLES
=
1175 (sizeof(CONF_METAVARIABLES
) / sizeof(CONF_METAVARIABLES
[0]));
1177 void md_config_t::expand_all_meta()
1179 // Expand all metavariables
1181 for (auto& opt
: *config_options
) {
1183 opt
.conf_ptr(str
, this);
1185 list
<config_option
const *> stack
;
1186 expand_meta(*str
, &opt
, stack
, &oss
);
1192 bool md_config_t::expand_meta(std::string
&origval
,
1193 std::ostream
*oss
) const
1195 list
<config_option
const *> stack
;
1196 return expand_meta(origval
, NULL
, stack
, oss
);
1199 bool md_config_t::expand_meta(std::string
&origval
,
1200 config_option
const *opt
,
1201 std::list
<config_option
const *> stack
,
1202 std::ostream
*oss
) const
1204 assert(lock
.is_locked());
1206 // no $ means no variable expansion is necessary
1207 if (origval
.find("$") == string::npos
)
1210 // ignore an expansion loop and create a human readable
1213 for (list
<config_option
const *>::iterator i
= stack
.begin();
1216 if (strcmp(opt
->name
, (*i
)->name
) == 0) {
1217 *oss
<< "variable expansion loop at "
1218 << opt
->name
<< "=" << origval
<< std::endl
;
1219 *oss
<< "expansion stack: " << std::endl
;
1220 for (list
<config_option
const *>::iterator j
= stack
.begin();
1223 *oss
<< (*j
)->name
<< "=" << *((*j
)->conf_ptr
<std::string
>(this)) << std::endl
;
1231 stack
.push_front(opt
);
1233 bool found_meta
= false;
1235 string val
= origval
;
1236 for (string::size_type s
= 0; s
< val
.size(); ) {
1237 if (val
[s
] != '$') {
1242 // try to parse the variable name into var, either \$\{(.+)\} or
1244 const char *valid_chars
= "abcdefghijklmnopqrstuvwxyz_";
1247 if (val
[s
+1] == '{') {
1249 endpos
= val
.find_first_not_of(valid_chars
, s
+2);
1250 if (endpos
!= std::string::npos
&&
1251 val
[endpos
] == '}') {
1252 var
= val
.substr(s
+2, endpos
-s
-2);
1257 endpos
= val
.find_first_not_of(valid_chars
, s
+1);
1258 if (endpos
!= std::string::npos
)
1259 var
= val
.substr(s
+1, endpos
-s
-1);
1261 var
= val
.substr(s
+1);
1264 bool expanded
= false;
1266 // special metavariable?
1267 for (int i
= 0; i
< NUM_CONF_METAVARIABLES
; ++i
) {
1268 if (var
!= CONF_METAVARIABLES
[i
])
1270 //cout << " meta match of " << var << " " << CONF_METAVARIABLES[i] << std::endl;
1272 out
+= name
.get_type_name();
1273 else if (var
== "cluster")
1275 else if (var
== "name")
1276 out
+= name
.to_cstr();
1277 else if (var
== "host")
1280 out
+= ceph_get_short_hostname();
1284 else if (var
== "num")
1285 out
+= name
.get_id().c_str();
1286 else if (var
== "id")
1287 out
+= name
.get_id().c_str();
1288 else if (var
== "pid")
1289 out
+= stringify(getpid());
1290 else if (var
== "cctid")
1291 out
+= stringify((unsigned long long)this);
1292 else if (var
== "data_dir") {
1293 if (data_dir_option
.length()) {
1295 _get_val(data_dir_option
.c_str(), &vv
, -1);
1298 expand_meta(tmp
, NULL
, stack
, oss
);
1301 // this isn't really right, but it'll result in a mangled
1302 // non-existent path that will fail any search list
1306 ceph_abort(); // unreachable
1312 for (auto& opt
: *config_options
) {
1313 if (var
== opt
.name
) {
1315 opt
.conf_ptr(origval
, const_cast<md_config_t
*>(this));
1317 expand_meta(*origval
, &opt
, stack
, oss
);
1321 _get_val(opt
.name
, &vv
, -1);
1339 // override the original value with the expanded value
1344 void md_config_t::diff(
1345 const md_config_t
*other
,
1346 map
<string
,pair
<string
,string
> > *diff
,
1347 set
<string
> *unknown
)
1349 Mutex::Locker
l(lock
);
1351 char local_buf
[4096];
1352 char other_buf
[4096];
1353 for (auto& opt
: *config_options
) {
1354 memset(local_buf
, 0, sizeof(local_buf
));
1355 memset(other_buf
, 0, sizeof(other_buf
));
1357 char *other_val
= other_buf
;
1358 int err
= other
->get_val(opt
.name
, &other_val
, sizeof(other_buf
));
1360 if (err
== -ENOENT
) {
1361 unknown
->insert(opt
.name
);
1366 char *local_val
= local_buf
;
1367 err
= _get_val(opt
.name
, &local_val
, sizeof(local_buf
));
1371 if (strcmp(local_val
, other_val
))
1372 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
);