X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fcommon%2Fconfig.cc;fp=src%2Fceph%2Fsrc%2Fcommon%2Fconfig.cc;h=0000000000000000000000000000000000000000;hb=7da45d65be36d36b880cc55c5036e96c24b53f00;hp=3cbb27e3484c043788d3412786c7a48b9908cea8;hpb=691462d09d0987b47e112d6ee8740375df3c51b2;p=stor4nfv.git diff --git a/src/ceph/src/common/config.cc b/src/ceph/src/common/config.cc deleted file mode 100644 index 3cbb27e..0000000 --- a/src/ceph/src/common/config.cc +++ /dev/null @@ -1,1380 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2004-2006 Sage Weil - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include "common/ceph_argparse.h" -#include "common/common_init.h" -#include "common/config.h" -#include "include/str_list.h" -#include "include/stringify.h" -#include "osd/osd_types.h" -#include "common/errno.h" -#include "common/hostname.h" - -#include - -/* Don't use standard Ceph logging in this file. - * We can't use logging until it's initialized, and a lot of the necessary - * initialization happens here. - */ -#undef dout -#undef ldout -#undef pdout -#undef derr -#undef lderr -#undef generic_dout -#undef dendl - -using std::map; -using std::list; -using std::ostringstream; -using std::pair; -using std::string; - -const char *CEPH_CONF_FILE_DEFAULT = "$data_dir/config, /etc/ceph/$cluster.conf, ~/.ceph/$cluster.conf, $cluster.conf" -#if defined(__FreeBSD__) - ", /usr/local/etc/ceph/$cluster.conf" -#endif - ; - -#define _STR(x) #x -#define STRINGIFY(x) _STR(x) - -int ceph_resolve_file_search(const std::string& filename_list, - std::string& result) -{ - list ls; - get_str_list(filename_list, ls); - - int ret = -ENOENT; - list::iterator iter; - for (iter = ls.begin(); iter != ls.end(); ++iter) { - int fd = ::open(iter->c_str(), O_RDONLY); - if (fd < 0) { - ret = -errno; - continue; - } - close(fd); - result = *iter; - return 0; - } - - return ret; -} - - - -md_config_t::md_config_t(bool is_daemon) - : cluster(""), - lock("md_config_t", true, false) -{ - init_subsys(); - - // Load the compile-time list of Option into - // a map so that we can resolve keys quickly. - for (const auto &i : ceph_options) { - if (schema.count(i.name)) { - // We may be instantiated pre-logging so send - std::cerr << "Duplicate config key in schema: '" << i.name << "'" - << std::endl; - assert(false); - } - schema.insert({i.name, i}); - } - - // Populate list of legacy_values according to the OPTION() definitions - // Note that this is just setting up our map of name->member ptr. The - // default values etc will get loaded in along with new-style data, - // as all loads write to both the values map, and the legacy - // members if present. - legacy_values = { -#define OPTION(name, type) \ - {std::string(STRINGIFY(name)), &md_config_t::name}, -#define SAFE_OPTION(name, type) OPTION(name, type) -#include "common/legacy_config_opts.h" -#undef OPTION -#undef SAFE_OPTION - }; - - validate_schema(); - - // Load default values from the schema - for (const auto &i : schema) { - const Option &opt = i.second; - bool has_daemon_default = !boost::get(&opt.daemon_value); - Option::value_t default_val; - if (is_daemon && has_daemon_default) { - default_val = opt.daemon_value; - } else { - default_val = opt.value; - } - - if (opt.type == Option::TYPE_STR) { - // We call pre_validate as a sanity check, but also to get any - // side effect (value modification) from the validator. - std::string *def_str = boost::get(&default_val); - std::string err; - if (opt.pre_validate(def_str, &err) != 0) { - std::cerr << "Default value " << opt.name << "=" << *def_str << " is " - "invalid: " << err << std::endl; - - // This is the compiled-in default that is failing its own option's - // validation, so this is super-invalid and should never make it - // past a pull request: crash out. - assert(false); - } - } - - values[i.first] = default_val; - } - - // Copy out values (defaults) into any legacy (C struct member) fields - for (const auto &i : legacy_values) { - const auto &name = i.first; - const auto &option = schema.at(name); - auto ptr = i.second; - - update_legacy_val(option, ptr); - } -} - -/** - * Sanity check schema. Assert out on failures, to ensure any bad changes - * cannot possibly pass any testing and make it into a release. - */ -void md_config_t::validate_schema() -{ - for (const auto &i : schema) { - const auto &opt = i.second; - for (const auto &see_also_key : opt.see_also) { - if (schema.count(see_also_key) == 0) { - std::cerr << "Non-existent see-also key '" << see_also_key - << "' on option '" << opt.name << "'" << std::endl; - assert(false); - } - } - } - - for (const auto &i : legacy_values) { - if (schema.count(i.first) == 0) { - std::cerr << "Schema is missing legacy field '" << i.first << "'" - << std::endl; - assert(false); - } - } -} - -void md_config_t::init_subsys() -{ -#define SUBSYS(name, log, gather) \ - subsys.add(ceph_subsys_##name, STRINGIFY(name), log, gather); -#define DEFAULT_SUBSYS(log, gather) \ - subsys.add(ceph_subsys_, "none", log, gather); -#include "common/subsys.h" -#undef SUBSYS -#undef DEFAULT_SUBSYS -} - -md_config_t::~md_config_t() -{ -} - -void md_config_t::add_observer(md_config_obs_t* observer_) -{ - Mutex::Locker l(lock); - const char **keys = observer_->get_tracked_conf_keys(); - for (const char ** k = keys; *k; ++k) { - obs_map_t::value_type val(*k, observer_); - observers.insert(val); - } -} - -void md_config_t::remove_observer(md_config_obs_t* observer_) -{ - Mutex::Locker l(lock); - bool found_obs = false; - for (obs_map_t::iterator o = observers.begin(); o != observers.end(); ) { - if (o->second == observer_) { - observers.erase(o++); - found_obs = true; - } - else { - ++o; - } - } - assert(found_obs); -} - -int md_config_t::parse_config_files(const char *conf_files, - std::ostream *warnings, - int flags) -{ - Mutex::Locker l(lock); - - if (internal_safe_to_start_threads) - return -ENOSYS; - - if (!cluster.size() && !conf_files) { - /* - * set the cluster name to 'ceph' when neither cluster name nor - * configuration file are specified. - */ - cluster = "ceph"; - } - - if (!conf_files) { - const char *c = getenv("CEPH_CONF"); - if (c) { - conf_files = c; - } - else { - if (flags & CINIT_FLAG_NO_DEFAULT_CONFIG_FILE) - return 0; - conf_files = CEPH_CONF_FILE_DEFAULT; - } - } - - std::list cfl; - get_str_list(conf_files, cfl); - - auto p = cfl.begin(); - while (p != cfl.end()) { - // expand $data_dir? - string &s = *p; - if (s.find("$data_dir") != string::npos) { - if (data_dir_option.length()) { - list stack; - expand_meta(s, NULL, stack, warnings); - p++; - } else { - cfl.erase(p++); // ignore this item - } - } else { - ++p; - } - } - return parse_config_files_impl(cfl, warnings); -} - -int md_config_t::parse_config_files_impl(const std::list &conf_files, - std::ostream *warnings) -{ - assert(lock.is_locked()); - - // open new conf - list::const_iterator c; - for (c = conf_files.begin(); c != conf_files.end(); ++c) { - cf.clear(); - string fn = *c; - expand_meta(fn, warnings); - int ret = cf.parse_file(fn.c_str(), &parse_errors, warnings); - if (ret == 0) - break; - else if (ret != -ENOENT) - return ret; - } - // it must have been all ENOENTs, that's the only way we got here - if (c == conf_files.end()) - return -ENOENT; - - if (cluster.size() == 0) { - /* - * If cluster name is not set yet, use the prefix of the - * basename of configuration file as cluster name. - */ - auto start = c->rfind('/') + 1; - auto end = c->find(".conf", start); - if (end == c->npos) { - /* - * If the configuration file does not follow $cluster.conf - * convention, we do the last try and assign the cluster to - * 'ceph'. - */ - cluster = "ceph"; - } else { - cluster = c->substr(start, end - start); - } - } - - std::vector my_sections; - _get_my_sections(my_sections); - for (const auto &i : schema) { - const auto &opt = i.second; - std::string val; - int ret = _get_val_from_conf_file(my_sections, opt.name, val, false); - if (ret == 0) { - std::string error_message; - int r = set_val_impl(val, opt, &error_message); - if (warnings != nullptr && (r != 0 || !error_message.empty())) { - *warnings << "parse error setting '" << opt.name << "' to '" << val - << "'"; - if (!error_message.empty()) { - *warnings << " (" << error_message << ")"; - } - *warnings << std::endl; - } - } - } - - // subsystems? - for (size_t o = 0; o < subsys.get_num(); o++) { - std::string as_option("debug_"); - as_option += subsys.get_name(o); - std::string val; - int ret = _get_val_from_conf_file(my_sections, as_option.c_str(), val, false); - if (ret == 0) { - int log, gather; - int r = sscanf(val.c_str(), "%d/%d", &log, &gather); - if (r >= 1) { - if (r < 2) - gather = log; - // cout << "config subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl; - subsys.set_log_level(o, log); - subsys.set_gather_level(o, gather); - } - } - } - - // Warn about section names that look like old-style section names - std::deque < std::string > old_style_section_names; - for (ConfFile::const_section_iter_t s = cf.sections_begin(); - s != cf.sections_end(); ++s) { - const string &str(s->first); - if (((str.find("mds") == 0) || (str.find("mon") == 0) || - (str.find("osd") == 0)) && (str.size() > 3) && (str[3] != '.')) { - old_style_section_names.push_back(str); - } - } - if (!old_style_section_names.empty()) { - ostringstream oss; - cerr << "ERROR! old-style section name(s) found: "; - string sep; - for (std::deque < std::string >::const_iterator os = old_style_section_names.begin(); - os != old_style_section_names.end(); ++os) { - cerr << sep << *os; - sep = ", "; - } - cerr << ". Please use the new style section names that include a period."; - } - return 0; -} - -void md_config_t::parse_env() -{ - Mutex::Locker l(lock); - if (internal_safe_to_start_threads) - return; - if (getenv("CEPH_KEYRING")) { - set_val_or_die("keyring", getenv("CEPH_KEYRING")); - } -} - -void md_config_t::show_config(std::ostream& out) -{ - Mutex::Locker l(lock); - _show_config(&out, NULL); -} - -void md_config_t::show_config(Formatter *f) -{ - Mutex::Locker l(lock); - _show_config(NULL, f); -} - -void md_config_t::_show_config(std::ostream *out, Formatter *f) -{ - if (out) { - *out << "name = " << name << std::endl; - *out << "cluster = " << cluster << std::endl; - } - if (f) { - f->dump_string("name", stringify(name)); - f->dump_string("cluster", cluster); - } - for (size_t o = 0; o < subsys.get_num(); o++) { - if (out) - *out << "debug_" << subsys.get_name(o) - << " = " << subsys.get_log_level(o) - << "/" << subsys.get_gather_level(o) << std::endl; - if (f) { - ostringstream ss; - std::string debug_name = "debug_"; - debug_name += subsys.get_name(o); - ss << subsys.get_log_level(o) - << "/" << subsys.get_gather_level(o); - f->dump_string(debug_name.c_str(), ss.str()); - } - } - for (const auto& i: schema) { - const Option &opt = i.second; - char *buf; - _get_val(opt.name, &buf, -1); - if (out) - *out << opt.name << " = " << buf << std::endl; - if (f) - f->dump_string(opt.name.c_str(), buf); - free(buf); - } -} - -int md_config_t::parse_argv(std::vector& args) -{ - Mutex::Locker l(lock); - if (internal_safe_to_start_threads) { - return -ENOSYS; - } - - bool show_config = false; - bool show_config_value = false; - string show_config_value_arg; - - // In this function, don't change any parts of the configuration directly. - // Instead, use set_val to set them. This will allow us to send the proper - // observer notifications later. - std::string val; - for (std::vector::iterator i = args.begin(); i != args.end(); ) { - if (strcmp(*i, "--") == 0) { - /* Normally we would use ceph_argparse_double_dash. However, in this - * function we *don't* want to remove the double dash, because later - * argument parses will still need to see it. */ - break; - } - else if (ceph_argparse_flag(args, i, "--show_conf", (char*)NULL)) { - cerr << cf << std::endl; - _exit(0); - } - else if (ceph_argparse_flag(args, i, "--show_config", (char*)NULL)) { - show_config = true; - } - else if (ceph_argparse_witharg(args, i, &val, "--show_config_value", (char*)NULL)) { - show_config_value = true; - show_config_value_arg = val; - } - else if (ceph_argparse_flag(args, i, "--foreground", "-f", (char*)NULL)) { - set_val_or_die("daemonize", "false"); - } - else if (ceph_argparse_flag(args, i, "-d", (char*)NULL)) { - set_val_or_die("daemonize", "false"); - set_val_or_die("log_file", ""); - set_val_or_die("log_to_stderr", "true"); - set_val_or_die("err_to_stderr", "true"); - set_val_or_die("log_to_syslog", "false"); - } - // Some stuff that we wanted to give universal single-character options for - // Careful: you can burn through the alphabet pretty quickly by adding - // to this list. - else if (ceph_argparse_witharg(args, i, &val, "--monmap", "-M", (char*)NULL)) { - set_val_or_die("monmap", val.c_str()); - } - else if (ceph_argparse_witharg(args, i, &val, "--mon_host", "-m", (char*)NULL)) { - set_val_or_die("mon_host", val.c_str()); - } - else if (ceph_argparse_witharg(args, i, &val, "--bind", (char*)NULL)) { - set_val_or_die("public_addr", val.c_str()); - } - else if (ceph_argparse_witharg(args, i, &val, "--keyfile", "-K", (char*)NULL)) { - set_val_or_die("keyfile", val.c_str()); - } - else if (ceph_argparse_witharg(args, i, &val, "--keyring", "-k", (char*)NULL)) { - set_val_or_die("keyring", val.c_str()); - } - else if (ceph_argparse_witharg(args, i, &val, "--client_mountpoint", "-r", (char*)NULL)) { - set_val_or_die("client_mountpoint", val.c_str()); - } - else { - int r = parse_option(args, i, NULL); - if (r < 0) { - return r; - } - } - } - - if (show_config) { - expand_all_meta(); - _show_config(&cout, NULL); - _exit(0); - } - - if (show_config_value) { - char *buf = 0; - int r = _get_val(show_config_value_arg.c_str(), &buf, -1); - if (r < 0) { - if (r == -ENOENT) - std::cerr << "failed to get config option '" << - show_config_value_arg << "': option not found" << std::endl; - else - std::cerr << "failed to get config option '" << - show_config_value_arg << "': " << cpp_strerror(r) << std::endl; - _exit(1); - } - string s = buf; - expand_meta(s, &std::cerr); - std::cout << s << std::endl; - _exit(0); - } - - return 0; -} - -int md_config_t::parse_option(std::vector& args, - std::vector::iterator& i, - ostream *oss) -{ - int ret = 0; - size_t o = 0; - std::string val; - - // subsystems? - for (o = 0; o < subsys.get_num(); o++) { - std::string as_option("--"); - as_option += "debug_"; - as_option += subsys.get_name(o); - ostringstream err; - if (ceph_argparse_witharg(args, i, &val, err, - as_option.c_str(), (char*)NULL)) { - if (err.tellp()) { - if (oss) { - *oss << err.str(); - } - ret = -EINVAL; - break; - } - int log, gather; - int r = sscanf(val.c_str(), "%d/%d", &log, &gather); - if (r >= 1) { - if (r < 2) - gather = log; - // cout << "subsys " << subsys.get_name(o) << " log " << log << " gather " << gather << std::endl; - subsys.set_log_level(o, log); - subsys.set_gather_level(o, gather); - if (oss) - *oss << "debug_" << subsys.get_name(o) << "=" << log << "/" << gather << " "; - } - break; - } - } - if (o < subsys.get_num()) { - return ret; - } - - std::string option_name; - std::string error_message; - o = 0; - for (const auto& opt_iter: schema) { - const Option &opt = opt_iter.second; - ostringstream err; - std::string as_option("--"); - as_option += opt.name; - option_name = opt.name; - if (opt.type == Option::TYPE_BOOL) { - int res; - if (ceph_argparse_binary_flag(args, i, &res, oss, as_option.c_str(), - (char*)NULL)) { - if (res == 0) - ret = set_val_impl("false", opt, &error_message); - else if (res == 1) - ret = set_val_impl("true", opt, &error_message); - else - ret = res; - break; - } else { - std::string no("--no-"); - no += opt.name; - if (ceph_argparse_flag(args, i, no.c_str(), (char*)NULL)) { - ret = set_val_impl("false", opt, &error_message); - break; - } - } - } else if (ceph_argparse_witharg(args, i, &val, err, - as_option.c_str(), (char*)NULL)) { - if (!err.str().empty()) { - error_message = err.str(); - ret = -EINVAL; - break; - } - if (oss && ((!opt.is_safe()) && - (observers.find(opt.name) == observers.end()))) { - *oss << "You cannot change " << opt.name << " using injectargs.\n"; - return -ENOSYS; - } - ret = set_val_impl(val, opt, &error_message); - break; - } - ++o; - } - - if (ret != 0 || !error_message.empty()) { - assert(!option_name.empty()); - if (oss) { - *oss << "Parse error setting " << option_name << " to '" - << val << "' using injectargs"; - if (!error_message.empty()) { - *oss << " (" << error_message << ")"; - } - *oss << ".\n"; - } else { - cerr << "parse error setting '" << option_name << "' to '" - << val << "'"; - if (!error_message.empty()) { - cerr << " (" << error_message << ")"; - } - cerr << "\n" << std::endl; - } - } - - if (o == schema.size()) { - // ignore - ++i; - } - return ret; -} - -int md_config_t::parse_injectargs(std::vector& args, - std::ostream *oss) -{ - assert(lock.is_locked()); - int ret = 0; - for (std::vector::iterator i = args.begin(); i != args.end(); ) { - int r = parse_option(args, i, oss); - if (r < 0) - ret = r; - } - return ret; -} - -void md_config_t::apply_changes(std::ostream *oss) -{ - Mutex::Locker l(lock); - /* - * apply changes until the cluster name is assigned - */ - if (cluster.size()) - _apply_changes(oss); -} - -bool md_config_t::_internal_field(const string& s) -{ - if (s == "internal_safe_to_start_threads") - return true; - return false; -} - -void md_config_t::_apply_changes(std::ostream *oss) -{ - /* Maps observers to the configuration options that they care about which - * have changed. */ - typedef std::map < md_config_obs_t*, std::set > rev_obs_map_t; - - expand_all_meta(); - - // expand_all_meta could have modified anything. Copy it all out again. - for (const auto &i : legacy_values) { - const auto &name = i.first; - const auto &option = schema.at(name); - auto ptr = i.second; - - update_legacy_val(option, ptr); - } - - // create the reverse observer mapping, mapping observers to the set of - // changed keys that they'll get. - rev_obs_map_t robs; - std::set empty_set; - char buf[128]; - char *bufptr = (char*)buf; - for (changed_set_t::const_iterator c = changed.begin(); - c != changed.end(); ++c) { - const std::string &key(*c); - pair < obs_map_t::iterator, obs_map_t::iterator > - range(observers.equal_range(key)); - if ((oss) && - (!_get_val(key.c_str(), &bufptr, sizeof(buf))) && - !_internal_field(key)) { - (*oss) << key << " = '" << buf << "' "; - if (range.first == range.second) { - (*oss) << "(not observed, change may require restart) "; - } - } - for (obs_map_t::iterator r = range.first; r != range.second; ++r) { - rev_obs_map_t::value_type robs_val(r->second, empty_set); - pair < rev_obs_map_t::iterator, bool > robs_ret(robs.insert(robs_val)); - std::set &keys(robs_ret.first->second); - keys.insert(key); - } - } - - changed.clear(); - - // Make any pending observer callbacks - for (rev_obs_map_t::const_iterator r = robs.begin(); r != robs.end(); ++r) { - md_config_obs_t *obs = r->first; - obs->handle_conf_change(this, r->second); - } - -} - -void md_config_t::call_all_observers() -{ - std::map > obs; - { - Mutex::Locker l(lock); - - expand_all_meta(); - - for (auto r = observers.begin(); r != observers.end(); ++r) { - obs[r->second].insert(r->first); - } - } - for (auto p = obs.begin(); - p != obs.end(); - ++p) { - p->first->handle_conf_change(this, p->second); - } -} - -int md_config_t::injectargs(const std::string& s, std::ostream *oss) -{ - int ret; - Mutex::Locker l(lock); - char b[s.length()+1]; - strcpy(b, s.c_str()); - std::vector nargs; - char *p = b; - while (*p) { - nargs.push_back(p); - while (*p && *p != ' ') p++; - if (!*p) - break; - *p++ = 0; - while (*p && *p == ' ') p++; - } - ret = parse_injectargs(nargs, oss); - if (!nargs.empty()) { - *oss << " failed to parse arguments: "; - std::string prefix; - for (std::vector::const_iterator i = nargs.begin(); - i != nargs.end(); ++i) { - *oss << prefix << *i; - prefix = ","; - } - *oss << "\n"; - ret = -EINVAL; - } - _apply_changes(oss); - return ret; -} - -void md_config_t::set_val_or_die(const std::string &key, - const std::string &val, - bool meta) -{ - std::stringstream err; - int ret = set_val(key, val, meta, &err); - if (ret != 0) { - std::cerr << "set_val_or_die(" << key << "): " << err.str(); - } - assert(ret == 0); -} - -int md_config_t::set_val(const std::string &key, const char *val, - bool meta, std::stringstream *err_ss) -{ - Mutex::Locker l(lock); - if (key.empty()) { - if (err_ss) *err_ss << "No key specified"; - return -EINVAL; - } - if (!val) { - return -EINVAL; - } - - std::string v(val); - if (meta) - expand_meta(v, &std::cerr); - - string k(ConfFile::normalize_key_name(key)); - - // subsystems? - if (strncmp(k.c_str(), "debug_", 6) == 0) { - for (size_t o = 0; o < subsys.get_num(); o++) { - std::string as_option = "debug_" + subsys.get_name(o); - if (k == as_option) { - int log, gather; - int r = sscanf(v.c_str(), "%d/%d", &log, &gather); - if (r >= 1) { - if (r < 2) { - gather = log; - } - subsys.set_log_level(o, log); - subsys.set_gather_level(o, gather); - if (err_ss) *err_ss << "Set " << k << " to " << log << "/" << gather; - return 0; - } - if (err_ss) { - *err_ss << "Invalid debug level, should be or /"; - } - return -EINVAL; - } - } - } - - const auto &opt_iter = schema.find(k); - if (opt_iter != schema.end()) { - const Option &opt = opt_iter->second; - if ((!opt.is_safe()) && internal_safe_to_start_threads) { - // If threads have been started and the option is not thread safe - if (observers.find(opt.name) == observers.end()) { - // And there is no observer to safely change it... - // You lose. - if (err_ss) *err_ss << "Configuration option '" << key << "' may " - "not be modified at runtime"; - return -ENOSYS; - } - } - - std::string error_message; - int r = set_val_impl(v, opt, &error_message); - if (r == 0) { - if (err_ss) *err_ss << "Set " << opt.name << " to " << v; - } else { - if (err_ss) *err_ss << error_message; - } - return r; - } - - if (err_ss) *err_ss << "Configuration option not found: '" << key << "'"; - return -ENOENT; -} - - -int md_config_t::get_val(const std::string &key, char **buf, int len) const -{ - Mutex::Locker l(lock); - return _get_val(key, buf,len); -} - -Option::value_t md_config_t::get_val_generic(const std::string &key) const -{ - Mutex::Locker l(lock); - return _get_val(key); -} - -Option::value_t md_config_t::_get_val(const std::string &key) const -{ - assert(lock.is_locked()); - - if (key.empty()) { - return Option::value_t(boost::blank()); - } - - // In key names, leading and trailing whitespace are not significant. - string k(ConfFile::normalize_key_name(key)); - - const auto &opt_iter = schema.find(k); - if (opt_iter != schema.end()) { - // Using .at() is safe because all keys in the schema always have - // entries in ::values - return values.at(k); - } else { - return Option::value_t(boost::blank()); - } -} - -int md_config_t::_get_val(const std::string &key, std::string *value) const { - assert(lock.is_locked()); - - std::string normalized_key(ConfFile::normalize_key_name(key)); - Option::value_t config_value = _get_val(normalized_key.c_str()); - if (!boost::get(&config_value)) { - ostringstream oss; - if (bool *flag = boost::get(&config_value)) { - oss << (*flag ? "true" : "false"); - } else if (double *dp = boost::get(&config_value)) { - oss << std::fixed << *dp; - } else { - oss << config_value; - } - *value = oss.str(); - return 0; - } - return -ENOENT; -} - -int md_config_t::_get_val(const std::string &key, char **buf, int len) const -{ - assert(lock.is_locked()); - - if (key.empty()) - return -EINVAL; - - string val ; - if (_get_val(key, &val) == 0) { - int l = val.length() + 1; - if (len == -1) { - *buf = (char*)malloc(l); - if (!*buf) - return -ENOMEM; - strncpy(*buf, val.c_str(), l); - return 0; - } - snprintf(*buf, len, "%s", val.c_str()); - return (l > len) ? -ENAMETOOLONG : 0; - } - - string k(ConfFile::normalize_key_name(key)); - // subsys? - for (size_t o = 0; o < subsys.get_num(); o++) { - std::string as_option = "debug_" + subsys.get_name(o); - if (k == as_option) { - if (len == -1) { - *buf = (char*)malloc(20); - len = 20; - } - int l = snprintf(*buf, len, "%d/%d", subsys.get_log_level(o), subsys.get_gather_level(o)); - return (l == len) ? -ENAMETOOLONG : 0; - } - } - - // couldn't find a configuration option with key 'k' - return -ENOENT; -} - -void md_config_t::get_all_keys(std::vector *keys) const { - const std::string negative_flag_prefix("no_"); - - keys->clear(); - keys->reserve(schema.size()); - for (const auto &i: schema) { - const Option &opt = i.second; - keys->push_back(opt.name); - if (opt.type == Option::TYPE_BOOL) { - keys->push_back(negative_flag_prefix + opt.name); - } - } - for (size_t i = 0; i < subsys.get_num(); ++i) { - keys->push_back("debug_" + subsys.get_name(i)); - } -} - -/* The order of the sections here is important. The first section in the - * vector is the "highest priority" section; if we find it there, we'll stop - * looking. The lowest priority section is the one we look in only if all - * others had nothing. This should always be the global section. - */ -void md_config_t::get_my_sections(std::vector §ions) const -{ - Mutex::Locker l(lock); - _get_my_sections(sections); -} - -void md_config_t::_get_my_sections(std::vector §ions) const -{ - assert(lock.is_locked()); - sections.push_back(name.to_str()); - - sections.push_back(name.get_type_name()); - - sections.push_back("global"); -} - -// Return a list of all sections -int md_config_t::get_all_sections(std::vector §ions) const -{ - Mutex::Locker l(lock); - for (ConfFile::const_section_iter_t s = cf.sections_begin(); - s != cf.sections_end(); ++s) { - sections.push_back(s->first); - } - return 0; -} - -int md_config_t::get_val_from_conf_file(const std::vector §ions, - const std::string &key, std::string &out, bool emeta) const -{ - Mutex::Locker l(lock); - return _get_val_from_conf_file(sections, key, out, emeta); -} - -int md_config_t::_get_val_from_conf_file(const std::vector §ions, - const std::string &key, std::string &out, bool emeta) const -{ - assert(lock.is_locked()); - std::vector ::const_iterator s = sections.begin(); - std::vector ::const_iterator s_end = sections.end(); - for (; s != s_end; ++s) { - int ret = cf.read(s->c_str(), key, out); - if (ret == 0) { - if (emeta) - expand_meta(out, &std::cerr); - return 0; - } - else if (ret != -ENOENT) - return ret; - } - return -ENOENT; -} - -int md_config_t::set_val_impl(const std::string &raw_val, const Option &opt, - std::string *error_message) -{ - assert(lock.is_locked()); - - std::string val = raw_val; - - int r = opt.pre_validate(&val, error_message); - if (r != 0) { - return r; - } - - Option::value_t new_value; - if (opt.type == Option::TYPE_INT) { - int64_t f = strict_si_cast(val.c_str(), error_message); - if (!error_message->empty()) { - return -EINVAL; - } - new_value = f; - } else if (opt.type == Option::TYPE_UINT) { - uint64_t f = strict_si_cast(val.c_str(), error_message); - if (!error_message->empty()) { - return -EINVAL; - } - new_value = f; - } else if (opt.type == Option::TYPE_STR) { - new_value = val; - } else if (opt.type == Option::TYPE_FLOAT) { - double f = strict_strtod(val.c_str(), error_message); - if (!error_message->empty()) { - return -EINVAL; - } else { - new_value = f; - } - } else if (opt.type == Option::TYPE_BOOL) { - if (strcasecmp(val.c_str(), "false") == 0) { - new_value = false; - } else if (strcasecmp(val.c_str(), "true") == 0) { - new_value = true; - } else { - int b = strict_strtol(val.c_str(), 10, error_message); - if (!error_message->empty()) { - return -EINVAL; - } - new_value = !!b; - } - } else if (opt.type == Option::TYPE_ADDR) { - entity_addr_t addr; - if (!addr.parse(val.c_str())){ - return -EINVAL; - } - new_value = addr; - } else if (opt.type == Option::TYPE_UUID) { - uuid_d uuid; - if (!uuid.parse(val.c_str())) { - return -EINVAL; - } - new_value = uuid; - } else { - ceph_abort(); - } - - r = opt.validate(new_value, error_message); - if (r != 0) { - return r; - } - - - // Apply the value to its entry in the `values` map - values[opt.name] = new_value; - - // Apply the value to its legacy field, if it has one - auto legacy_ptr_iter = legacy_values.find(std::string(opt.name)); - if (legacy_ptr_iter != legacy_values.end()) { - update_legacy_val(opt, legacy_ptr_iter->second); - } - - changed.insert(opt.name); - return 0; -} - -/** - * Handles assigning from a variant-of-types to a variant-of-pointers-to-types - */ -class assign_visitor : public boost::static_visitor<> -{ - md_config_t *conf; - Option::value_t val; - public: - - assign_visitor(md_config_t *conf_, Option::value_t val_) - : conf(conf_), val(val_) - {} - - template - void operator()( T md_config_t::* ptr) const - { - T *member = const_cast(&(conf->*(boost::get(ptr)))); - - *member = boost::get(val); - } -}; - -void md_config_t::update_legacy_val(const Option &opt, - md_config_t::member_ptr_t member_ptr) -{ - if (boost::get(&values.at(opt.name))) { - // This shouldn't happen, but if it does then just don't even - // try to assign to the legacy field. - return; - } - - boost::apply_visitor(assign_visitor(this, values.at(opt.name)), member_ptr); -} - - -static const char *CONF_METAVARIABLES[] = { - "data_dir", // put this first: it may contain some of the others - "cluster", "type", "name", "host", "num", "id", "pid", "cctid" -}; -static const int NUM_CONF_METAVARIABLES = - (sizeof(CONF_METAVARIABLES) / sizeof(CONF_METAVARIABLES[0])); - -void md_config_t::expand_all_meta() -{ - // Expand all metavariables - ostringstream oss; - for (const auto &i : schema) { - const Option &opt = i.second; - - if (opt.type == Option::TYPE_STR) { - list stack; - std::string *str = boost::get(&(values.at(opt.name))); - assert(str != nullptr); // Non-string values should never get in - expand_meta(*str, &opt, stack, &oss); - } - } - cerr << oss.str(); -} - -bool md_config_t::expand_meta(std::string &val, - std::ostream *oss) const -{ - list stack; - return expand_meta(val, NULL, stack, oss); -} - -bool md_config_t::expand_meta(std::string &origval, - const Option *opt, - std::list stack, - std::ostream *oss) const -{ - assert(lock.is_locked()); - - // no $ means no variable expansion is necessary - if (origval.find("$") == string::npos) - return false; - - // ignore an expansion loop and create a human readable - // message about it - if (opt) { - for (const auto stack_ptr : stack) { - if (opt->name == stack_ptr->name) { - *oss << "variable expansion loop at " - << opt->name << "=" << origval << std::endl; - *oss << "expansion stack: " << std::endl; - for (const auto j : stack) { - std::string val; - _get_val(j->name, &val); - *oss << j->name << "=" << val << std::endl; - } - return false; - } - } - - stack.push_front(opt); - } - - bool found_meta = false; - string out; - string val = origval; - for (string::size_type s = 0; s < val.size(); ) { - if (val[s] != '$') { - out += val[s++]; - continue; - } - - // try to parse the variable name into var, either \$\{(.+)\} or - // \$[a-z\_]+ - const char *valid_chars = "abcdefghijklmnopqrstuvwxyz_"; - string var; - size_t endpos = 0; - if (val[s+1] == '{') { - // ...${foo_bar}... - endpos = val.find_first_not_of(valid_chars, s+2); - if (endpos != std::string::npos && - val[endpos] == '}') { - var = val.substr(s+2, endpos-s-2); - endpos++; - } - } else { - // ...$foo... - endpos = val.find_first_not_of(valid_chars, s+1); - if (endpos != std::string::npos) - var = val.substr(s+1, endpos-s-1); - else - var = val.substr(s+1); - } - - bool expanded = false; - if (var.length()) { - // special metavariable? - for (int i = 0; i < NUM_CONF_METAVARIABLES; ++i) { - if (var != CONF_METAVARIABLES[i]) - continue; - //cout << " meta match of " << var << " " << CONF_METAVARIABLES[i] << std::endl; - if (var == "type") - out += name.get_type_name(); - else if (var == "cluster") - out += cluster; - else if (var == "name") - out += name.to_cstr(); - else if (var == "host") - { - if (host == "") - out += ceph_get_short_hostname(); - else - out += host; - } - else if (var == "num") - out += name.get_id().c_str(); - else if (var == "id") - out += name.get_id().c_str(); - else if (var == "pid") - out += stringify(getpid()); - else if (var == "cctid") - out += stringify((unsigned long long)this); - else if (var == "data_dir") { - if (data_dir_option.length()) { - char *vv = NULL; - _get_val(data_dir_option.c_str(), &vv, -1); - string tmp = vv; - free(vv); - expand_meta(tmp, NULL, stack, oss); - out += tmp; - } else { - // this isn't really right, but it'll result in a mangled - // non-existent path that will fail any search list - out += "$data_dir"; - } - } else - ceph_abort(); // unreachable - expanded = true; - } - - if (!expanded) { - // config option? - const auto other_opt_iter = schema.find(var); - if (other_opt_iter != schema.end()) { - const Option &other_opt = other_opt_iter->second; - if (other_opt.type == Option::TYPE_STR) { - // The referenced option is a string, it may need substitution - // before inserting. - Option::value_t *other_val_ptr = const_cast(&(values.at(other_opt.name))); - std::string *other_opt_val = boost::get(other_val_ptr); - expand_meta(*other_opt_val, &other_opt, stack, oss); - out += *other_opt_val; - } else { - // The referenced option is not a string: retrieve and insert - // its stringized form. - char *vv = NULL; - _get_val(other_opt.name, &vv, -1); - out += vv; - free(vv); - } - expanded = true; - } - } - } - - if (expanded) { - found_meta = true; - s = endpos; - } else { - out += val[s++]; - } - } - // override the original value with the expanded value - origval = out; - return found_meta; -} - -void md_config_t::diff( - const md_config_t *other, - map > *diff, - set *unknown) -{ - diff_helper(other, diff, unknown); -} -void md_config_t::diff( - const md_config_t *other, - map > *diff, - set *unknown, const string& setting) -{ - diff_helper(other, diff, unknown, setting); -} - -void md_config_t::diff_helper( - const md_config_t *other, - map > *diff, - set *unknown, const string& setting) -{ - Mutex::Locker l(lock); - - char local_buf[4096]; - char other_buf[4096]; - for (const auto &i : schema) { - const Option &opt = i.second; - if (!setting.empty()) { - if (setting != opt.name) { - continue; - } - } - memset(local_buf, 0, sizeof(local_buf)); - memset(other_buf, 0, sizeof(other_buf)); - - char *other_val = other_buf; - int err = other->get_val(opt.name, &other_val, sizeof(other_buf)); - if (err < 0) { - if (err == -ENOENT) { - unknown->insert(opt.name); - } - continue; - } - - char *local_val = local_buf; - err = _get_val(opt.name, &local_val, sizeof(local_buf)); - if (err != 0) - continue; - - if (strcmp(local_val, other_val)) - diff->insert(make_pair(opt.name, make_pair(local_val, other_val))); - else if (!setting.empty()) { - diff->insert(make_pair(opt.name, make_pair(local_val, other_val))); - break; - } - } -} - -void md_config_t::complain_about_parse_errors(CephContext *cct) -{ - ::complain_about_parse_errors(cct, &parse_errors); -} -