| /** @file |
| |
| runroot.cc |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| /* |
| Please refer to traffic_layout document for the usage |
| */ |
| |
| #include "tscore/ink_error.h" |
| #include "tscore/I_Layout.h" |
| #include "tscore/runroot.h" |
| #include <yaml-cpp/yaml.h> |
| |
| static std::string runroot_file = {}; |
| |
| // this is a temporary approach and will be replaced when std::filesystem is in |
| bool |
| exists(const std::string &dir) |
| { |
| struct stat buffer; |
| int result = stat(dir.c_str(), &buffer); |
| return (!result) ? true : false; |
| } |
| |
| bool |
| is_directory(const std::string &directory) |
| { |
| struct stat buffer; |
| int result = stat(directory.c_str(), &buffer); |
| return (!result && (S_IFDIR & buffer.st_mode)) ? true : false; |
| } |
| |
| // the function for the checking of the yaml file in the passed in path |
| // if found return the path to the yaml file, if not return empty string. |
| static std::string |
| get_yaml_path(const std::string &path) |
| { |
| // yaml_file 2 and 3 are for temporary use in case the change may break for people using runroot already |
| // this can be removed in the future. |
| std::string yaml_file; |
| std::string yaml_file2; |
| std::string yaml_file3; |
| if (is_directory(path.c_str())) { |
| std::string yaml_file(Layout::relative_to(path, "runroot.yaml")); |
| if (exists(yaml_file)) { |
| return yaml_file; |
| } |
| std::string yaml_file2(Layout::relative_to(path, "runroot.yml")); |
| if (exists(yaml_file2)) { |
| return yaml_file2; |
| } |
| std::string yaml_file3(Layout::relative_to(path, "runroot_path.yml")); |
| if (exists(yaml_file3)) { |
| return yaml_file3; |
| } |
| } else if (exists(path)) { |
| return path; |
| } |
| return {}; |
| } |
| |
| // the function for the checking of the yaml file in passed in directory or parent directory |
| // if found return the parent path to the yaml file |
| static std::string |
| get_parent_yaml_path(const std::string &path) |
| { |
| std::string whole_path = path; |
| if (whole_path.back() == '/') { |
| whole_path.pop_back(); |
| } |
| // go up to 4 level of parent directories |
| for (int i = 0; i < 4; i++) { |
| if (whole_path.empty()) { |
| return {}; |
| } |
| std::string yaml_file = get_yaml_path(whole_path); |
| if (!yaml_file.empty()) { |
| return yaml_file; |
| } |
| whole_path = whole_path.substr(0, whole_path.find_last_of('/')); |
| } |
| return {}; |
| } |
| |
| static void |
| runroot_extra_handling(const char *executable, bool json) |
| { |
| std::string path; |
| // 2. check Environment variable |
| char *env_val = getenv("TS_RUNROOT"); |
| if (env_val) { |
| path = get_yaml_path(env_val); |
| if (!path.empty()) { |
| runroot_file = path; |
| if (!json) { |
| ink_notice("using the environment variable TS_RUNROOT"); |
| } |
| return; |
| } else if (!json) { |
| ink_warning("Unable to access runroot: '%s' from $TS_RUNROOT", env_val); |
| } |
| } |
| // 3. find cwd or parent path of cwd to check |
| char cwd[PATH_MAX] = {0}; |
| if (getcwd(cwd, sizeof(cwd)) != nullptr) { |
| path = get_parent_yaml_path(cwd); |
| if (!path.empty()) { |
| runroot_file = path; |
| if (!json) { |
| ink_notice("using cwd as TS_RUNROOT"); |
| } |
| return; |
| } |
| } |
| // 4. installed executable |
| char RealBinPath[PATH_MAX] = {0}; |
| if ((executable != nullptr) && realpath(executable, RealBinPath) != nullptr) { |
| std::string bindir = RealBinPath; |
| bindir = bindir.substr(0, bindir.find_last_of('/')); // getting the bin dir not executable path |
| path = get_parent_yaml_path(bindir); |
| if (!path.empty()) { |
| runroot_file = path; |
| if (!json) { |
| ink_notice("using the installed dir as TS_RUNROOT"); |
| } |
| return; |
| } |
| } |
| // 5. if no runroot use, using default build |
| return; |
| } |
| |
| // This is a temporary approach to handle runroot with migration to ArgParser. |
| // When all program use ArgParser, we can remove the runroot_handler below and replace it with this one. |
| void |
| argparser_runroot_handler(std::string const &value, const char *executable, bool json) |
| { |
| // 1.if --run-root is provided |
| if (!value.empty()) { |
| std::string path = get_yaml_path(value); |
| if (!path.empty()) { |
| if (!json) { |
| ink_notice("using command line path as RUNROOT"); |
| } |
| runroot_file = path; |
| return; |
| } else if (!json) { |
| ink_warning("Unable to access runroot: '%s'", value.c_str()); |
| } |
| } |
| runroot_extra_handling(executable, json); |
| } |
| |
| // handler for ts runroot |
| // this function set up runroot_file |
| void |
| runroot_handler(const char **argv, bool json) |
| { |
| std::string prefix = "--run-root"; |
| std::string path; |
| |
| // check if we have --run-root... |
| std::string arg = {}; |
| |
| int i = 0; |
| while (argv[i]) { |
| std::string_view command = argv[i]; |
| if (command.substr(0, prefix.size()) == prefix) { |
| arg = command.data(); |
| break; |
| } |
| i++; |
| } |
| |
| // if --run-root is provided |
| if (!arg.empty() && arg != prefix) { |
| // 1. pass in path |
| prefix += "="; |
| std::string value = arg.substr(prefix.size(), arg.size() - 1); |
| path = get_yaml_path(value); |
| if (!path.empty()) { |
| if (!json) { |
| ink_notice("using command line path as RUNROOT"); |
| } |
| runroot_file = path; |
| return; |
| } else if (!json) { |
| ink_warning("Unable to access runroot: '%s'", value.c_str()); |
| } |
| } |
| |
| runroot_extra_handling(argv[0], json); |
| } |
| |
| // return a map of all path with default layout |
| std::unordered_map<std::string, std::string> |
| runroot_map_default() |
| { |
| std::unordered_map<std::string, std::string> map; |
| |
| map[LAYOUT_PREFIX] = Layout::get()->prefix; |
| map[LAYOUT_EXEC_PREFIX] = Layout::get()->exec_prefix; |
| map[LAYOUT_BINDIR] = Layout::get()->bindir; |
| map[LAYOUT_SBINDIR] = Layout::get()->sbindir; |
| map[LAYOUT_SYSCONFDIR] = Layout::get()->sysconfdir; |
| map[LAYOUT_DATADIR] = Layout::get()->datadir; |
| map[LAYOUT_INCLUDEDIR] = Layout::get()->includedir; |
| map[LAYOUT_LIBDIR] = Layout::get()->libdir; |
| map[LAYOUT_LIBEXECDIR] = Layout::get()->libexecdir; |
| map[LAYOUT_LOCALSTATEDIR] = Layout::get()->localstatedir; |
| map[LAYOUT_RUNTIMEDIR] = Layout::get()->runtimedir; |
| map[LAYOUT_LOGDIR] = Layout::get()->logdir; |
| // mandir is not needed for runroot |
| map[LAYOUT_CACHEDIR] = Layout::get()->cachedir; |
| |
| return map; |
| } |
| |
| // return a map of all path in runroot.yaml |
| RunrootMapType |
| runroot_map(const std::string &file) |
| { |
| RunrootMapType map; |
| try { |
| YAML::Node yamlfile = YAML::LoadFile(file); |
| std::string prefix = file.substr(0, file.find_last_of('/')); |
| |
| for (const auto &it : yamlfile) { |
| // key value pairs of dirs |
| std::string value = it.second.as<std::string>(); |
| if (value[0] != '/') { |
| value = Layout::relative_to(prefix, value); |
| } |
| map[it.first.as<std::string>()] = value; |
| } |
| } catch (YAML::Exception &e) { |
| ink_warning("Unable to read '%s': %s", file.c_str(), e.what()); |
| ink_notice("Continuing with default value"); |
| return RunrootMapType{}; |
| } |
| return map; |
| } |
| |
| // check for the using of runroot |
| // a map of all path will be returned |
| // if we do not use runroot, a empty map will be returned. |
| RunrootMapType |
| check_runroot() |
| { |
| if (runroot_file.empty()) { |
| return RunrootMapType{}; |
| } |
| |
| int len = runroot_file.size(); |
| if ((len + 1) > PATH_NAME_MAX) { |
| ink_fatal("runroot path is too big: %d, max %d\n", len, PATH_NAME_MAX - 1); |
| } |
| return runroot_map(runroot_file); |
| } |
| |
| std::string_view |
| get_runroot() |
| { |
| return runroot_file; |
| } |