From 174a63f7a3054a92861e3fc929398a7330d2b81d Mon Sep 17 00:00:00 2001 From: Kamil Iskra Date: Thu, 14 Dec 2017 16:17:54 -0600 Subject: [PATCH] Add exec support --- src/argo_nodeos_config.cpp | 18 +++++++++- src/container_manager.cpp | 69 ++++++++++++++++++++++++++++++++++---- src/container_manager.hpp | 4 +++ 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/argo_nodeos_config.cpp b/src/argo_nodeos_config.cpp index 00926e6..5b5bc77 100644 --- a/src/argo_nodeos_config.cpp +++ b/src/argo_nodeos_config.cpp @@ -524,7 +524,10 @@ enum Option_val OV_DELETE_SERVICE_OS, - OV_RESET + OV_RESET, + + /*--exec="name:'c0' argv='argv0 argv1'"*/ + OV_EXEC }; @@ -546,6 +549,7 @@ struct option long_options[] = { {"detach_from_container", required_argument, NULL, OV_DETACH_FROM_CONTAINER}, {"migrate_to_container", required_argument, NULL, OV_MIGRATE_TO_CONTAINER}, {"reset", no_argument, NULL, OV_RESET}, + {"exec", required_argument, NULL, OV_EXEC}, {0, 0, 0, 0} }; @@ -683,6 +687,9 @@ bool parse_for_node_config(int argc, char** argv, Container_manager& cm) case OV_RESET: cm.reset(); break; + case OV_EXEC: + cm.exec(optarg); + break; case '?': case ':': cmd_error = true; @@ -757,10 +764,19 @@ int main(int argc, char** argv) argo_exit(EXIT_FAILURE, e.what()); } + char** exec_argv = cm->get_exec_argv(); delete cm; rlock.unlock(); release(); + + /* We perform the execve(2) after all the cleanup is done. */ + if (exec_argv) + { + execv(exec_argv[0], exec_argv); + argo_exit(EXIT_FAILURE, "Command execution failed", errno); + } + argo_exit(EXIT_SUCCESS); return 0; } diff --git a/src/container_manager.cpp b/src/container_manager.cpp index d79cced..14f53f8 100644 --- a/src/container_manager.cpp +++ b/src/container_manager.cpp @@ -869,7 +869,7 @@ void Container_manager::attach_to_container(string command) string name; sp.get_string("name", name); Argo_container *cc = find_by_name(name); - THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + "does not exists"); + THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + " does not exists"); vector tasks; sp.get_int_list("pids", tasks); @@ -924,7 +924,7 @@ void Container_manager::detach_from_container(string command) string name; sp.get_string("name", name); Argo_container *cc = find_by_name(name); - THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + "does not exists"); + THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + " does not exists"); vector tasks; sp.get_int_list("pids", tasks); @@ -949,7 +949,7 @@ void Container_manager::migrate_to_container(string command) string name; sp.get_string("name", name); Argo_container *cc = find_by_name(name); - THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + "does not exists"); + THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + " does not exists"); vector tasks; sp.get_int_list("pids", tasks); @@ -964,12 +964,13 @@ void Container_manager::migrate_to_container(string command) " because it belongs to another user! Alternatively, the action can be performed as root"); std::ostringstream oss; - for(auto task : tasks) + for(vector::iterator task = tasks.begin(); task != tasks.end(); task++) { bool is_task_contained = false; - for(auto cont : _containers) + for(vector::iterator cont = _containers.begin(); + cont != _containers.end(); cont++) { - if(cont->has_task(task)) + if((*cont)->has_task(*task)) { is_task_contained = true; break; @@ -977,7 +978,7 @@ void Container_manager::migrate_to_container(string command) } if(!is_task_contained) { - oss<<"Task "<log(LOG_TYPE_INFO, "Config has been cleaned."); } + +void Container_manager::exec(string command) +{ + String_parser sp(command); + sp.parse(); + + THROW_ON_BAD_INPUT_IF(!sp.has_key("name") || !sp.has_key("argv"), + "Bad exec command"); + string name; + sp.get_string("name", name); + + Argo_container *cc = find_by_name(name); + + THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + " does not exists"); + + THROW_ON_FORBIDDEN_ACTION_IF(ruid != 0 && (ruid != cc->get_owner()), + "Can't execute in container " + cc->get_name() + + " because it belongs to another user! Alternatively, the action can be performed as root"); + + string argv; + sp.get_string("argv", argv); + + if (argv[0] == '\'') /* Strip ' from both ends. */ + argv = argv.substr(1, argv.size() - 2); + + vector argvs; + split(argv, ' ', argvs); + + /* Remove a single layer of backslashes. */ + for (vector::iterator i = argvs.begin(); i != argvs.end(); ++i) + for (auto j = i->begin(); j != i->end(); ++j) + if (*j == '\\') + i->erase(j); + + vector tasks(1, getpid()); + cc->add_tasks(tasks); + cc->commit_last_changes(); + + std::ostringstream ss; + ss << "About to execute"; + + /* We use global allocators so that _exec_argv survives after + the container manager is destroyed. */ + _exec_argv = new char*[argvs.size() + 1]; + for (int i = 0; i < argvs.size(); i++) + { + _exec_argv[i] = new char[argvs[i].size() + 1]; + strcpy(_exec_argv[i], argvs[i].c_str()); + ss << " '" << argvs[i] << "'"; + } + _exec_argv[argvs.size()] = NULL; + + _logger->log(LOG_TYPE_INFO, ss.str()); +} diff --git a/src/container_manager.hpp b/src/container_manager.hpp index e554c15..a33a34c 100644 --- a/src/container_manager.hpp +++ b/src/container_manager.hpp @@ -33,6 +33,8 @@ class Container_manager string _argo_service_os_cgroup; string _argo_argo_containers_root; + char ** _exec_argv; + Container_manager(Container_manager& orig) = delete; Container_manager& operator = (const Container_manager& orig) = delete; @@ -232,6 +234,7 @@ class Container_manager inline const string* const get_argo_argo_container_root() const {return &_cgroup_root;} inline Error_behavior get_error_behaviour()const {return _error_behavior;} inline ILogger* get_logger() const {return _logger;} + inline char** get_exec_argv() const {return _exec_argv;} void show_available_resources(string command); void create_container(string command); @@ -247,6 +250,7 @@ class Container_manager void alter_service_os(string command); void delete_service_os(); void reset(); + void exec(string command); }; #endif // __CONTAINER_MANAGER_HPP__ -- 2.26.2