MESSAGE(STATUS "")
MESSAGE(STATUS "Generating makefile for the liblxcpp...")
FILE(GLOB HEADERS *.hpp)
-FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/fd-utils.hpp
- ${COMMON_FOLDER}/utils/exception.hpp
- ${COMMON_FOLDER}/utils/channel.hpp
- ${COMMON_FOLDER}/utils/environment.hpp
- ${COMMON_FOLDER}/utils/execute.hpp)
+FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/fd-utils.hpp
+ ${COMMON_FOLDER}/utils/exception.hpp
+ ${COMMON_FOLDER}/utils/channel.hpp
+ ${COMMON_FOLDER}/utils/environment.hpp
+ ${COMMON_FOLDER}/utils/execute.hpp)
FILE(GLOB HEADERS_NETLINK ${COMMON_FOLDER}/netlink/*.hpp)
+FILE(GLOB HEADERS_COMMANDS commands/*.hpp)
+
FILE(GLOB SRCS *.cpp *.hpp)
FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/fd-utils.cpp
${COMMON_FOLDER}/utils/exception.cpp
${COMMON_FOLDER}/utils/environment.cpp
${COMMON_FOLDER}/utils/execute.cpp)
FILE(GLOB SRCS_NETLINK ${COMMON_FOLDER}/netlink/*.cpp)
+FILE(GLOB SRCS_COMMANDS commands/*.cpp)
SET(_LIB_VERSION_ "${VERSION}")
SET(_LIB_SOVERSION_ "0")
SET(PC_FILE "lib${PROJECT_NAME}.pc")
## Setup target ################################################################
-ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_UTILS} ${SRCS_NETLINK})
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_UTILS} ${SRCS_NETLINK} ${SRCS_COMMANDS})
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
SOVERSION ${_LIB_SOVERSION_}
VERSION ${_LIB_VERSION_}
DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/utils)
INSTALL(FILES ${HEADERS_NETLINK}
DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/netlink)
+INSTALL(FILES ${HEADERS_COMMANDS}
+ DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/commands)
* @brief Implementation of attaching to a container
*/
-#include "lxcpp/attach-manager.hpp"
+#include "lxcpp/commands/attach-manager.hpp"
#include "lxcpp/exception.hpp"
#include "lxcpp/process.hpp"
#include "lxcpp/filesystem.hpp"
#include "lxcpp/namespace.hpp"
#include "lxcpp/capability.hpp"
+#include "lxcpp/environment.hpp"
#include "utils/exception.hpp"
#include <unistd.h>
#include <sys/mount.h>
+#include <functional>
namespace lxcpp {
*/
}
+int execFunction(void* call)
+{
+ try {
+ return (*static_cast<AttachManager::Call*>(call))();
+ } catch(...) {
+ return -1; // Non-zero on failure
+ }
+ return 0; // Success
+}
+
} // namespace
AttachManager::AttachManager(lxcpp::ContainerImpl& container)
{
}
-void AttachManager::attach(Container::AttachCall& call,
- const std::string& wdInContainer)
+void AttachManager::attach(Container::AttachCall& userCall,
+ const int capsToKeep,
+ const std::string& workDirInContainer,
+ const std::vector<std::string>& envToKeep,
+ const std::vector<std::pair<std::string, std::string>>& envToSet)
{
// Channels for setup synchronization
utils::Channel intermChannel;
+ Call call = std::bind(&AttachManager::child,
+ std::move(userCall),
+ capsToKeep,
+ std::move(envToKeep),
+ std::move(envToSet));
+
const pid_t interPid = lxcpp::fork();
if (interPid > 0) {
intermChannel.setLeft();
intermChannel.shutdown();
} else {
intermChannel.setRight();
- interm(intermChannel, wdInContainer, call);
+ interm(intermChannel, workDirInContainer, call);
intermChannel.shutdown();
::_exit(0);
}
}
-int AttachManager::child(void* data)
+int AttachManager::child(const Container::AttachCall& call,
+ const int capsToKeep,
+ const std::vector<std::string>& envToKeep,
+ const std::vector<std::pair<std::string, std::string>>& envToSet)
{
- try {
- // TODO Pass mask and options via data
- dropCapsFromBoundingExcept(0);
- setupMountPoints();
- return (*static_cast<Container::AttachCall*>(data))();
- } catch(...) {
- return -1; // Non-zero on failure
- }
- return 0; // Success
+ // Setup capabilities
+ dropCapsFromBoundingExcept(capsToKeep);
+
+ // Setup /proc /sys mount
+ setupMountPoints();
+
+ // Setup environment variables
+ clearenvExcept(envToKeep);
+ setenv(envToSet);
+
+ // Run user's code
+ return call();
}
void AttachManager::parent(utils::Channel& intermChannel, const pid_t interPid)
}
void AttachManager::interm(utils::Channel& intermChannel,
- const std::string& wdInContainer,
- Container::AttachCall& call)
+ const std::string& workDirInContainer,
+ Call& call)
{
lxcpp::setns(mContainer.getInitPid(), mContainer.getNamespaces());
// Change the current work directory
- // wdInContainer is a path relative to the container's root
- lxcpp::chdir(wdInContainer);
+ // workDirInContainer is a path relative to the container's root
+ lxcpp::chdir(workDirInContainer);
// PID namespace won't affect the returned pid
// CLONE_PARENT: Child's PPID == Caller's PID
- const pid_t childPid = lxcpp::clone(&AttachManager::child,
+ const pid_t childPid = lxcpp::clone(execFunction,
&call,
CLONE_PARENT);
intermChannel.write(childPid);
class AttachManager final {
public:
+ typedef std::function<int(void)> Call;
+
AttachManager(lxcpp::ContainerImpl& container);
~AttachManager();
* Runs the call in the container's context
*
* @param call function to run inside container
- * @param wdInContainer Current Work Directory. Path relative to container's root
+ * @param capsToKeep mask of the capabilities that shouldn't be dropped
+ * @param workDirInContainer Current Work Directory. Path relative to container's root
+ * @param envToKeep environment variables to keep in container
+ * @param envToSet environment variables to add/modify in container
*/
void attach(Container::AttachCall& call,
- const std::string& wdInContainer);
+ const int capsToKeep,
+ const std::string& workDirInContainer,
+ const std::vector<std::string>& envToKeep,
+ const std::vector<std::pair<std::string, std::string>>& envToSet);
private:
+
const lxcpp::ContainerImpl& mContainer;
// Methods for different stages of setting up the attachment
- static int child(void* data);
+ static int child(const Container::AttachCall& call,
+ const int capsToKeep,
+ const std::vector<std::string>& envToKeep,
+ const std::vector<std::pair<std::string, std::string>>& envToSet);
void parent(utils::Channel& intermChannel,
const pid_t pid);
void interm(utils::Channel& intermChannel,
- const std::string& wdInContainer,
+ const std::string& workDirInContainer,
Container::AttachCall& call);
};
#include "lxcpp/filesystem.hpp"
#include "lxcpp/namespace.hpp"
#include "lxcpp/capability.hpp"
-#include "lxcpp/attach-manager.hpp"
+#include "lxcpp/commands/attach-manager.hpp"
#include "utils/exception.hpp"
const std::string& cwdInContainer)
{
AttachManager attachManager(*this);
- attachManager.attach(call, cwdInContainer);
+ // TODO: Env variables should agree with the ones already in the container
+ attachManager.attach(call,
+ /*capsToKeep*/ 0,
+ cwdInContainer,
+ /*envToKeep*/ {},
+ /*envInContainer*/{{"container","lxcpp"}} );
}
const std::vector<Namespace>& ContainerImpl::getNamespaces() const
}
void ContainerImpl::createInterface(const std::string& hostif,
- const std::string& zoneif,
- InterfaceType type,
- MacVLanMode mode)
+ const std::string& zoneif,
+ InterfaceType type,
+ MacVLanMode mode)
{
NetworkInterface ni(*this, zoneif);
ni.create(hostif, type, mode);
class Container {
public:
- typedef std::function<int()> AttachCall;
+ typedef std::function<int(void)> AttachCall;
virtual ~Container() {};
--- /dev/null
+/*
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief Handling environment variables
+ */
+
+#include "lxcpp/environment.hpp"
+#include "lxcpp/exception.hpp"
+
+#include "logger/logger.hpp"
+#include "utils/exception.hpp"
+
+#include <stdlib.h>
+
+namespace lxcpp {
+
+void clearenvExcept(const std::vector<std::string>& names)
+{
+ // Backup keeps pairs (name,value)
+ std::vector<std::pair< std::string,std::string>> backup;
+ for(const auto& name: names) {
+ try {
+ backup.push_back({name, lxcpp::getenv(name)});
+ } catch(const NoSuchValue&) {
+ // Continue if there's no such variable
+ }
+ }
+
+ lxcpp::clearenv();
+
+ // Restore backup
+ lxcpp::setenv(backup);
+}
+
+void clearenv()
+{
+ if(::clearenv()) {
+ const std::string msg = "clearenv() failed: " +
+ utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw EnvironmentSetupException(msg);
+ }
+}
+
+std::string getenv(const std::string& name)
+{
+ const char* value = ::getenv(name.c_str());
+ if (!value) {
+ const std::string msg = "getenv() failed: No such name";
+ LOGW(msg);
+ throw NoSuchValue(msg);
+ }
+ return value;
+}
+
+void setenv(const std::string& name, const std::string& value)
+{
+ if (-1 == ::setenv(name.c_str(),
+ value.c_str(),
+ 1 /*write if exists*/)) {
+ const std::string msg = "setenv() failed. Not all env set. " +
+ utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw EnvironmentSetupException(msg);
+ }
+}
+
+void setenv(const std::vector<std::pair<std::string, std::string>>& variables)
+{
+ for(const auto& variable: variables) {
+ lxcpp::setenv(variable.first, variable.second);
+ }
+}
+
+} // namespace lxcpp
--- /dev/null
+/*
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * @author Jan Olszak (j.olszak@samsung.com)
+ * @brief Handling environment variables
+ */
+
+#ifndef LXCPP_ENVIRONMENT_HPP
+#define LXCPP_ENVIRONMENT_HPP
+
+#include <vector>
+#include <utility>
+#include <string>
+
+namespace lxcpp {
+
+void clearenv();
+
+/**
+ * Clears the env variables except those listed.
+ * There's a race condition - a moment when listed variables aren't set
+ * Function should be used only for setting up a new process.
+ *
+ * @param names names of the variables to keep
+ */
+void clearenvExcept(const std::vector<std::string>& names);
+
+std::string getenv(const std::string& name);
+
+void setenv(const std::string& name, const std::string& value);
+
+void setenv(const std::vector<std::pair<std::string, std::string>>& variables);
+
+} // namespace lxcpp
+
+#endif // LXCPP_ENVIRONMENT_HPP
: Exception(message) {}
};
+struct EnvironmentSetupException: public Exception {
+ EnvironmentSetupException(const std::string& message = "Error during handling environment variables")
+ : Exception(message) {}
+};
+
struct CapabilitySetupException: public Exception {
CapabilitySetupException(const std::string& message = "Error during a capability operation")
: Exception(message) {}
: Exception(message) {}
};
+struct NoSuchValue: public Exception {
+ NoSuchValue(const std::string& message = "Value not found")
+ : Exception(message) {}
+};
+
struct NetworkException : public Exception {
NetworkException (const std::string& message = "Error during setting up a network")
: Exception(message) {}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Jan Olszak(j.olszak@samsung.com)
+ *
+ * Licensed 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
+ */
+
+
+/**
+ * @file
+ * @author Jan Olszak(j.olszak@samsung.com)
+ * @brief Unit tests of lxcpp namespace helpers
+ */
+
+#include "config.hpp"
+#include "ut.hpp"
+
+#include "lxcpp/environment.hpp"
+#include "lxcpp/exception.hpp"
+#include "lxcpp/namespace.hpp"
+#include "lxcpp/process.hpp"
+
+#include "utils/execute.hpp"
+
+#include <iostream>
+#include <sched.h>
+#include <stdlib.h>
+
+namespace {
+
+struct Fixture {
+ Fixture() {}
+ ~Fixture() {}
+};
+
+const int TEST_PASSED = 0;
+const int ERROR = 1;
+
+const std::string TEST_NAME = "TEST_NAME";
+const std::string TEST_VALUE = "TEST_VALUE";
+
+const std::string TEST_NAME_REMOVED = "TEST_NAME_REMOVED";
+const std::string TEST_VALUE_REMOVED = "TEST_VALUE_REMOVED";
+
+} // namespace
+
+BOOST_FIXTURE_TEST_SUITE(LxcppEnvironmentSuite, Fixture)
+
+using namespace lxcpp;
+
+BOOST_AUTO_TEST_CASE(SetGetEnv)
+{
+ pid_t pid = lxcpp::fork();
+ if (pid == 0) {
+ try {
+ lxcpp::setenv(TEST_NAME, TEST_VALUE);
+
+ if(lxcpp::getenv(TEST_NAME) == TEST_VALUE) {
+ ::_exit(TEST_PASSED);
+ }
+ ::_exit(ERROR);
+ } catch(...) {
+ ::_exit(ERROR);
+ }
+ } else if (pid > 0) {
+ int status = -1;
+ BOOST_REQUIRE(utils::waitPid(pid, status));
+ BOOST_REQUIRE(status == TEST_PASSED);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(ClearEnvExcept)
+{
+ pid_t pid = lxcpp::fork();
+ if (pid == 0) {
+ try {
+ lxcpp::setenv(TEST_NAME, TEST_VALUE);
+ lxcpp::setenv(TEST_NAME_REMOVED, TEST_VALUE_REMOVED);
+
+ clearenvExcept({TEST_NAME});
+
+ try {
+ lxcpp::getenv(TEST_NAME_REMOVED);
+ } catch(const lxcpp::NoSuchValue&) {
+ if(lxcpp::getenv(TEST_NAME) == TEST_VALUE) {
+ ::_exit(TEST_PASSED);
+ }
+ }
+ ::_exit(ERROR);
+ } catch(...) {
+ ::_exit(ERROR);
+ }
+ } else if (pid > 0) {
+ int status = -1;
+ BOOST_REQUIRE(utils::waitPid(pid, status));
+ BOOST_REQUIRE(status == TEST_PASSED);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(ClearEnv)
+{
+ pid_t pid = lxcpp::fork();
+ if (pid == 0) {
+ try {
+ lxcpp::setenv(TEST_NAME_REMOVED, TEST_VALUE_REMOVED);
+ lxcpp::clearenv();
+
+ // clearenv should clear environ
+ if (::environ) {
+ ::_exit(ERROR);
+ }
+
+ try {
+ lxcpp::getenv(TEST_NAME_REMOVED);
+ } catch(const lxcpp::NoSuchValue&) {
+ ::_exit(TEST_PASSED);
+ }
+ ::_exit(ERROR);
+ } catch(...) {
+ ::_exit(ERROR);
+ }
+ } else if (pid > 0) {
+ int status = -1;
+ BOOST_REQUIRE(utils::waitPid(pid, status));
+ BOOST_REQUIRE(status == TEST_PASSED);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()