| /** @file |
| |
| A brief file description |
| |
| @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. |
| */ |
| |
| // for engine of traffic runroot |
| // function introduction in engine.h |
| |
| #include "tscore/runroot.h" |
| #include "tscore/I_Layout.h" |
| #include "tscore/ink_error.h" |
| #include "tscore/ink_defs.h" |
| #include "records/I_RecProcess.h" |
| #include "RecordsConfig.h" |
| #include "engine.h" |
| #include "file_system.h" |
| #include "info.h" |
| |
| #include <fstream> |
| #include <iostream> |
| #include <ftw.h> |
| #include <yaml-cpp/yaml.h> |
| #include <grp.h> |
| #include <sysexits.h> |
| |
| static const long MAX_LOGIN = ink_login_name_max(); |
| static constexpr int MAX_GROUP_NUM = 32; |
| |
| // Personally I don't really like the way that nftw needs global variables. Right now there is no other options. |
| // This iteration through directory can be avoided after std::filesystem is in. |
| |
| // for nftw check_directory |
| static std::string empty_check_directory; |
| // for 'verify --fix' nftw iteration |
| static PermissionEntry permission_entry; |
| // if fix_flag is set, permission handler will perform fixing operation |
| static bool fix_flag = false; |
| |
| // the function for the checking of the yaml file in the passed in path |
| // if found return the path, if not return empty string |
| std::string |
| check_path(const std::string &path) |
| { |
| std::string yaml_file = Layout::relative_to(path, "runroot.yaml"); |
| if (!exists(yaml_file)) { |
| ink_warning("Unable to access runroot: '%s' - %s", yaml_file.c_str(), strerror(errno)); |
| return {}; |
| } |
| return path; |
| } |
| |
| // the function for the checking of the yaml file in passed in directory or parent directory |
| // if found return the parent path containing the yaml file |
| std::string |
| check_parent_path(const std::string &path) |
| { |
| std::string yaml_path = path; |
| if (yaml_path.back() == '/') { |
| yaml_path.pop_back(); |
| } |
| // go up to 4 level of parent directories |
| for (int i = 0; i < 4; i++) { |
| if (yaml_path.empty()) { |
| return {}; |
| } |
| if (exists(Layout::relative_to(yaml_path, "runroot.yaml"))) { |
| return yaml_path; |
| } |
| yaml_path = yaml_path.substr(0, yaml_path.find_last_of("/")); |
| } |
| return {}; |
| } |
| |
| // handle the path of the engine during parsing |
| static std::string |
| path_handler(const std::string &path, bool run_flag, const std::string &command) |
| { |
| std::string cur_working_dir = ""; |
| char cwd[PATH_MAX]; |
| if (!getcwd(cwd, sizeof(cwd))) { |
| ink_warning("unexpected failure from getcwd() - %s", strerror(errno)); |
| } else { |
| cur_working_dir = cwd; |
| } |
| |
| if (run_flag) { |
| // no path passed in, use cwd |
| if (path.empty()) { |
| return cur_working_dir; |
| } |
| if (path[0] == '/') { |
| return path; |
| } else { |
| return Layout::relative_to(cur_working_dir, path); |
| } |
| } |
| |
| // for other commands |
| // 1. passed in path |
| if (!path.empty()) { |
| std::string cmdpath; |
| if (path[0] == '/') { |
| cmdpath = check_path(path); |
| } else { |
| cmdpath = check_path(Layout::relative_to(cur_working_dir, path)); |
| } |
| if (!cmdpath.empty()) { |
| return cmdpath; |
| } |
| } |
| |
| // 2. find cwd or parent path of cwd to check |
| std::string cwdpath = check_parent_path(cur_working_dir); |
| if (!cwdpath.empty()) { |
| return cwdpath; |
| } |
| |
| // 3. installed executable |
| char RealBinPath[PATH_MAX] = {0}; |
| if (!command.empty() && realpath(command.c_str(), RealBinPath) != nullptr) { |
| std::string bindir = RealBinPath; |
| |
| bindir = bindir.substr(0, bindir.find_last_of("/")); // getting the bin dir not executable path |
| bindir = check_parent_path(bindir); |
| if (!bindir.empty()) { |
| return bindir; |
| } |
| } |
| |
| return path; |
| } |
| |
| // check if there is any directory inside empty_check_directory to see if it is empty or not |
| static int |
| check_directory_empty(const char *path, const struct stat *s, int flag) |
| { |
| return std::string(path) != empty_check_directory ? -1 : 0; |
| } |
| |
| void |
| LayoutEngine::info() |
| { |
| bool json = arguments.get("json"); |
| |
| if (arguments.get("features")) { |
| produce_features(json); |
| } else if (arguments.get("versions")) { |
| produce_versions(json); |
| } else { |
| produce_layout(json); |
| } |
| } |
| |
| void |
| LayoutEngine::create_runroot() |
| { |
| // set up options |
| std::string path = path_handler(arguments.get("path").value(), true, _argv[0]); |
| if (path.empty()) { |
| ink_error("Path not valid for creating"); |
| status_code = EX_SOFTWARE; |
| return; |
| } |
| bool force_flag = arguments.get("force"); |
| bool abs_flag = arguments.get("absolute"); |
| std::string layout_file = arguments.get("layout").value(); |
| if (layout_file.find("runroot.yaml") != std::string::npos) { |
| ink_error( |
| "'runroot.yaml' is a potentially dangerous name for '--layout' option.\nPlease set other name to the file for '--layout'"); |
| status_code = EX_SOFTWARE; |
| return; |
| } |
| // deal with the copy style |
| CopyStyle copy_style = HARD; |
| std::string style = arguments.get("copy-style").value(); |
| if (!style.empty()) { |
| transform(style.begin(), style.end(), style.begin(), ::tolower); |
| if (style == "full") { |
| copy_style = FULL; |
| } else if (style == "soft") { |
| copy_style = SOFT; |
| } else if (style == "hard") { |
| copy_style = HARD; |
| } else { |
| ink_error("Unknown copy style: '%s'", style.c_str()); |
| status_code = EX_USAGE; |
| return; |
| } |
| } |
| std::string original_root = Layout::get()->prefix; |
| const std::string &ts_runroot = path; |
| // check for existing runroot to use rather than create new one |
| if (!force_flag && exists(Layout::relative_to(ts_runroot, "runroot.yaml"))) { |
| std::cout << "Using existing runroot...\n" |
| "Please remove the old runroot if new runroot is needed" |
| << std::endl; |
| return; |
| } |
| if (!force_flag && !check_parent_path(ts_runroot).empty()) { |
| ink_error("Cannot create runroot inside another runroot"); |
| status_code = EX_SOFTWARE; |
| return; |
| } |
| |
| std::cout << "creating runroot - " + ts_runroot << std::endl; |
| |
| // check if directory is empty when --force is not used |
| if (is_directory(ts_runroot) && !force_flag) { |
| empty_check_directory = ts_runroot; |
| if (ftw(ts_runroot.c_str(), check_directory_empty, OPEN_MAX_FILE) != 0) { |
| // if the directory is not empty, check for valid Y/N |
| for (int i = 0; true; i++) { |
| std::cout << "Are you sure to create runroot inside a non-empty directory Y/N: "; |
| std::string input; |
| std::cin >> input; |
| if (input == "Y" || input == "y") { |
| break; |
| } |
| if (input == "N" || input == "n") { |
| return; |
| } |
| if (i == 2) { |
| ink_error("Invalid input Y/N"); |
| status_code = EX_SOFTWARE; |
| return; |
| } |
| } |
| } |
| } |
| |
| // create new root & copy from original to new runroot. then fill in the map |
| RunrootMapType original_map; // map the original build time directory |
| |
| original_map[LAYOUT_EXEC_PREFIX] = TS_BUILD_EXEC_PREFIX; |
| original_map[LAYOUT_BINDIR] = TS_BUILD_BINDIR; |
| original_map[LAYOUT_SBINDIR] = TS_BUILD_SBINDIR; |
| original_map[LAYOUT_SYSCONFDIR] = TS_BUILD_SYSCONFDIR; |
| original_map[LAYOUT_DATADIR] = TS_BUILD_DATADIR; |
| original_map[LAYOUT_INCLUDEDIR] = TS_BUILD_INCLUDEDIR; |
| original_map[LAYOUT_LIBDIR] = TS_BUILD_LIBDIR; |
| original_map[LAYOUT_LIBEXECDIR] = TS_BUILD_LIBEXECDIR; |
| original_map[LAYOUT_LOCALSTATEDIR] = TS_BUILD_LOCALSTATEDIR; |
| original_map[LAYOUT_RUNTIMEDIR] = TS_BUILD_RUNTIMEDIR; |
| original_map[LAYOUT_LOGDIR] = TS_BUILD_LOGDIR; |
| original_map[LAYOUT_MANDIR] = TS_BUILD_MANDIR; |
| original_map[LAYOUT_INFODIR] = TS_BUILD_INFODIR; |
| original_map[LAYOUT_CACHEDIR] = TS_BUILD_CACHEDIR; |
| |
| RunrootMapType new_map = original_map; |
| // use the user provided layout: layout_file |
| if (layout_file.size() != 0) { |
| try { |
| YAML::Node yamlfile = YAML::LoadFile(layout_file); |
| for (const auto &it : yamlfile) { |
| std::string key = it.first.as<std::string>(); |
| std::string value = it.second.as<std::string>(); |
| auto iter = new_map.find(key); |
| if (iter != new_map.end()) { |
| iter->second = value; |
| } else { |
| if (key != "prefix") { |
| ink_warning("Unknown item from %s: '%s'", layout_file.c_str(), key.c_str()); |
| } |
| } |
| } |
| } catch (YAML::Exception &e) { |
| ink_warning("Unable to read provided YAML file '%s': %s", layout_file.c_str(), e.what()); |
| ink_notice("Continuing with default value"); |
| } |
| } |
| |
| // copy each directory to the runroot path |
| // symlink the executables |
| // set up path_map for yaml to emit key-value pairs |
| RunrootMapType path_map; |
| for (const auto &it : original_map) { |
| // path handle |
| std::string join_path; |
| if (it.second[0] && it.second[0] == '/') { |
| join_path = it.second.substr(1); |
| } else { |
| join_path = it.second; |
| } |
| std::string new_join_path = new_map[it.first]; |
| |
| std::string old_path = Layout::relative_to(original_root, join_path); |
| std::string new_path = Layout::relative_to(ts_runroot, new_join_path); |
| if (abs_flag) { |
| path_map[it.first] = Layout::relative_to(ts_runroot, new_join_path); |
| } else { |
| path_map[it.first] = Layout::relative_to(".", new_join_path); |
| } |
| // don't copy the prefix, mandir, localstatedir and infodir |
| if (it.first != LAYOUT_EXEC_PREFIX && it.first != LAYOUT_LOCALSTATEDIR && it.first != LAYOUT_MANDIR && |
| it.first != LAYOUT_INFODIR) { |
| if (!copy_directory(old_path, new_path, it.first, copy_style)) { |
| ink_warning("Unable to copy '%s' - %s", it.first.c_str(), strerror(errno)); |
| ink_notice("Creating '%s': %s", it.first.c_str(), new_path.c_str()); |
| // if copy failed for certain directory, we create it in runroot |
| if (!create_directory(new_path)) { |
| ink_warning("Unable to create '%s' - %s", it.first.c_str(), strerror(errno)); |
| } |
| } |
| } |
| } |
| |
| std::cout << "Copying from " + original_root + " ..." << std::endl; |
| |
| if (abs_flag) { |
| path_map[LAYOUT_PREFIX] = ts_runroot; |
| } else { |
| path_map[LAYOUT_PREFIX] = "."; |
| } |
| |
| YAML::Emitter yamlfile; |
| // emit key value pairs to the yaml file |
| yamlfile << YAML::BeginMap; |
| for (const auto &it : dir_vector) { |
| yamlfile << YAML::Key << it; |
| yamlfile << YAML::Value << path_map[it]; |
| } |
| yamlfile << YAML::EndMap; |
| |
| // create the file |
| std::ofstream f(Layout::relative_to(ts_runroot, "runroot.yaml")); |
| if (f.bad()) { |
| ink_warning("Writing to YAML file failed\n"); |
| } else { |
| f << yamlfile.c_str(); |
| } |
| } |
| |
| // the function for removing the runroot |
| void |
| LayoutEngine::remove_runroot() |
| { |
| std::string path = path_handler(arguments.get("path").value(), false, _argv[0]); |
| // check validity of the path |
| if (path.empty()) { |
| ink_error("Path not valid (runroot.yaml not found)"); |
| status_code = EX_IOERR; |
| return; |
| } |
| |
| std::string clean_root = path; |
| append_slash(clean_root); |
| |
| if (arguments.get("force")) { |
| // the force remove |
| std::cout << "Forcing removing runroot ..." << std::endl; |
| if (!remove_directory(clean_root)) { |
| ink_warning("Failed force removing runroot '%s' - %s", clean_root.c_str(), strerror(errno)); |
| } |
| } else { |
| // handle the map and deleting of each directories specified in the yml file |
| RunrootMapType map = runroot_map(Layout::relative_to(clean_root, "runroot.yaml")); |
| map.erase(LAYOUT_PREFIX); |
| map.erase(LAYOUT_EXEC_PREFIX); |
| // get current working directory |
| std::string cur_working_dir = ""; |
| char cwd[PATH_MAX]; |
| if (getcwd(cwd, sizeof(cwd)) == nullptr) { |
| ink_warning("unexpected failure from getcwd() - %s", strerror(errno)); |
| } else { |
| cur_working_dir = cwd; |
| } |
| for (const auto &it : map) { |
| std::string dir = it.second; |
| append_slash(dir); |
| // get the directory to remove: prefix/etc/trafficserver -> prefix/etc |
| dir = dir.substr(0, dir.substr(clean_root.size()).find_first_of("/") + clean_root.size()); |
| // don't remove cwd |
| if (cur_working_dir != dir) { |
| remove_directory(dir); |
| } else { |
| // if we are at this directory, remove files inside |
| remove_inside_directory(dir); |
| } |
| } |
| // remove yaml file |
| std::string yaml_file = Layout::relative_to(clean_root, "runroot.yaml"); |
| if (remove(yaml_file.c_str()) != 0) { |
| ink_notice("unable to delete runroot.yaml - %s", strerror(errno)); |
| } |
| |
| append_slash(cur_working_dir); |
| if (cur_working_dir.find(clean_root) != 0) { |
| // if cwd is not runroot and runroot is empty, remove it |
| if (remove(clean_root.c_str()) != 0) { |
| ink_notice("unable to delete %s - %s", clean_root.c_str(), strerror(errno)); |
| } |
| } |
| } |
| } |
| |
| // check permission for verify |
| static int |
| permission_handler(const char *path, const struct stat *s, int flag) |
| { |
| std::string cur_directory = permission_entry.name; |
| // filter traffic server related files |
| if (!filter_ts_files(cur_directory, path)) { |
| return 0; |
| } |
| if (flag == FTW_NS || !s) { |
| ink_warning("unable to stat() destination path %s - %s", path, strerror(errno)); |
| return -1; |
| } |
| |
| int ret = 0; |
| // --------- for directories --------- |
| if (flag == FTW_D || flag == FTW_DNR) { |
| // always need read permission for directories |
| if (!(s->st_mode & permission_entry.r_mode)) { |
| if (fix_flag) { |
| if (chmod(path, s->st_mode | permission_entry.r_mode) < 0) { |
| ink_warning("Unable to change file mode on %s - %s", path, strerror(errno)); |
| } else { |
| std::cout << "Fixed read permission: " << path << std::endl; |
| } |
| } else { |
| std::cout << "Read permission failed for directory: " << path << std::endl; |
| ret = -1; |
| } |
| } |
| // need write permission for logdir, runtimedir and cachedir |
| if (cur_directory == LAYOUT_LOGDIR || cur_directory == LAYOUT_RUNTIMEDIR || cur_directory == LAYOUT_CACHEDIR) { |
| if (!(s->st_mode & permission_entry.w_mode)) { |
| if (fix_flag) { |
| if (chmod(path, s->st_mode | permission_entry.w_mode) < 0) { |
| ink_warning("Unable to change file mode on %s - %s", path, strerror(errno)); |
| } else { |
| std::cout << "Fixed write permission: " << path << std::endl; |
| } |
| } else { |
| std::cout << "Write permission failed for directory: " << path << std::endl; |
| ret = -1; |
| } |
| } |
| } |
| // always need execute permission for directories |
| if (!(s->st_mode & permission_entry.e_mode)) { |
| if (fix_flag) { |
| if (chmod(path, s->st_mode | permission_entry.e_mode) < 0) { |
| ink_warning("Unable to change file mode on %s - %s", path, strerror(errno)); |
| } else { |
| std::cout << "Fixed execute permission: " << path << std::endl; |
| } |
| } else { |
| std::cout << "Execute permission failed for directory: " << path << std::endl; |
| ret = -1; |
| } |
| } |
| } else { |
| // --------- for files --------- |
| // always need read permission for all files |
| if (!(s->st_mode & permission_entry.r_mode)) { |
| if (fix_flag) { |
| if (chmod(path, s->st_mode | permission_entry.r_mode) < 0) { |
| ink_warning("Unable to change file mode on %s - %s", path, strerror(errno)); |
| } else { |
| std::cout << "Fixed read permission: " << path << std::endl; |
| } |
| } else { |
| std::cout << "Read permission failed for file " << path << std::endl; |
| ret = -1; |
| } |
| } |
| // need write permission for files in logdir, runtimedir and cachedir |
| if (cur_directory == LAYOUT_LOGDIR || cur_directory == LAYOUT_RUNTIMEDIR || cur_directory == LAYOUT_CACHEDIR) { |
| if (!(s->st_mode & permission_entry.w_mode)) { |
| if (fix_flag) { |
| if (chmod(path, s->st_mode | permission_entry.w_mode) < 0) { |
| ink_warning("Unable to change file mode on %s - %s", path, strerror(errno)); |
| } else { |
| std::cout << "Fixed write permission: " << path << std::endl; |
| } |
| } else { |
| std::cout << "Write permission failed for file " << path << std::endl; |
| ret = -1; |
| } |
| } |
| } |
| // execute permission on files in bindir, sbindir, libdir and libexecdir |
| if (cur_directory == LAYOUT_BINDIR || cur_directory == LAYOUT_SBINDIR || cur_directory == LAYOUT_LIBDIR || |
| cur_directory == LAYOUT_LIBEXECDIR) { |
| std::string tmp_path = path; |
| // skip the files in perl5 and pkgconfig from libdir |
| if (tmp_path.find("/perl5/") != std::string::npos || tmp_path.find("/pkgconfig/") != std::string::npos) { |
| return 0; |
| } |
| if (!(s->st_mode & permission_entry.e_mode)) { |
| if (fix_flag) { |
| if (chmod(path, s->st_mode | permission_entry.e_mode) < 0) { |
| ink_warning("Unable to change file mode on %s - %s", path, strerror(errno)); |
| } else { |
| std::cout << "Fixed execute permission: " << path << std::endl; |
| } |
| } else { |
| std::cout << "Execute permission failed for file: " << path << std::endl; |
| ret = -1; |
| } |
| } |
| } |
| } |
| return ret; |
| } |
| |
| // used for prefix, exec_prefix and localstatedir |
| // only check the read/execute permission on those directories |
| static bool |
| check_directory_permission(const char *path) |
| { |
| struct stat stat_buffer; |
| if (stat(path, &stat_buffer) < 0) { |
| ink_warning("unable to stat() destination path %s - %s", path, strerror(errno)); |
| return false; |
| } |
| if (!(stat_buffer.st_mode & permission_entry.r_mode)) { |
| std::cout << "Read permission failed for: " << path << std::endl; |
| return false; |
| } |
| if (!(stat_buffer.st_mode & permission_entry.e_mode)) { |
| std::cout << "Execute permission failed for: " << path << std::endl; |
| return false; |
| } |
| return true; |
| } |
| |
| #if defined(darwin) |
| // on Darwin, getgrouplist() takes int. |
| using gid_type = int; |
| #else |
| using gid_type = gid_t; |
| #endif |
| |
| // helper function to check if user is from the same group of path_gid |
| static bool |
| from_group(const char *user, gid_type group_id, gid_type path_gid) |
| { |
| int ngroups = MAX_GROUP_NUM; |
| gid_type groups[ngroups]; |
| if (getgrouplist(user, group_id, groups, &ngroups) == -1) { |
| ink_warning("Unable to get group list as user '%s'\n", user); |
| return false; |
| } |
| for (int i = 0; i < ngroups; i++) { |
| if (path_gid == groups[i]) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| // set permission to the map in verify runroot |
| static void |
| set_permission(PermissionMapType &permission_map, const struct passwd *pwd) |
| { |
| gid_t ts_gid = pwd->pw_gid; |
| uid_t ts_uid = pwd->pw_uid; |
| bool new_line = false; |
| |
| // set up permission map for all permissions |
| for (auto &it : permission_map) { |
| std::string name = it.first; |
| std::string value = it.second.path; |
| |
| struct stat stat_buffer; |
| if (stat(value.c_str(), &stat_buffer) < 0) { |
| ink_warning("unable to stat() destination path %s - %s", value.c_str(), strerror(errno)); |
| it.second.result = false; |
| new_line = true; |
| continue; |
| } |
| gid_t path_gid = stat_buffer.st_gid; |
| uid_t path_uid = stat_buffer.st_uid; |
| |
| if (ts_uid == path_uid) { |
| it.second.r_mode = S_IRUSR; |
| it.second.w_mode = S_IWUSR; |
| it.second.e_mode = S_IXUSR; |
| } else if (from_group(pwd->pw_name, ts_gid, path_gid)) { |
| it.second.r_mode = S_IRGRP; |
| it.second.w_mode = S_IWGRP; |
| it.second.e_mode = S_IXGRP; |
| } else { |
| it.second.r_mode = S_IROTH; |
| it.second.w_mode = S_IWOTH; |
| it.second.e_mode = S_IXOTH; |
| } |
| // set the result in permission entry |
| permission_entry = it.second; |
| it.second.result = true; |
| // Special case with prefix, exec_prefix and localstatedir. We only need to check the directory itself |
| // but not the files within because they are just container dir for others. |
| if (name == LAYOUT_PREFIX || name == LAYOUT_EXEC_PREFIX || name == LAYOUT_LOCALSTATEDIR) { |
| if (!check_directory_permission(value.c_str())) { |
| it.second.result = false; |
| new_line = true; |
| } |
| } else { |
| // go through all files to check permission |
| if (ftw(value.c_str(), permission_handler, OPEN_MAX_FILE) != 0) { |
| it.second.result = false; |
| new_line = true; |
| } |
| } |
| } |
| if (new_line) { |
| std::cout << std::endl; // print a new line after the failed permission messages |
| } |
| } |
| |
| // the fixing permission of runroot used by verify command |
| static void |
| fix_runroot(PermissionMapType &permission_map, const struct passwd *pwd) |
| { |
| fix_flag = true; |
| for (const auto &it : permission_map) { |
| std::string name = it.first; |
| std::string value = it.second.path; |
| permission_entry = permission_map[name]; |
| ftw(value.c_str(), permission_handler, OPEN_MAX_FILE); |
| } |
| fix_flag = false; |
| set_permission(permission_map, pwd); |
| } |
| |
| void |
| LayoutEngine::verify_runroot() |
| { |
| // require sudo permission for --fix |
| if (arguments.get("fix") && getuid() != 0) { |
| ink_error("To fix permission issues, root privilege is required.\nPlease run with sudo."); |
| status_code = EX_SOFTWARE; |
| return; |
| } |
| |
| // retrieve information |
| std::string path = path_handler(arguments.get("path").value(), false, _argv[0]); |
| std::string user; |
| char user_buf[MAX_LOGIN + 1]; |
| if (arguments.get("with-user")) { |
| user = arguments.get("with-user").value(); |
| } else { |
| RecProcessInit(RECM_STAND_ALONE, nullptr /* diags */); |
| LibRecordsConfigInit(); |
| if (RecGetRecordString("proxy.config.admin.user_id", user_buf, sizeof(user_buf)) != 0 || strlen(user_buf) == 0) { |
| user = user_buf; |
| } else { |
| user = TS_PKGSYSUSER; |
| } |
| } |
| // Numeric user notation for user |
| if (user[0] == '#') { |
| struct passwd *pwd = getpwuid(atoi(&user[1])); |
| if (!pwd) { |
| ink_error("No user found under id '%s'", user.c_str()); |
| status_code = EX_OSERR; |
| return; |
| } |
| user = pwd->pw_name; |
| } |
| std::cout << "Verifying permission as user: \x1b[1m" << user << "\x1b[0m" << std::endl << std::endl; |
| // try to find the user from password file |
| struct passwd *pwd = getpwnam(user.c_str()); |
| if (!pwd) { |
| ink_error("No user found under name '%s'", user.c_str()); |
| status_code = EX_OSERR; |
| return; |
| } |
| // put paths from yaml file or default paths to path_map |
| RunrootMapType path_map; |
| if (path.empty()) { |
| path_map = runroot_map_default(); |
| } else { |
| path_map = runroot_map(Layout::relative_to(path, "runroot.yaml")); |
| } |
| // setup the permission map |
| PermissionMapType permission_map; |
| for (const auto &it : dir_vector) { |
| permission_map[it].name = it; |
| permission_map[it].path = path_map[it]; |
| } |
| // root always has full access and no need to check for root |
| if (user != "root") { |
| set_permission(permission_map, pwd); |
| // if --fix is used |
| if (arguments.get("fix")) { |
| fix_runroot(permission_map, pwd); |
| } |
| } |
| |
| // display pass or fail for permission required |
| for (const auto &it : dir_vector) { |
| if (permission_map[it].result) { |
| std::cout << it << ": \x1b[1m" << path_map[it] << "\x1b[0m \033[1;32mPASSED\033[0m" << std::endl; |
| } else { |
| std::cout << it << ": \x1b[1m" << path_map[it] << "\x1b[0m \033[1;31mFAILED\033[0m" << std::endl; |
| status_code = EX_SOFTWARE; |
| } |
| } |
| } |