/** * Copyright (c) 2021 OceanBase * OceanBase Database Proxy(ODP) is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #define USING_LOG_PREFIX PROXY #include #include "utils/ob_layout.h" #include "ob_proxy_init.h" #define UNIX_PATH_LENGTH_MAX (sizeof(struct sockaddr_un) - sizeof(sa_family_t)) using namespace oceanbase::common; using namespace oceanbase::obproxy::event; namespace oceanbase { namespace obproxy { static const char* obproxy_domain = "obproxy.domain"; static const char* obproxy_dir = "./.obproxy"; ObLayout &get_global_layout() { static ObLayout g_layout; return g_layout; } ObLayout::ObLayout() : is_inited_(false), prefix_(NULL), bin_dir_(NULL), etc_dir_(NULL), log_dir_(NULL), conf_dir_(NULL), control_config_dir_(NULL), dbconfig_dir_(NULL), unix_domain_path_(NULL) { } ObLayout::~ObLayout() { } int ObLayout::init(const char *start_cmd) { int ret = OB_SUCCESS; char *cwd = NULL; PageArena arena; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; MPRINT("layout has already been inited, ret=%d", ret); } else if (OB_ISNULL(start_cmd)) { ret = OB_ERR_UNEXPECTED; MPRINT("start cmd is NULL, ret=%d", ret); } else if (OB_ISNULL(cwd = arena.alloc(MAX_PATH_LENGTH))) { ret = OB_ALLOCATE_MEMORY_FAILED; MPRINT("fail to alloc memeory,alloc_size=%ld, ret=%d", MAX_PATH_LENGTH, ret); } else if (OB_ISNULL(getcwd(cwd, MAX_PATH_LENGTH))) { ret = OB_ERR_UNEXPECTED; MPRINT("fail to get current working dir, errno=%d, errmsg=%s, ret=%d", errno, strerror(errno), ret); } else if (OB_FAIL(init_bin_dir(cwd, start_cmd))) { MPRINT("fail to init proxy bin dir, ret=%d", ret); } else if (OB_FAIL(init_dir_prefix(cwd))) { MPRINT("fail to init proxy dir prefix, ret=%d", ret); } else if (RUN_MODE_CLIENT == g_run_mode && OB_FAIL(handle_client_dirs())) { MPRINT("fail to construct client dirs, ret=%d", ret); } else if (OB_FAIL(construct_dirs())) { MPRINT("fail to construct dirs, ret=%d", ret); } else { is_inited_ = true; } return ret; } int ObLayout::merge_file_path(const char *root, const char *file, common::ObIAllocator &allocator, char *&buf) { int ret = OB_SUCCESS; buf = NULL; if (OB_ISNULL(root) || OB_ISNULL(file)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", "root", P(root), "file", P(file), K(ret)); } else { int64_t root_len = STRLEN(root); int64_t file_len = STRLEN(file); //one '/' append after root and a '\0' at the end int64_t need_len = root_len + file_len + 2; int64_t path_len = 0; char *path = NULL; if (OB_ISNULL(path = static_cast(allocator.alloc(need_len)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc memeory", K(need_len), K(ret)); } else if ('/' == file[0]) { //do nothing if file is rooted ,just return file path[0] = '/'; path_len = 1; } else { MEMCPY(path, root, root_len); path_len = root_len; if ((root_len > 0) && ('/' != path[root_len - 1])) { path[path_len++] = '/'; } } while (OB_SUCC(ret) && '\0' != *file) { const char *next = file; while ('\0' != *next && '/' != (*next)) { ++next; } int64_t seg_len = next - file; if (0 == seg_len || (1 == seg_len && '.' == file[0])) { //nop when (/ or ./) } else if (2 == seg_len && '.' == file[0] && '.' == file[1]) { // handle ../ if (1 == path_len && '/' == path[0]) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(root), K(file), K(ret)); } else if (path_len >= 3 && 0 == MEMCMP(path + path_len - 3, "../", 3)) { if ('\0' != *next) { ++seg_len; } MEMCPY(path + path_len, "../", seg_len); path_len += seg_len; } else { do { --path_len; } while (path_len && ('/' != path[path_len - 1])); } } else { //an actually segment .append it to path if ('\0' != *next) { ++seg_len; } MEMCPY(path + path_len, file, seg_len); path_len += seg_len; } if ('\0' != *next) { //skip over trailing slash to the next segment ++next; } file = next; } if (OB_SUCC(ret)) { path[path_len] = '\0'; buf = path; } } return ret; } int ObLayout::init_bin_dir(const char *cwd, const char *start_cmd) { int ret = OB_SUCCESS; if (OB_ISNULL(cwd) || OB_ISNULL(start_cmd)) { ret = OB_INVALID_ARGUMENT; MPRINT("invalid cwd or start cmd, cwd=%s, start_cmd=%s, ret=%d", cwd, start_cmd, ret); } else if (OB_FAIL(merge_file_path(cwd, start_cmd, allocator_, bin_dir_))) { MPRINT("fail to merge bin dir, ret=%d", ret); } else { int64_t bin_len = STRLEN(bin_dir_); while (bin_len > 1 && '/' != bin_dir_[bin_len - 1]) { bin_dir_[bin_len - 1] = '\0'; --bin_len; } } return ret; } int ObLayout::init_dir_prefix(const char *cwd) { int ret = OB_SUCCESS; if (RUN_MODE_PROXY == g_run_mode) { if (OB_FAIL(init_dir_prefix_proxy_mode(cwd))) { LOG_WARN("init dir prefix proxy mode failed", K(ret)); } } else if (RUN_MODE_CLIENT == g_run_mode) { if (OB_FAIL(init_dir_prefix_client_mode())) { LOG_WARN("init_dir_prefix_client_mode", K(ret)); } } return ret; } int ObLayout::init_dir_prefix_client_mode() { int ret = OB_SUCCESS; int64_t prefix_len = 0; prefix_len = strlen(obproxy_dir); if (OB_SUCC(ret)) { if (OB_ISNULL(prefix_ = static_cast(allocator_.alloc(prefix_len + 1)))) { ret = OB_ALLOCATE_MEMORY_FAILED; MPRINT("fail to alloc memeory, prefix_len=%ld, ret=%d", prefix_len, ret); } else { MEMCPY(prefix_, obproxy_dir, prefix_len); prefix_[prefix_len] = '\0'; } } return ret; } int ObLayout::init_dir_prefix_proxy_mode(const char *cwd) { int ret = OB_SUCCESS; char *env_path = NULL; int64_t prefix_len = 0; if (OB_ISNULL(cwd)) { ret = OB_INVALID_ARGUMENT; MPRINT("invalid cwd, cwd=%s, ret=%d", cwd, ret); } else if (OB_ISNULL(env_path = getenv("OBPROXY_ROOT"))) { MPRINT("OBPROXY_ROOT is not set, set current working dir"); prefix_len = STRLEN(cwd); } else { int64_t env_path_len = STRLEN(env_path); if (OB_UNLIKELY(env_path_len >= MAX_PATH_LENGTH)) { ret = OB_SIZE_OVERFLOW; MPRINT("root path buf is not enough, env_path=%s, env_path_len=%ld, ret=%d", env_path, env_path_len, ret); } else if (OB_UNLIKELY('/' != env_path[0])) { ret = OB_INVALID_ARGUMENT; MPRINT("invalid env path for proxy, env_path=%s, ret=%d", env_path, ret); } else { //trim the ending slashes while (env_path_len > 1 && '/' == env_path[env_path_len - 1]) { --env_path_len; } prefix_len = env_path_len; } } if (OB_SUCC(ret)) { if (OB_ISNULL(prefix_ = static_cast(allocator_.alloc(prefix_len + 1)))) { ret = OB_ALLOCATE_MEMORY_FAILED; MPRINT("fail to alloc memeory, prefix_len=%ld, ret=%d", prefix_len, ret); } else { MEMCPY(prefix_, (NULL != env_path) ? env_path : cwd, prefix_len); prefix_[prefix_len] = '\0'; } } return ret; } int ObLayout::construct_dirs() { int ret = OB_SUCCESS; static const char *ETC_PATH= "etc"; static const char *LOG_PATH = "log"; static const char *CONF_PATH = ".conf"; static const char *CONTROL_CONFIG_PATH = "control-config"; static const char *DBCONFIG_PATH = "sharding-config"; if (OB_FAIL(construct_single_dir(ETC_PATH, etc_dir_))) { MPRINT("fail to construct etc dir, ret=%d", ret); } else if (OB_FAIL(construct_single_dir(LOG_PATH, log_dir_))) { MPRINT("fail to construct log dir, ret=%d", ret); } else if (OB_FAIL(construct_single_dir(CONF_PATH, conf_dir_))) { MPRINT("fail to construct .conf dir, ret=%d", ret); } else if (OB_FAIL(construct_single_dir(CONTROL_CONFIG_PATH, control_config_dir_))) { MPRINT("fail to construct control-config dir, ret=%d", ret); } else if (OB_FAIL(construct_single_dir(DBCONFIG_PATH, dbconfig_dir_))) { MPRINT("fail to construct sharding-config dir, ret=%d", ret); } return ret; } int ObLayout::extract_actual_path(const char * const full_path, char *&actual_path) { int ret = OB_SUCCESS; struct stat64 file_info; int64_t len = 0; if (OB_UNLIKELY(len = strlen(full_path)) == 0) { ret = OB_INVALID_ARGUMENT; MPRINT("invalid arguments, full_path=%s, ret=%d", full_path, ret); } else { //if this directory was exist, and it is a symbolic link, need extract its actual path if (0 == ::lstat64(full_path, &file_info) && S_ISLNK(file_info.st_mode)) { MPRINT("this is symbolic link, need extract actual path, full_path=%s", full_path); ssize_t buf_size = static_cast(file_info.st_size + 1); if (OB_ISNULL(actual_path = static_cast(allocator_.alloc(buf_size)))) { ret = OB_ALLOCATE_MEMORY_FAILED; MPRINT("fail to alloc memeory, buf_size=%ld, ret=%d", buf_size, ret); } else { ssize_t path_size = ::readlink(full_path, actual_path, buf_size); if (path_size != (buf_size - 1)) { ret = ob_get_sys_errno(); MPRINT("fail to readlink file, full_path=%s, path_size=%ld, buf_size=%ld, " "errno=%d, errmsg=%s, ret=%d", full_path, path_size, buf_size, errno, strerror(errno), ret); } else { actual_path[path_size] = '\0'; MPRINT("succ to extract actual path, full_path=%s, actual_path=%s", full_path, actual_path); } } } else { //if do not use symbolic link, actual_path equal to full_path actual_path = const_cast(full_path); } } return ret; } int ObLayout::construct_single_dir(const char *sub_dir, char *&full_path) { int ret = OB_SUCCESS; full_path = NULL; char *actual_path = NULL; if (OB_FAIL(merge_file_path(prefix_, sub_dir, allocator_, full_path))) { MPRINT("fail to merge_file_path, sub_dir=%s, ret=%d", sub_dir, ret); } else if (OB_FAIL(extract_actual_path(full_path, actual_path))) { MPRINT("fail to extract_actual_path, full_path=%s, ret=%d", full_path, ret); } else if (OB_FAIL(FileDirectoryUtils::create_full_path(actual_path))) { MPRINT("fail to create_full_path, actual_path=%s, ret=%d", actual_path, ret); } else { //do nothing } if (NULL != actual_path && full_path != actual_path) { allocator_.free(actual_path); } actual_path = NULL; return ret; } int ObLayout::handle_client_dirs() { int ret = OB_SUCCESS; if (OB_FAIL(construct_client_obproxy_dirs())) { LOG_WARN("construct_client_obproxy_dirs failed", K(ret)); } else if (OB_FAIL(remove_unix_domain())) { LOG_WARN("remove unix domain failed", K(ret)); } return ret; } int ObLayout::construct_client_obproxy_dirs() { int ret = OB_SUCCESS; char *actual_path = NULL; // Create the .obproxy directory if (OB_FAIL(extract_actual_path(prefix_, actual_path))) { MPRINT("fail to extract_actual_path, prefix_path=%s, ret=%d", prefix_, ret); } else if (OB_FAIL(FileDirectoryUtils::create_full_path(actual_path))) { MPRINT("fail to create_full_path, actual_path=%s, ret=%d", actual_path, ret); } if (NULL != actual_path && prefix_ != actual_path) { allocator_.free(actual_path); } actual_path = NULL; return ret; } int ObLayout::remove_unix_domain() { int ret = OB_SUCCESS; char *actual_path = NULL; if (OB_FAIL(merge_file_path(prefix_, obproxy_domain, allocator_, unix_domain_path_))) { MPRINT("fail to merge file path, sub_dir=%s, ret=%d", obproxy_domain, ret); } else if (OB_FAIL(extract_actual_path(unix_domain_path_, actual_path))) { MPRINT("fail to extract_actual_path, full_path=%s, ret=%d", unix_domain_path_, ret); } else { remove(actual_path); if (NULL != actual_path && unix_domain_path_ != actual_path) { allocator_.free(actual_path); } actual_path = NULL; } return ret; } }//end of namespace obproxy }//end of namespace oceanbase