}
}
-bool md_config_t::expand_meta(std::string &val) const
+bool md_config_t::expand_meta(std::string &origval) const
{
assert(lock.is_locked());
bool found_meta = false;
+
+ set<string> resolved;
+
+ string::size_type sz;
+ string val = origval;
+
+ restart:
+ sz = val.size();
string out;
- string::size_type sz = val.size();
out.reserve(sz);
+
for (string::size_type s = 0; s < sz; ) {
if (val[s] != '$') {
out += val[s++];
continue;
}
string::size_type rem = sz - (s + 1);
- int i;
- for (i = 0; i < NUM_CONF_METAVARIABLES; ++i) {
+
+ // special metavariable?
+ for (int i = 0; i < NUM_CONF_METAVARIABLES; ++i) {
size_t clen = strlen(CONF_METAVARIABLES[i]);
if (rem < clen)
continue;
else
assert(0); // unreachable
found_meta = true;
- break;
- }
- if (i == NUM_CONF_METAVARIABLES)
- out += val[s++];
- else
s += strlen(CONF_METAVARIABLES[i]) + 1;
- }
- val = out;
+ out += val.substr(s);
+ val = out;
+ goto restart;
+ }
+
+ // config option?
+ for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) {
+ config_option *opt = &config_optionsp[i];
+ size_t clen = strlen(opt->name);
+ if (rem < clen)
+ continue;
+ if (strncmp(val.c_str() + s + 1, opt->name, clen))
+ continue;
+
+ // avoid loops
+ if (resolved.count(opt->name))
+ continue; // loop; skip
+ resolved.insert(opt->name);
+
+ found_meta = true;
+ char *vv = NULL;
+ _get_val(opt->name, &vv, -1);
+ out += vv;
+ s += strlen(opt->name) + 1;
+ out += val.substr(s);
+ //cout << "val '" << val << "' s " << s << " out '" << out << "' after sub " << opt->name << " -> " << vv << std::endl;
+ val = out;
+ free(vv);
+ goto restart;
+ }
+
+ // pass it thru
+ out += val[s++];
+ }
+ //cout << "done '" << origval << "' -> '" << out << "'" << std::endl;
+ origval = out;
return found_meta;
}
ASSERT_EQ(string("21"), string(buf));
}
+TEST(DaemonConfig, Substitution) {
+ int ret;
+ ret = g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false");
+ ret = g_ceph_context->_conf->set_val("host", "foo");
+ ASSERT_EQ(ret, 0);
+ ret = g_ceph_context->_conf->set_val("public_network", "bar$hostbaz", false);
+ ASSERT_EQ(ret, 0);
+ g_ceph_context->_conf->apply_changes(NULL);
+ char buf[128];
+ memset(buf, 0, sizeof(buf));
+ char *tmp = buf;
+ ret = g_ceph_context->_conf->get_val("public_network", &tmp, sizeof(buf));
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(string("barfoobaz"), string(buf));
+}
+
+TEST(DaemonConfig, SubstitutionLoop) {
+ int ret;
+ ret = g_ceph_context->_conf->set_val("internal_safe_to_start_threads", "false");
+ ret = g_ceph_context->_conf->set_val("host", "foo$public_network", false);
+ ASSERT_EQ(ret, 0);
+ ret = g_ceph_context->_conf->set_val("public_network", "bar$host", false);
+ ASSERT_EQ(ret, 0);
+ g_ceph_context->_conf->apply_changes(NULL);
+ char buf[128], buf2[128];
+ memset(buf, 0, sizeof(buf));
+ memset(buf2, 0, sizeof(buf2));
+ char *tmp = buf;
+ char *tmp2 = buf;
+ ret = g_ceph_context->_conf->get_val("host", &tmp, sizeof(buf));
+ ASSERT_EQ(ret, 0);
+ ret = g_ceph_context->_conf->get_val("public_network", &tmp2, sizeof(buf));
+ ASSERT_EQ(ret, 0);
+ ASSERT_TRUE(strchr(buf, '$') || strchr(buf2, '$'));
+}
+
TEST(DaemonConfig, ArgV) {
ASSERT_EQ(0, g_ceph_context->_conf->set_val("internal_safe_to_start_threads",
"false"));