From 54a315716b6773507cc0bffa236f10f11c5d2400 Mon Sep 17 00:00:00 2001
From: Pawel Kubik
Date: Mon, 14 Sep 2015 12:20:36 +0200
Subject: [PATCH 01/16] CLI bash completion fix
[Feature] CLI bash completion fix
[Cause] Bash completion broken after commit 4a9c93f
[Solution] Bash completion script template fix
[Verification] Build, install, check CLI completion
Change-Id: Iff043a983d042e4181b33b0f6c4e415befcc22ed
---
cli/support/vsm-completion.sh.in | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/cli/support/vsm-completion.sh.in b/cli/support/vsm-completion.sh.in
index 74a02a5..704e162 100755
--- a/cli/support/vsm-completion.sh.in
+++ b/cli/support/vsm-completion.sh.in
@@ -2,8 +2,13 @@
[ -z "$BASH_VERSION" ] && return
__@PROJECT_NAME@_cli() {
- words=`@CLI_CODENAME@ --bash-completion ${COMP_WORDS[COMP_CWORD]}`
- COMPREPLY=($(compgen -W "$words" -- ${COMP_WORDS[COMP_CWORD]}))
+ if [ "${COMP_WORDS[COMP_CWORD]}" = "" ]; then
+ comp="''"
+ else
+ comp=
+ fi
+ words=`@CLI_CODENAME@ --bash-completion $(echo "${COMP_WORDS[@]:1}" | sed 's/ = /=/g') $comp`
+ COMPREPLY=($(compgen -W "$words" -- "${COMP_WORDS[COMP_CWORD]}"))
}
complete -F __@PROJECT_NAME@_cli vsm
--
2.7.4
From 3166537b1ec126be9343551b0d7801a89c08e637 Mon Sep 17 00:00:00 2001
From: Jan Olszak
Date: Wed, 16 Sep 2015 11:22:22 +0200
Subject: [PATCH 02/16] lxcpp: Setting up the control terminal
[Feature] Setting up the control terminal in Attach
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I6b1dced4f9a16c04e82b122679f86b90be29d3d1
---
libs/lxcpp/commands/attach.cpp | 51 +++++++++++++++++++++++++++++++++++++++++-
libs/lxcpp/commands/attach.hpp | 3 +++
libs/lxcpp/container-impl.cpp | 1 +
libs/lxcpp/credentials.hpp | 2 --
4 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/libs/lxcpp/commands/attach.cpp b/libs/lxcpp/commands/attach.cpp
index 0ff856e..01a811b 100644
--- a/libs/lxcpp/commands/attach.cpp
+++ b/libs/lxcpp/commands/attach.cpp
@@ -31,9 +31,13 @@
#include "lxcpp/credentials.hpp"
#include "utils/exception.hpp"
+#include "utils/fd-utils.hpp"
+#include "logger/logger.hpp"
#include
#include
+#include
+#include
#include
@@ -67,6 +71,35 @@ void setupMountPoints()
*/
}
+bool setupControlTTY(const int ttyFD)
+{
+ if (!::isatty(ttyFD)) {
+ return false;
+ }
+
+ if (::setsid() < 0) {
+ return false;
+ }
+
+ if (::ioctl(ttyFD, TIOCSCTTY, NULL) < 0) {
+ return false;
+ }
+
+ if (::dup2(ttyFD, STDIN_FILENO) < 0) {
+ return false;
+ }
+
+ if (::dup2(ttyFD, STDOUT_FILENO) < 0) {
+ return false;
+ }
+
+ if (::dup2(ttyFD, STDERR_FILENO) < 0) {
+ return false;
+ }
+
+ return true;
+}
+
int execFunction(void* call)
{
try {
@@ -83,6 +116,7 @@ Attach::Attach(lxcpp::ContainerImpl& container,
Container::AttachCall& userCall,
const uid_t uid,
const gid_t gid,
+ const std::string& ttyPath,
const std::vector& supplementaryGids,
const int capsToKeep,
const std::string& workDirInContainer,
@@ -98,10 +132,18 @@ Attach::Attach(lxcpp::ContainerImpl& container,
mEnvToKeep(envToKeep),
mEnvToSet(envToSet)
{
+ mTTYFD = ::open(ttyPath.c_str(), O_RDWR | O_NOCTTY);
+ if (mTTYFD < 0) {
+ const std::string msg = "open() failed: " +
+ utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw BadArgument(msg);
+ }
}
Attach::~Attach()
{
+ utils::close(mTTYFD);
}
void Attach::execute()
@@ -113,6 +155,7 @@ void Attach::execute()
mUserCall,
mUid,
mGid,
+ mTTYFD,
mSupplementaryGids,
mCapsToKeep,
mEnvToKeep,
@@ -127,13 +170,14 @@ void Attach::execute()
intermChannel.setRight();
interm(intermChannel, call);
intermChannel.shutdown();
- ::_exit(0);
+ ::_exit(EXIT_SUCCESS);
}
}
int Attach::child(const Container::AttachCall& call,
const uid_t uid,
const gid_t gid,
+ const int ttyFD,
const std::vector& supplementaryGids,
const int capsToKeep,
const std::vector& envToKeep,
@@ -155,6 +199,11 @@ int Attach::child(const Container::AttachCall& call,
lxcpp::setuid(uid);
+ // Set control TTY
+ if(!setupControlTTY(ttyFD)) {
+ ::_exit(EXIT_FAILURE);
+ }
+
// Run user's code
return call();
}
diff --git a/libs/lxcpp/commands/attach.hpp b/libs/lxcpp/commands/attach.hpp
index 36c57ba..2c1f365 100644
--- a/libs/lxcpp/commands/attach.hpp
+++ b/libs/lxcpp/commands/attach.hpp
@@ -58,6 +58,7 @@ public:
Container::AttachCall& userCall,
const uid_t uid,
const gid_t gid,
+ const std::string& ttyPath,
const std::vector& supplementaryGids,
const int capsToKeep,
const std::string& workDirInContainer,
@@ -72,6 +73,7 @@ private:
const Container::AttachCall& mUserCall;
const uid_t mUid;
const gid_t mGid;
+ int mTTYFD;
const std::vector& mSupplementaryGids;
const int mCapsToKeep;
const std::string& mWorkDirInContainer;
@@ -82,6 +84,7 @@ private:
static int child(const Container::AttachCall& call,
const uid_t uid,
const gid_t gid,
+ const int ttyFD,
const std::vector& supplementaryGids,
const int capsToKeep,
const std::vector& envToKeep,
diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp
index 73e5254..8249009 100644
--- a/libs/lxcpp/container-impl.cpp
+++ b/libs/lxcpp/container-impl.cpp
@@ -152,6 +152,7 @@ void ContainerImpl::attach(Container::AttachCall& call,
call,
/*uid in container*/ 0,
/*gid in container*/ 0,
+ "/dev/tty",
/*supplementary gids in container*/ {},
/*capsToKeep*/ 0,
cwdInContainer,
diff --git a/libs/lxcpp/credentials.hpp b/libs/lxcpp/credentials.hpp
index df00ce5..ab1a490 100644
--- a/libs/lxcpp/credentials.hpp
+++ b/libs/lxcpp/credentials.hpp
@@ -36,8 +36,6 @@ void setgid(const gid_t gid);
void setuid(const uid_t uid);
-
-
} // namespace lxcpp
#endif // LXCPP_CREDENTIALS_HPP
\ No newline at end of file
--
2.7.4
From 61e31300c53fb090f48930f4d4462e6bc9218be1 Mon Sep 17 00:00:00 2001
From: Lukasz Pawelczyk
Date: Wed, 29 Jul 2015 13:27:25 +0200
Subject: [PATCH 03/16] lxcpp: Initial implementation of the start API call
[Feature] Initial implementation of the start API call.
[Verification] Build, install, run tests
Significant changes related to the start API call:
- Start command that daemonizes and execs guard binary
- Guard process implementation that execs the container's init
Additional changes in this commit supporting the Start API call:
- API extension to Channel class, support close on exec and be able
to survive (as a FD) exec() call
- set close on exec in persistent file logger
- new logger helper to setup the logger
- add pid to the log format
Change-Id: I2d9648e2a861add2aa1bd1d66587bff2a109cc9c
---
CMakeLists.txt | 8 +-
common/utils/channel.cpp | 55 ++++++++++++-
common/utils/channel.hpp | 27 ++++++-
libs/logger/backend-persistent-file.hpp | 9 ++-
libs/logger/formatter.cpp | 5 +-
libs/logger/level.hpp | 2 +-
libs/logger/logger.cpp | 38 +++++++++
libs/logger/logger.hpp | 28 ++++++-
libs/lxcpp/CMakeLists.txt | 10 ++-
libs/lxcpp/commands/attach.cpp | 2 +
libs/lxcpp/commands/start.cpp | 135 ++++++++++++++++++++++++++++++++
libs/lxcpp/commands/start.hpp | 66 ++++++++++++++++
libs/lxcpp/container-config.hpp | 111 ++++++++++++++++++++++++++
libs/lxcpp/container-impl.cpp | 12 ++-
libs/lxcpp/container-impl.hpp | 28 ++-----
libs/lxcpp/container.hpp | 5 ++
libs/lxcpp/exception.hpp | 5 ++
libs/lxcpp/guard/CMakeLists.txt | 37 +++++++++
libs/lxcpp/guard/guard.cpp | 100 +++++++++++++++++++++++
libs/lxcpp/guard/guard.hpp | 39 +++++++++
libs/lxcpp/guard/main.cpp | 49 ++++++++++++
libs/lxcpp/logger-config.cpp | 48 ++++++++++++
libs/lxcpp/logger-config.hpp | 65 +++++++++++++++
libs/lxcpp/utils.cpp | 122 +++++++++++++++++++++++++++++
libs/lxcpp/utils.hpp | 54 +++++++++++++
packaging/vasum.spec | 1 +
26 files changed, 1022 insertions(+), 39 deletions(-)
create mode 100644 libs/lxcpp/commands/start.cpp
create mode 100644 libs/lxcpp/commands/start.hpp
create mode 100644 libs/lxcpp/container-config.hpp
create mode 100644 libs/lxcpp/guard/CMakeLists.txt
create mode 100644 libs/lxcpp/guard/guard.cpp
create mode 100644 libs/lxcpp/guard/guard.hpp
create mode 100644 libs/lxcpp/guard/main.cpp
create mode 100644 libs/lxcpp/logger-config.cpp
create mode 100644 libs/lxcpp/logger-config.hpp
create mode 100644 libs/lxcpp/utils.cpp
create mode 100644 libs/lxcpp/utils.hpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5b98eee..0409167 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -143,10 +143,10 @@ ENDIF(NOT DEFINED PYTHON_SITELIB)
SET(COMMON_FOLDER ${PROJECT_SOURCE_DIR}/common)
SET(LIBS_FOLDER ${PROJECT_SOURCE_DIR}/libs)
SET(LOGGER_FOLDER ${PROJECT_SOURCE_DIR}/libs/logger)
-SET(LXCPP_FOLDER ${PROJECT_SOURCE_DIR}/libs/lxcpp)
SET(DBUS_FOLDER ${PROJECT_SOURCE_DIR}/libs/dbus)
SET(CONFIG_FOLDER ${PROJECT_SOURCE_DIR}/libs/config)
SET(IPC_FOLDER ${PROJECT_SOURCE_DIR}/libs/ipc)
+SET(LXCPP_FOLDER ${PROJECT_SOURCE_DIR}/libs/lxcpp)
SET(CLIENT_FOLDER ${PROJECT_SOURCE_DIR}/client)
SET(SERVER_FOLDER ${PROJECT_SOURCE_DIR}/server)
SET(ZONE_SUPPORT_FOLDER ${PROJECT_SOURCE_DIR}/zone-support)
@@ -180,6 +180,10 @@ IF(NOT DEFINED DATA_DIR)
SET(DATA_DIR "${CMAKE_INSTALL_PREFIX}/share")
ENDIF(NOT DEFINED DATA_DIR)
+IF(NOT DEFINED LIBEXEC_DIR)
+ SET(LIBEXEC_DIR "${CMAKE_INSTALL_PREFIX}/libexec")
+ENDIF(NOT DEFINED LIBEXEC_DIR)
+
IF(NOT DEFINED RUN_DIR)
SET(RUN_DIR "/var/run")
ENDIF(NOT DEFINED RUN_DIR)
@@ -190,12 +194,12 @@ SET(VSM_UNIT_TESTS_IPC_SOCKET_PATH ${RUN_DIR}/vasum-ipc-unit-tests.socket)
ADD_SUBDIRECTORY(${COMMON_FOLDER})
ADD_SUBDIRECTORY(${LOGGER_FOLDER})
-ADD_SUBDIRECTORY(${LXCPP_FOLDER})
IF(NOT WITHOUT_DBUS)
ADD_SUBDIRECTORY(${DBUS_FOLDER})
ENDIF(NOT WITHOUT_DBUS)
ADD_SUBDIRECTORY(${CONFIG_FOLDER})
ADD_SUBDIRECTORY(${IPC_FOLDER})
+ADD_SUBDIRECTORY(${LXCPP_FOLDER})
ADD_SUBDIRECTORY(${CLIENT_FOLDER})
ADD_SUBDIRECTORY(${SERVER_FOLDER})
IF(NOT WITHOUT_DBUS)
diff --git a/common/utils/channel.cpp b/common/utils/channel.cpp
index fbb110d..3a0dd31 100644
--- a/common/utils/channel.cpp
+++ b/common/utils/channel.cpp
@@ -27,6 +27,8 @@
#include "logger/logger.hpp"
+#include
+#include
#include
namespace {
@@ -36,10 +38,15 @@ const int RIGHT = 1;
namespace utils {
-Channel::Channel()
+Channel::Channel(const bool closeOnExec)
: mSocketIndex(-1)
{
- if (::socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, mSockets) < 0) {
+ int flags = SOCK_STREAM;
+ if (closeOnExec) {
+ flags |= SOCK_CLOEXEC;
+ };
+
+ if (::socketpair(AF_LOCAL, flags, 0, mSockets.data()) < 0) {
const std::string msg = "socketpair() failed: " +
utils::getSystemErrorMessage();
LOGE(msg);
@@ -47,23 +54,36 @@ Channel::Channel()
}
}
+Channel::Channel(const int fd)
+ : mSocketIndex(LEFT),
+ mSockets{{fd, -1}}
+{
+ assert(fd >= 0);
+}
+
Channel::~Channel()
{
closeSocket(LEFT);
closeSocket(RIGHT);
}
+/*
+ * This function has to be safe in regard to signal(7)
+ */
void Channel::setLeft()
{
mSocketIndex = LEFT;
- utils::close(mSockets[RIGHT]);
+ ::close(mSockets[RIGHT]);
mSockets[RIGHT] = -1;
}
+/*
+ * This function has to be safe in regard to signal(7)
+ */
void Channel::setRight()
{
mSocketIndex = RIGHT;
- utils::close(mSockets[LEFT]);
+ ::close(mSockets[LEFT]);
mSockets[LEFT] = -1;
}
@@ -73,6 +93,33 @@ void Channel::shutdown()
closeSocket(mSocketIndex);
}
+int Channel::getFD()
+{
+ assert(mSocketIndex != -1 && "Channel's end isn't set");
+ return mSockets[mSocketIndex];
+}
+
+int Channel::getLeftFD()
+{
+ return mSockets[LEFT];
+}
+
+int Channel::getRightFD()
+{
+ return mSockets[RIGHT];
+}
+
+void Channel::setCloseOnExec(const bool closeOnExec)
+{
+ const int fd = getFD();
+
+ if (closeOnExec) {
+ ::fcntl(fd, F_SETFD, ::fcntl(fd, F_GETFD) | FD_CLOEXEC);
+ } else {
+ ::fcntl(fd, F_SETFD, ::fcntl(fd, F_GETFD) & ~FD_CLOEXEC);
+ }
+}
+
void Channel::closeSocket(int socketIndex)
{
utils::shutdown(mSockets[socketIndex]);
diff --git a/common/utils/channel.hpp b/common/utils/channel.hpp
index f537121..3b60daa 100644
--- a/common/utils/channel.hpp
+++ b/common/utils/channel.hpp
@@ -26,6 +26,8 @@
#define COMMON_UTILS_CHANNEL_HPP
#include "utils/fd-utils.hpp"
+
+#include
#include
namespace utils {
@@ -35,7 +37,8 @@ namespace utils {
*/
class Channel {
public:
- Channel();
+ explicit Channel(const bool closeOnExec = true);
+ explicit Channel(const int fd);
~Channel();
Channel(const Channel&) = delete;
@@ -72,12 +75,32 @@ public:
template
Data read();
+ /**
+ * Get an active file descriptor
+ */
+ int getFD();
+
+ /**
+ * Gen the left file descriptor
+ */
+ int getLeftFD();
+
+ /**
+ * Gen the right file descriptor
+ */
+ int getRightFD();
+
+ /**
+ * Sets close on exec on an active fd to either true or false
+ */
+ void setCloseOnExec(const bool closeOnExec);
+
private:
void closeSocket(int socketIndex);
int mSocketIndex;
- int mSockets[2];
+ std::array mSockets;
};
template
diff --git a/libs/logger/backend-persistent-file.hpp b/libs/logger/backend-persistent-file.hpp
index 74d2def..5cbd714 100644
--- a/libs/logger/backend-persistent-file.hpp
+++ b/libs/logger/backend-persistent-file.hpp
@@ -27,7 +27,9 @@
#include "logger/backend.hpp"
+#include
#include
+#include
namespace logger {
@@ -35,7 +37,12 @@ class PersistentFileBackend : public LogBackend {
public:
PersistentFileBackend(const std::string& filePath) :
mfilePath(filePath),
- mOut(mfilePath, std::ios::app) {}
+ mOut(mfilePath, std::ios::app)
+ {
+ using filebufType = __gnu_cxx::stdio_filebuf;
+ const int fd = static_cast(mOut.rdbuf())->fd();
+ ::fcntl(fd, F_SETFD, ::fcntl(fd, F_GETFD) | FD_CLOEXEC);
+ }
void log(LogLevel logLevel,
const std::string& file,
diff --git a/libs/logger/formatter.cpp b/libs/logger/formatter.cpp
index 17bed53..06404f2 100644
--- a/libs/logger/formatter.cpp
+++ b/libs/logger/formatter.cpp
@@ -26,6 +26,7 @@
#include "logger/formatter.hpp"
#include "utils/ccolor.hpp"
+#include
#include
#include
#include
@@ -39,7 +40,7 @@ namespace {
const int TIME_COLUMN_LENGTH = 12;
const int SEVERITY_COLUMN_LENGTH = 8;
-const int THREAD_COLUMN_LENGTH = 3;
+const int PROCESS_COLUMN_LENGTH = 8;
const int FILE_COLUMN_LENGTH = 60;
std::atomic gNextThreadId(1);
@@ -122,7 +123,7 @@ std::string LogFormatter::getHeader(LogLevel logLevel,
std::ostringstream logLine;
logLine << getCurrentTime() << ' '
<< std::left << std::setw(SEVERITY_COLUMN_LENGTH) << '[' + toString(logLevel) + ']'
- << std::right << std::setw(THREAD_COLUMN_LENGTH) << getCurrentThread() << ": "
+ << std::right << std::setw(PROCESS_COLUMN_LENGTH) << ::getpid() << "/" << getCurrentThread() << ": "
<< std::left << std::setw(FILE_COLUMN_LENGTH)
<< file + ':' + std::to_string(line) + ' ' + func + ':';
return logLine.str();
diff --git a/libs/logger/level.hpp b/libs/logger/level.hpp
index fd33343..99dc235 100644
--- a/libs/logger/level.hpp
+++ b/libs/logger/level.hpp
@@ -33,7 +33,7 @@ namespace logger {
* @brief Available log levels
* @ingroup libLogger
*/
-enum class LogLevel {
+enum class LogLevel : int {
TRACE, ///< Most detailed log level
DEBUG, ///< Debug logs
INFO, ///< Information
diff --git a/libs/logger/logger.cpp b/libs/logger/logger.cpp
index ec0855b..fbb85d6 100644
--- a/libs/logger/logger.cpp
+++ b/libs/logger/logger.cpp
@@ -40,6 +40,44 @@ std::mutex gLogMutex;
} // namespace
+void setupLogger(const LogType type,
+ const LogLevel level,
+ const std::string &arg)
+{
+ if (type == LogType::LOG_FILE || type == LogType::LOG_PERSISTENT_FILE) {
+ if (arg.empty()) {
+ throw std::runtime_error("Path needs to be specified in the agument");
+ }
+ }
+
+ switch(type) {
+ case LogType::LOG_NULL:
+ Logger::setLogBackend(new NullLogger());
+ break;
+#ifdef HAVE_SYSTEMD
+ case LogType::LOG_JOURNALD:
+ Logger::setLogBackend(new SystemdJournalBackend());
+ break;
+#endif
+ case LogType::LOG_FILE:
+ Logger::setLogBackend(new FileBackend(arg));
+ break;
+ case LogType::LOG_PERSISTENT_FILE:
+ Logger::setLogBackend(new PersistentFileBackend(arg));
+ break;
+ case LogType::LOG_SYSLOG:
+ Logger::setLogBackend(new SyslogBackend());
+ break;
+ case LogType::LOG_STDERR:
+ Logger::setLogBackend(new StderrBackend());
+ break;
+ default:
+ throw std::runtime_error("Bad logger type passed");
+ }
+
+ Logger::setLogLevel(level);
+}
+
void Logger::logMessage(LogLevel logLevel,
const std::string& message,
const std::string& file,
diff --git a/libs/logger/logger.hpp b/libs/logger/logger.hpp
index 0a1ebe6..92baee1 100644
--- a/libs/logger/logger.hpp
+++ b/libs/logger/logger.hpp
@@ -61,9 +61,14 @@
#define COMMON_LOGGER_LOGGER_HPP
#include "logger/level.hpp"
+#include "logger/backend-null.hpp"
+#ifdef HAVE_SYSTEMD
+#include "logger/backend-journal.hpp"
+#endif
#include "logger/backend-file.hpp"
-#include "logger/backend-stderr.hpp"
#include "logger/backend-persistent-file.hpp"
+#include "logger/backend-syslog.hpp"
+#include "logger/backend-stderr.hpp"
#include
#include
@@ -74,6 +79,27 @@
namespace logger {
+enum class LogType : int {
+ LOG_NULL,
+ LOG_JOURNALD,
+ LOG_FILE,
+ LOG_PERSISTENT_FILE,
+ LOG_SYSLOG,
+ LOG_STDERR
+};
+
+/**
+ * A helper function to easily and completely setup a new logger
+ *
+ * @param type logger type to be set up
+ * @param level maximum log level that will be logged
+ * @param arg an argument used by some loggers, specific to them
+ * (e.g. file name for file loggers)
+ */
+void setupLogger(const LogType type,
+ const LogLevel level,
+ const std::string &arg = "");
+
class LogBackend;
class Logger {
diff --git a/libs/lxcpp/CMakeLists.txt b/libs/lxcpp/CMakeLists.txt
index 203ddd3..8f391e8 100644
--- a/libs/lxcpp/CMakeLists.txt
+++ b/libs/lxcpp/CMakeLists.txt
@@ -19,6 +19,9 @@
PROJECT(lxcpp)
+SET(GUARD_CODENAME "${PROJECT_NAME}-guard")
+ADD_SUBDIRECTORY(guard)
+
MESSAGE(STATUS "")
MESSAGE(STATUS "Generating makefile for the liblxcpp...")
FILE(GLOB HEADERS *.hpp)
@@ -37,15 +40,18 @@ ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_COMMANDS})
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
SOVERSION ${_LIB_SOVERSION_}
VERSION ${_LIB_VERSION_}
+ COMPILE_DEFINITIONS GUARD_PATH="${LIBEXEC_DIR}/${GUARD_CODENAME}"
)
ADD_DEPENDENCIES(${PROJECT_NAME} Common Logger)
## Link libraries ##############################################################
FIND_PACKAGE(Boost COMPONENTS system filesystem)
+PKG_CHECK_MODULES(LXCPP_DEPS REQUIRED glib-2.0)
+
INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER})
-INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS})
-TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${Boost_LIBRARIES} Logger)
+INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS} ${LXCPP_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${Boost_LIBRARIES} Logger Config)
## Generate the pc file ########################################################
CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY)
diff --git a/libs/lxcpp/commands/attach.cpp b/libs/lxcpp/commands/attach.cpp
index 01a811b..419f651 100644
--- a/libs/lxcpp/commands/attach.cpp
+++ b/libs/lxcpp/commands/attach.cpp
@@ -167,6 +167,8 @@ void Attach::execute()
parent(intermChannel, interPid);
intermChannel.shutdown();
} else {
+ // TODO: only safe functions mentioned in signal(7) should be used below.
+ // This is not the case now, needs fixing.
intermChannel.setRight();
interm(intermChannel, call);
intermChannel.shutdown();
diff --git a/libs/lxcpp/commands/start.cpp b/libs/lxcpp/commands/start.cpp
new file mode 100644
index 0000000..f68654a
--- /dev/null
+++ b/libs/lxcpp/commands/start.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Implementation of starting a container
+ */
+
+#include "lxcpp/commands/start.hpp"
+#include "lxcpp/exception.hpp"
+#include "lxcpp/process.hpp"
+#include "lxcpp/utils.hpp"
+
+#include "logger/logger.hpp"
+#include "config/manager.hpp"
+
+#include
+
+
+namespace lxcpp {
+
+
+Start::Start(ContainerConfig &config)
+ : mConfig(config),
+ mChannel(false),
+ mGuardPath(GUARD_PATH),
+ mChannelFD(std::to_string(mChannel.getRightFD()))
+{
+}
+
+Start::~Start()
+{
+}
+
+void Start::execute()
+{
+ LOGD("Forking daemonize and guard processes. Execing guard libexec binary.");
+ LOGD("Logging will cease now. It should be restored using some new facility in the guard process.");
+ const pid_t pid = lxcpp::fork();
+
+ if (pid > 0) {
+ mChannel.setLeft();
+ parent(pid);
+ } else {
+ // Below this point only safe functions mentioned in signal(7) are allowed.
+ mChannel.setRight();
+ daemonize();
+ ::_exit(EXIT_FAILURE);
+ }
+}
+
+void Start::parent(const pid_t pid)
+{
+ int status = lxcpp::waitpid(pid);
+ if (status != EXIT_SUCCESS) {
+ const std::string msg = "Problem with a daemonize process";
+ LOGE(msg);
+ throw ProcessSetupException(msg);
+ }
+
+ // Send the config to the guard process
+ config::saveToFD(mChannel.getFD(), mConfig);
+
+ // Read the pids from the guard process
+ mConfig.mGuardPid = mChannel.read();
+ mConfig.mInitPid = mChannel.read();
+
+ mChannel.shutdown();
+
+ if (mConfig.mGuardPid <= 0 || mConfig.mInitPid <= 0) {
+ const std::string msg = "Problem with receiving pids";
+ LOGE(msg);
+ throw ProcessSetupException(msg);
+ }
+
+ LOGD("Guard PID: " << mConfig.mGuardPid);
+ LOGD("Init PID: " << mConfig.mInitPid);
+}
+
+void Start::daemonize()
+{
+ // Double fork() with exit() to reattach the process under the host's init
+ pid_t pid = ::fork();
+ if (pid < 0) {
+ ::_exit(EXIT_FAILURE);
+ }
+
+ if (pid == 0) {
+ // Prepare a clean environment for a guard process:
+ // - chdir to / so it's independent on other directories
+ // - null std* fds so it's properly dettached from the terminal
+ // - set a new session so it cannot reacquire a terminal
+
+ if (::chdir("/") < 0) {
+ ::_exit(EXIT_FAILURE);
+ }
+ if (nullStdFDs() <0) {
+ ::_exit(EXIT_FAILURE);
+ }
+ if (::setsid() < 0) {
+ ::_exit(EXIT_FAILURE);
+ }
+
+ // Add name and path of the container to argv. They are not used, but will
+ // identify the container in the process list in case setProcTitle() fails
+ // and will guarantee we have enough argv memory to write the title we want.
+ const char *argv[] = {mGuardPath.c_str(),
+ mChannelFD.c_str(),
+ mConfig.mName.c_str(),
+ mConfig.mRootPath.c_str(),
+ NULL};
+ ::execve(argv[0], const_cast(argv), NULL);
+ ::_exit(EXIT_FAILURE);
+ }
+
+ ::_exit(EXIT_SUCCESS);
+}
+
+
+} // namespace lxcpp
diff --git a/libs/lxcpp/commands/start.hpp b/libs/lxcpp/commands/start.hpp
new file mode 100644
index 0000000..758b471
--- /dev/null
+++ b/libs/lxcpp/commands/start.hpp
@@ -0,0 +1,66 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Headers for starting a container
+ */
+
+#ifndef LXCPP_COMMANDS_START_HPP
+#define LXCPP_COMMANDS_START_HPP
+
+#include "lxcpp/commands/command.hpp"
+#include "lxcpp/container-config.hpp"
+#include "utils/channel.hpp"
+
+#include
+
+
+namespace lxcpp {
+
+
+class Start final: Command {
+public:
+ /**
+ * Starts the container
+ *
+ * In more details it prepares an environment for a guard process,
+ * starts it, and passes it the configuration through a file descriptor.
+ *
+ * @param config container's config
+ */
+ Start(ContainerConfig &config);
+ ~Start();
+
+ void execute();
+
+private:
+ ContainerConfig &mConfig;
+ utils::Channel mChannel;
+ std::string mGuardPath;
+ std::string mChannelFD;
+
+ void parent(const pid_t pid);
+ void daemonize();
+};
+
+
+} // namespace lxcpp
+
+
+#endif // LXCPP_COMMANDS_START_HPP
diff --git a/libs/lxcpp/container-config.hpp b/libs/lxcpp/container-config.hpp
new file mode 100644
index 0000000..9caad96
--- /dev/null
+++ b/libs/lxcpp/container-config.hpp
@@ -0,0 +1,111 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief A definition of a ContainerConfig struct
+ */
+
+#ifndef LXCPP_CONTAINER_CONFIG_HPP
+#define LXCPP_CONTAINER_CONFIG_HPP
+
+#include "lxcpp/logger-config.hpp"
+
+#include
+#include
+
+#include
+#include
+#include
+
+
+namespace lxcpp {
+
+
+struct ContainerConfig {
+ /**
+ * Name of the container.
+ *
+ * Set: by constructor, cannot be changed afterwards.
+ * Get: getName()
+ */
+ std::string mName;
+
+ /**
+ * Path of the root directory of the container.
+ *
+ * Set: by contstructor, cannot be changed afterwards.
+ * Get: getRootPath()
+ */
+ std::string mRootPath;
+
+ /**
+ * Pid of the guard process.
+ *
+ * Set: automatically by the guard process itself.
+ * Get: getGuardPid()
+ */
+ pid_t mGuardPid;
+
+ /**
+ * Pid of the container's init process.
+ *
+ * Set: automatically by the guard process.
+ * Get: getInitPid()
+ */
+ pid_t mInitPid;
+
+ /**
+ * Argv of the container's init process to be executed.
+ * The path has to be relative to the RootPath.
+ *
+ * Set: setInit()
+ * Get: getInit()
+ */
+ std::vector mInit;
+
+ /**
+ * Logger to be configured inside the guard process. This logger
+ * reconfiguration is due to the fact that guard looses standard file
+ * descriptors and might loose access to other files by mount namespace
+ * usage. Hence an option to set some other logger that will work
+ * regardless. E.g. PersistentFile.
+ *
+ * Set: setLogger()
+ * Get: none
+ */
+ LoggerConfig mLogger;
+
+ ContainerConfig() : mGuardPid(-1), mInitPid(-1) {}
+
+ CONFIG_REGISTER
+ (
+ mName,
+ mRootPath,
+ mGuardPid,
+ mInitPid,
+ mInit,
+ mLogger
+ )
+};
+
+
+}
+
+
+#endif // LXCPP_CONTAINER_CONFIG_HPP
diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp
index 8249009..cee6fa4 100644
--- a/libs/lxcpp/container-impl.cpp
+++ b/libs/lxcpp/container-impl.cpp
@@ -28,6 +28,7 @@
#include "lxcpp/namespace.hpp"
#include "lxcpp/capability.hpp"
#include "lxcpp/commands/attach.hpp"
+#include "lxcpp/commands/start.hpp"
#include "logger/logger.hpp"
#include "utils/exception.hpp"
@@ -120,9 +121,18 @@ pid_t ContainerImpl::getInitPid() const
return mConfig.mInitPid;
}
+void ContainerImpl::setLogger(const logger::LogType type,
+ const logger::LogLevel level,
+ const std::string &arg)
+{
+ mConfig.mLogger.set(type, level, arg);
+}
+
void ContainerImpl::start()
{
- throw NotImplementedException();
+ // TODO: check config consistency and completeness somehow
+ Start start(mConfig);
+ start.execute();
}
void ContainerImpl::stop()
diff --git a/libs/lxcpp/container-impl.hpp b/libs/lxcpp/container-impl.hpp
index 5435d49..1bf44b7 100644
--- a/libs/lxcpp/container-impl.hpp
+++ b/libs/lxcpp/container-impl.hpp
@@ -25,37 +25,15 @@
#define LXCPP_CONTAINER_IMPL_HPP
#include
-#include
-#include
#include
+#include "lxcpp/container-config.hpp"
#include "lxcpp/container.hpp"
#include "lxcpp/namespace.hpp"
#include "lxcpp/network.hpp"
-#include "utils/channel.hpp"
-
namespace lxcpp {
-struct ContainerConfig {
- std::string mName;
- std::string mRootPath;
- pid_t mGuardPid;
- pid_t mInitPid;
- std::vector mInit;
-
- ContainerConfig() : mGuardPid(-1), mInitPid(-1) {}
-
- CONFIG_REGISTER
- (
- mName,
- mRootPath,
- mGuardPid,
- mInitPid,
- mInit
- )
-};
-
class ContainerImpl : public virtual Container {
public:
@@ -73,6 +51,10 @@ public:
const std::vector& getInit();
void setInit(const std::vector &init);
+ void setLogger(const logger::LogType type,
+ const logger::LogLevel level,
+ const std::string &arg);
+
const std::vector& getNamespaces() const;
// Execution actions
diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp
index 192f2df..88c3ff8 100644
--- a/libs/lxcpp/container.hpp
+++ b/libs/lxcpp/container.hpp
@@ -25,6 +25,7 @@
#define LXCPP_CONTAINER_HPP
#include "lxcpp/network-config.hpp"
+#include "lxcpp/logger-config.hpp"
#include
#include
@@ -60,6 +61,10 @@ public:
virtual const std::vector& getInit() = 0;
virtual void setInit(const std::vector &init) = 0;
+ virtual void setLogger(const logger::LogType type,
+ const logger::LogLevel level,
+ const std::string &arg) = 0;
+
// Execution actions
virtual void start() = 0;
virtual void stop() = 0;
diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp
index 7764282..11a6a0e 100644
--- a/libs/lxcpp/exception.hpp
+++ b/libs/lxcpp/exception.hpp
@@ -66,6 +66,11 @@ struct CapabilitySetupException: public Exception {
: Exception(message) {}
};
+struct UtilityException: public Exception {
+ explicit UtilityException(const std::string& message = "Error during an utility operation")
+ : Exception(message) {}
+};
+
struct BadArgument: public Exception {
explicit BadArgument(const std::string& message = "Bad argument passed")
: Exception(message) {}
diff --git a/libs/lxcpp/guard/CMakeLists.txt b/libs/lxcpp/guard/CMakeLists.txt
new file mode 100644
index 0000000..6c69300
--- /dev/null
+++ b/libs/lxcpp/guard/CMakeLists.txt
@@ -0,0 +1,37 @@
+# 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 CMakeLists.txt
+# @author Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+#
+
+MESSAGE(STATUS "")
+MESSAGE(STATUS "Generating makefile for the Guard...")
+FILE(GLOB guard_SRCS *.cpp *.hpp)
+
+
+## Setup target ################################################################
+ADD_EXECUTABLE(${GUARD_CODENAME} ${guard_SRCS})
+
+
+## Link libraries ##############################################################
+PKG_CHECK_MODULES(GUARD_DEPS REQUIRED glib-2.0)
+INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER})
+INCLUDE_DIRECTORIES(SYSTEM ${GUARD_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS})
+TARGET_LINK_LIBRARIES(${GUARD_CODENAME} lxcpp)
+
+
+## Install #####################################################################
+INSTALL(TARGETS ${GUARD_CODENAME} DESTINATION ${LIBEXEC_DIR})
diff --git a/libs/lxcpp/guard/guard.cpp b/libs/lxcpp/guard/guard.cpp
new file mode 100644
index 0000000..63c7263
--- /dev/null
+++ b/libs/lxcpp/guard/guard.cpp
@@ -0,0 +1,100 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief LXCPP guard process implementation
+ */
+
+#include "lxcpp/utils.hpp"
+#include "lxcpp/guard/guard.hpp"
+#include "lxcpp/process.hpp"
+
+#include "config/manager.hpp"
+#include "logger/logger.hpp"
+
+#include
+#include
+
+
+namespace lxcpp {
+
+
+void startContainer(const ContainerConfig &cfg)
+{
+ std::vector argv;
+ argv.reserve(cfg.mInit.size() + 1);
+ for (auto const & it : cfg.mInit) {
+ argv.push_back(it.c_str());
+ }
+ argv.push_back(nullptr);
+
+ LOGD("Executing container's init: " << argv[0]);
+ ::execve(argv[0], const_cast(argv.data()), NULL);
+ ::_exit(EXIT_FAILURE);
+}
+
+int startGuard(int channelFD)
+{
+ ContainerConfig cfg;
+ utils::Channel channel(channelFD);
+ channel.setCloseOnExec(true);
+ config::loadFromFD(channel.getFD(), cfg);
+
+ logger::setupLogger(cfg.mLogger.getType(),
+ cfg.mLogger.getLevel(),
+ cfg.mLogger.getArg());
+
+ LOGD("Guard started, config & logging restored");
+
+ try {
+ LOGD("Setting the guard process title");
+ const std::string title = "[LXCPP] " + cfg.mName + " " + cfg.mRootPath;
+ setProcTitle(title);
+ } catch (std::exception &e) {
+ // Ignore, this is optional
+ LOGW("Failed to set the guard process title");
+ }
+
+ // TODO: container preparation part 1
+
+ // TODO: switch to clone
+ LOGD("Forking container's init process");
+ pid_t pid = lxcpp::fork();
+
+ if (pid == 0) {
+ // TODO: container preparation part 2
+
+ startContainer(cfg);
+ ::_exit(EXIT_FAILURE);
+ }
+
+ cfg.mGuardPid = ::getpid();
+ cfg.mInitPid = pid;
+
+ channel.write(cfg.mGuardPid);
+ channel.write(cfg.mInitPid);
+ channel.shutdown();
+
+ int status = lxcpp::waitpid(pid);
+ LOGD("Init exited with status: " << status);
+ return status;
+}
+
+
+} // namespace lxcpp
diff --git a/libs/lxcpp/guard/guard.hpp b/libs/lxcpp/guard/guard.hpp
new file mode 100644
index 0000000..78457ae
--- /dev/null
+++ b/libs/lxcpp/guard/guard.hpp
@@ -0,0 +1,39 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief LXCPP guard process header
+ */
+
+#ifndef LXCPP_GUARD_GUARD_HPP
+#define LXCPP_GUARD_GUARD_HPP
+
+
+#include "lxcpp/container-config.hpp"
+#include "utils/channel.hpp"
+
+namespace lxcpp {
+
+
+int startGuard(int channelFD);
+
+
+} // namespace lxcpp
+
+#endif // LXCPP_GUARD_HPP
diff --git a/libs/lxcpp/guard/main.cpp b/libs/lxcpp/guard/main.cpp
new file mode 100644
index 0000000..c8db30b
--- /dev/null
+++ b/libs/lxcpp/guard/main.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Main file for the Guard process (libexec)
+ */
+
+#include "lxcpp/guard/guard.hpp"
+
+#include "utils/fd-utils.hpp"
+
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ if (argc == 1) {
+ std::cout << "This file should not be executed by hand" << std::endl;
+ ::_exit(EXIT_FAILURE);
+ }
+
+ // NOTE: this might not be required now, but I leave it here not to forget.
+ // We need to investigate this with vasum and think about possibility of
+ // poorly written software that leaks file descriptors and might use LXCPP.
+#if 0
+ for(int fd = 3; fd < ::sysconf(_SC_OPEN_MAX); ++fd) {
+ utils::close(fd);
+ }
+#endif
+
+ int fd = std::stoi(argv[1]);
+ return lxcpp::startGuard(fd);
+}
diff --git a/libs/lxcpp/logger-config.cpp b/libs/lxcpp/logger-config.cpp
new file mode 100644
index 0000000..3aed302
--- /dev/null
+++ b/libs/lxcpp/logger-config.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsumg.com)
+ * @brief Logger configuration
+ */
+
+#include "lxcpp/logger-config.hpp"
+#include "lxcpp/exception.hpp"
+
+namespace lxcpp {
+
+
+void LoggerConfig::set(const logger::LogType type,
+ const logger::LogLevel level,
+ const std::string &arg)
+{
+ if (type == logger::LogType::LOG_FILE || type == logger::LogType::LOG_PERSISTENT_FILE) {
+ if (arg.empty()) {
+ const std::string msg = "Path needs to be specified in the agument";
+ LOGE(msg);
+ throw BadArgument(msg);
+ }
+ }
+
+ mType = static_cast(type);
+ mLevel = static_cast(level);
+ mArg = arg;
+}
+
+
+} //namespace lxcpp
diff --git a/libs/lxcpp/logger-config.hpp b/libs/lxcpp/logger-config.hpp
new file mode 100644
index 0000000..8312623
--- /dev/null
+++ b/libs/lxcpp/logger-config.hpp
@@ -0,0 +1,65 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsumg.com)
+ * @brief Logger configuration
+ */
+
+#ifndef LXCPP_LOGGER_CONFIG_HPP
+#define LXCPP_LOGGER_CONFIG_HPP
+
+#include "config/config.hpp"
+#include "config/fields.hpp"
+#include "logger/logger.hpp"
+
+
+namespace lxcpp {
+
+
+/**
+ * Logger configuration
+ */
+struct LoggerConfig {
+private:
+ int mType;
+ int mLevel;
+ std::string mArg;
+
+public:
+ void set(const logger::LogType type,
+ const logger::LogLevel level,
+ const std::string &arg = "");
+
+ logger::LogType getType() const {return static_cast(mType);}
+ logger::LogLevel getLevel() const {return static_cast(mLevel);}
+ std::string getArg() const {return mArg;}
+
+ CONFIG_REGISTER
+ (
+ mType,
+ mLevel,
+ mArg
+ )
+};
+
+
+} //namespace lxcpp
+
+
+#endif // LXCPP_LOGGER_CONFIG_HPP
diff --git a/libs/lxcpp/utils.cpp b/libs/lxcpp/utils.cpp
new file mode 100644
index 0000000..41e76b5
--- /dev/null
+++ b/libs/lxcpp/utils.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief LXCPP utils implementation
+ */
+
+#include "lxcpp/exception.hpp"
+
+#include "logger/logger.hpp"
+#include "utils/fd-utils.hpp"
+#include "utils/exception.hpp"
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+
+namespace lxcpp {
+
+
+/*
+ * This function has to be safe in regard to signal(7)
+ */
+int nullStdFDs()
+{
+ int ret = -1;
+
+ int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR | O_CLOEXEC));
+ if (fd == -1) {
+ goto err;
+ }
+
+ if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDIN_FILENO))) {
+ goto err_close;
+ }
+
+ if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDOUT_FILENO))) {
+ goto err_close;
+ }
+
+ if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDERR_FILENO))) {
+ goto err_close;
+ }
+
+ if (-1 == TEMP_FAILURE_RETRY(::close(fd))) {
+ goto err_close;
+ }
+
+ return 0;
+
+err_close:
+ TEMP_FAILURE_RETRY(::close(fd));
+err:
+ return ret;
+}
+
+void setProcTitle(const std::string &title)
+{
+ std::ifstream f("/proc/self/stat");
+ auto it = std::istream_iterator(f);
+
+ // Skip the first 47 fields, entries 48-49 are ARG_START and ARG_END.
+ std::advance(it, 47);
+ unsigned long argStart = std::stol(*it++);
+ unsigned long argEnd = std::stol(*it++);
+
+ f.close();
+
+ char *mem = reinterpret_cast(argStart);
+ ptrdiff_t oldLen = argEnd - argStart;
+
+ // Include the null byte here, because in the calculations below we want to have room for it.
+ size_t newLen = title.length() + 1;
+
+ // We shouldn't use more then we have available. Hopefully that should be enough.
+ if ((long)newLen > oldLen) {
+ newLen = oldLen;
+ } else {
+ argEnd = argStart + newLen;
+ }
+
+ // Sanity check
+ if (argEnd < newLen || argEnd < argStart) {
+ std::string msg = "setProcTitle() failed: " + utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw UtilityException(msg);
+ }
+
+ // Let's try to set the memory range properly (this requires capabilities)
+ if (::prctl(PR_SET_MM, PR_SET_MM_ARG_END, argEnd, 0, 0) < 0) {
+ // If that failed let's fall back to the poor man's version, just zero the memory we already have.
+ ::bzero(mem, oldLen);
+ }
+
+ ::strcpy(mem, title.c_str());
+}
+
+
+} // namespace lxcpp
diff --git a/libs/lxcpp/utils.hpp b/libs/lxcpp/utils.hpp
new file mode 100644
index 0000000..2a59303
--- /dev/null
+++ b/libs/lxcpp/utils.hpp
@@ -0,0 +1,54 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief LXCPP utils headers
+ */
+
+#ifndef LXCPP_UTILS_HPP
+#define LXCPP_UTILS_HPP
+
+#include
+
+
+namespace lxcpp {
+
+/**
+ * Nullifies all standard file descriptors (stdin, stdout, stderr)
+ * replacing them with file descriptor to /dev/null. Used to
+ * as a part of a process to detach a process from a control terminal.
+ *
+ * This function has to be safe in regard to signal(7)
+ *
+ * @returns an error code in case of failure.
+ */
+int nullStdFDs();
+
+/**
+ * Changes the tittle of a current process title (e.g. visible in ps tool).
+ *
+ * @param title A new tittle to be set
+ */
+void setProcTitle(const std::string &title);
+
+
+} // namespace lxcpp
+
+
+#endif // LXCPP_START_HPP
diff --git a/packaging/vasum.spec b/packaging/vasum.spec
index 2cd5dd8..7709ab4 100644
--- a/packaging/vasum.spec
+++ b/packaging/vasum.spec
@@ -487,6 +487,7 @@ The package provides liblxcpp library.
%files -n liblxcpp
%defattr(644,root,root,755)
%{_libdir}/liblxcpp.so.0
+%attr(755,root,root) %{_libexecdir}/lxcpp-guard
%attr(755,root,root) %{_libdir}/liblxcpp.so.%{version}
%package -n liblxcpp-devel
--
2.7.4
From a3495900d30400f536a89118984fca13df3187e1 Mon Sep 17 00:00:00 2001
From: Pawel Kubik
Date: Tue, 15 Sep 2015 15:40:41 +0200
Subject: [PATCH 04/16] Instructions for generating code coverage report
[Feature] Instructions in markdown
[Cause] Need for local coverage reports
[Solution] N/A
[Verification] Follow instructions in the file and check report
Change-Id: I69df0752268585c622b5006107ab91a59b840ea7
---
doc/coverage_report.md | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 doc/coverage_report.md
diff --git a/doc/coverage_report.md b/doc/coverage_report.md
new file mode 100644
index 0000000..cb9ef8e
--- /dev/null
+++ b/doc/coverage_report.md
@@ -0,0 +1,40 @@
+Generating Code Coverage Report
+===============================
+
+Requirements
+------------
+ - [**gcc**](gcc.gnu.org) - provides `gcov` which generates coverage summary
+ - [**gcovr**](gcovr.com) - recursively runs `gcov` and generates HTML report.
+ [*PyPI*](pypi.python.org/pypi/gcovr) should provide the newest version.
+ You can use `pip` command (available in most repositories):
+ ```bash
+ sudo pip install gcovr
+ ```
+
+Instructions
+------------
+
+All command should be run from within your build directory. **repodir** is a
+path to your repository root.
+
+1. Generate your build using CCOV profile
+```bash
+cmake -DCMAKE_BUILD_TYPE=CCOV repodir
+```
+
+2. Compile, install and run tests in order to generate coverage files (.gcda extension)
+```bash
+make
+sudo make install
+sudo vsm_all_tests.py
+```
+ **Make sure that no other Vasum binaries are being used after installation
+ except from those used by tests!**
+
+3. Generate HTML report
+```bash
+gcovr -e tests -s -v -r repodir --html -o coverage.html
+```
+
+4. Coverage report consists of single page **coverage.html**. Find it in your
+ build directory and open in a web browser.
--
2.7.4
From c6006f81f49ddd8c3fc1cf59f3b54ea522f12fcc Mon Sep 17 00:00:00 2001
From: Krzysztof Dynowski
Date: Thu, 27 Aug 2015 15:25:58 +0200
Subject: [PATCH 05/16] lxcpp: network implementation (part 1)
[Feature] Network implementation for lxcpp (list, details)
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I2f43a2bb6d042b5aad9abf87951965e585fb4eb6
---
common/netlink/netlink-message.cpp | 22 +-
common/netlink/netlink-message.hpp | 8 +-
common/netlink/netlink.cpp | 2 +-
common/utils/text.cpp | 43 ++++
common/utils/text.hpp | 54 +++++
libs/lxcpp/commands/netcreate.cpp | 45 ++++
libs/lxcpp/commands/netcreate.hpp | 57 +++++
libs/lxcpp/container-config.hpp | 9 +
libs/lxcpp/container-impl.cpp | 40 +++-
libs/lxcpp/container-impl.hpp | 18 +-
libs/lxcpp/container.hpp | 20 +-
libs/lxcpp/network-config.cpp | 66 +++++-
libs/lxcpp/network-config.hpp | 55 ++++-
libs/lxcpp/network.cpp | 398 +++++++++++++++++++++++++++++++++-
libs/lxcpp/network.hpp | 78 ++++++-
server/netdev.cpp | 4 +-
tests/unit_tests/lxcpp/ut-network.cpp | 83 +++++++
17 files changed, 938 insertions(+), 64 deletions(-)
create mode 100644 common/utils/text.cpp
create mode 100644 common/utils/text.hpp
create mode 100644 libs/lxcpp/commands/netcreate.cpp
create mode 100644 libs/lxcpp/commands/netcreate.hpp
create mode 100644 tests/unit_tests/lxcpp/ut-network.cpp
diff --git a/common/netlink/netlink-message.cpp b/common/netlink/netlink-message.cpp
index cef7828..5bdda7b 100644
--- a/common/netlink/netlink-message.cpp
+++ b/common/netlink/netlink-message.cpp
@@ -191,7 +191,7 @@ void NetlinkResponse::skipAttribute()
NetlinkResponse& NetlinkResponse::openNested(int ifla)
{
const rtattr *rta = asAttr(get(RTA_LENGTH(0)));
- if (rta->rta_type == ifla) {
+ if (rta->rta_type != ifla) {
const std::string msg = "Wrong attribute type, expected: " + std::to_string(ifla) + ", got: " + std::to_string(rta->rta_type);
LOGE(msg);
throw VasumException(msg);
@@ -217,9 +217,13 @@ NetlinkResponse& NetlinkResponse::closeNested()
return *this;
}
-NetlinkResponse& NetlinkResponse::fetch(int ifla, std::string& value, int maxSize)
+NetlinkResponse& NetlinkResponse::fetch(int ifla, std::string& value, unsigned len)
{
- value = std::string(get(ifla, maxSize));
+ const rtattr *rta = asAttr(get(RTA_LENGTH(0)));
+ if (len > RTA_PAYLOAD(rta)) {
+ len = RTA_PAYLOAD(rta);
+ }
+ value = std::string(get(ifla, -1), len);
skipAttribute();
return *this;
}
@@ -228,12 +232,15 @@ const char* NetlinkResponse::get(int ifla, int len) const
{
const rtattr *rta = asAttr(get(RTA_LENGTH(len < 0 ? 0 : len)));
if (rta->rta_type != ifla) {
- const std::string msg = "Wrong attribute type, expected: " + std::to_string(ifla) + ", got: " + std::to_string(rta->rta_type);
+ const std::string msg = "Wrong attribute type, expected: " + std::to_string(ifla) +
+ ", got: " + std::to_string(rta->rta_type);
LOGE(msg);
throw VasumException(msg);
}
if (len >= 0 && rta->rta_len != RTA_LENGTH(len)) {
- const std::string msg = "Wrong attribute length, expected: " + std::to_string(rta->rta_len) + ", got: " + std::to_string(len);
+ const std::string msg = "Wrong attribute " + std::to_string(ifla) +
+ " length, expected: " + std::to_string(rta->rta_len) +
+ ", got: " + std::to_string(RTA_LENGTH(len));
LOGE(msg);
throw VasumException(msg);
}
@@ -270,6 +277,11 @@ int NetlinkResponse::getAttributeType() const
return asAttr(get(RTA_LENGTH(0)))->rta_type;
}
+int NetlinkResponse::getAttributeLength() const
+{
+ return RTA_PAYLOAD(asAttr(get(RTA_LENGTH(0))));
+}
+
NetlinkResponse& NetlinkResponse::seek(int len)
{
if (size() < mPosition + len) {
diff --git a/common/netlink/netlink-message.hpp b/common/netlink/netlink-message.hpp
index 3379009..73e6a4c 100644
--- a/common/netlink/netlink-message.hpp
+++ b/common/netlink/netlink-message.hpp
@@ -25,6 +25,7 @@
#ifndef COMMON_NETLINK_NETLINK_MESSAGE_HPP
#define COMMON_NETLINK_NETLINK_MESSAGE_HPP
+#include
#include
#include
#include
@@ -150,7 +151,7 @@ public:
/**
* Fetch attribute
*/
- NetlinkResponse& fetch(int ifla, std::string& value, int maxSize = -1);
+ NetlinkResponse& fetch(int ifla, std::string& value, unsigned maxLen = std::numeric_limits::max());
template
NetlinkResponse& fetch(int ifla, T& value);
///@}
@@ -161,6 +162,11 @@ public:
int getAttributeType() const;
/**
+ * Get attributie length
+ **/
+ int getAttributeLength() const;
+
+ /**
* Fetch data of type T
*/
template
diff --git a/common/netlink/netlink.cpp b/common/netlink/netlink.cpp
index 3408293..45d0697 100644
--- a/common/netlink/netlink.cpp
+++ b/common/netlink/netlink.cpp
@@ -100,7 +100,7 @@ void Netlink::open(int netNsPid)
auto fdFactory = []{ return socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); };
assert(mFd == -1);
- if (netNsPid == 0 || netNsPid == getpid()) {
+ if (netNsPid == 0 || netNsPid == 1 || netNsPid == ::getpid()) {
mFd = fdFactory();
if (mFd == -1) {
LOGE("Can't open socket: " << getSystemErrorMessage());
diff --git a/common/utils/text.cpp b/common/utils/text.cpp
new file mode 100644
index 0000000..5bdf335
--- /dev/null
+++ b/common/utils/text.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief Text related utility
+ */
+
+#include "utils/text.hpp"
+
+namespace utils {
+namespace {
+const char hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+}
+
+std::string toHexString(const void *data, unsigned len)
+{
+ const unsigned char *d = static_cast(data);
+ std::string s(len * 2, ' ');
+ for (unsigned i = 0; i < len; ++i) {
+ s[2 * i] = hexmap[(d[i] >> 4) & 0x0F];
+ s[2 * i + 1] = hexmap[d[i] & 0x0F];
+ }
+ return s;
+}
+
+} // namespace utils
diff --git a/common/utils/text.hpp b/common/utils/text.hpp
new file mode 100644
index 0000000..435f421
--- /dev/null
+++ b/common/utils/text.hpp
@@ -0,0 +1,54 @@
+/*
+ * 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 Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief Text related utils
+ */
+
+#ifndef COMMON_UTILS_TEXT_HPP
+#define COMMON_UTILS_TEXT_HPP
+
+#include
+
+namespace utils {
+
+/**
+ * Convert binary bytes array to hex string representation
+ */
+std::string toHexString(const void *data, unsigned len);
+
+inline bool beginsWith(std::string const &value, std::string const &part)
+{
+ if (part.size() > value.size()) {
+ return false;
+ }
+ return std::equal(part.begin(), part.end(), value.begin());
+}
+
+inline bool endsWith(std::string const &value, std::string const &part)
+{
+ if (part.size() > value.size()) {
+ return false;
+ }
+ return std::equal(part.rbegin(), part.rend(), value.rbegin());
+}
+
+} // namespace utils
+
+#endif // COMMON_UTILS_TEXT_HPP
diff --git a/libs/lxcpp/commands/netcreate.cpp b/libs/lxcpp/commands/netcreate.cpp
new file mode 100644
index 0000000..3c88d8e
--- /dev/null
+++ b/libs/lxcpp/commands/netcreate.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief Network configuration command
+ */
+
+#include "lxcpp/commands/netcreate.hpp"
+#include "lxcpp/network.hpp"
+
+namespace lxcpp {
+
+void NetCreateAll::execute()
+{
+ for (const auto& i : mInterfaceConfigs) {
+ NetworkInterface networkInerface(mContainerPid, i.getZoneIf());
+ networkInerface.create(i.getHostIf(), i.getType(), i.getMode());
+
+ Attrs attrs;
+ for (const auto& a : i.getAddrList()) {
+ Attr attr;
+ NetworkInterface::convertInetAddr2Attr(a, attr);
+ attrs.push_back(attr);
+ }
+ networkInerface.setAttrs(attrs);
+ }
+}
+
+} // namespace lxcpp
diff --git a/libs/lxcpp/commands/netcreate.hpp b/libs/lxcpp/commands/netcreate.hpp
new file mode 100644
index 0000000..5d6e512
--- /dev/null
+++ b/libs/lxcpp/commands/netcreate.hpp
@@ -0,0 +1,57 @@
+/*
+ * 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 Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief Network configuration command
+ */
+
+#ifndef LXCPP_COMMAND_NETCREATE_HPP
+#define LXCPP_COMMAND_NETCREATE_HPP
+
+#include "lxcpp/commands/command.hpp"
+#include "lxcpp/network-config.hpp"
+
+#include
+
+namespace lxcpp {
+
+class NetCreateAll final: Command {
+public:
+ /**
+ * Runs call in the container's context
+ *
+ * Creates and configures network interfaces in the container
+ *
+ */
+ NetCreateAll(pid_t containerPid, const std::vector& iflist) :
+ mContainerPid(containerPid),
+ mInterfaceConfigs(iflist)
+ {
+ }
+
+ void execute();
+
+private:
+ const pid_t mContainerPid;
+ const std::vector& mInterfaceConfigs;
+};
+
+} // namespace lxcpp
+
+#endif // LXCPP_COMMAND_NETCREATE_HPP
diff --git a/libs/lxcpp/container-config.hpp b/libs/lxcpp/container-config.hpp
index 9caad96..54422bf 100644
--- a/libs/lxcpp/container-config.hpp
+++ b/libs/lxcpp/container-config.hpp
@@ -25,6 +25,7 @@
#define LXCPP_CONTAINER_CONFIG_HPP
#include "lxcpp/logger-config.hpp"
+#include "lxcpp/network-config.hpp"
#include
#include
@@ -71,6 +72,14 @@ struct ContainerConfig {
pid_t mInitPid;
/**
+ * Container network configration
+ *
+ * Set: by container network config methods
+ * Get: none
+ */
+ NetworkConfig mNetwork;
+
+ /**
* Argv of the container's init process to be executed.
* The path has to be relative to the RootPath.
*
diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp
index cee6fa4..a524231 100644
--- a/libs/lxcpp/container-impl.cpp
+++ b/libs/lxcpp/container-impl.cpp
@@ -182,22 +182,48 @@ void ContainerImpl::addInterfaceConfig(const std::string& hostif,
InterfaceType type,
MacVLanMode mode)
{
- mInterfaceConfig.push_back(NetworkInterfaceConfig(hostif,zoneif,type,mode));
+ mConfig.mNetwork.addInterfaceConfig(hostif, zoneif, type, mode);
}
-void ContainerImpl::addAddrConfig(const std::string& /*ifname*/, const InetAddr& /*addr*/)
+void ContainerImpl::addInetConfig(const std::string& ifname, const InetAddr& addr)
{
- throw NotImplementedException();
+ mConfig.mNetwork.addInetConfig(ifname, addr);
}
-std::vector ContainerImpl::getInterfaces()
+std::vector ContainerImpl::getInterfaces() const
{
return NetworkInterface::getInterfaces(getInitPid());
}
-NetworkInterfaceInfo ContainerImpl::getInterfaceInfo(const std::string& /*ifname*/)
+NetworkInterfaceInfo ContainerImpl::getInterfaceInfo(const std::string& ifname) const
{
- throw NotImplementedException();
+ NetworkInterface ni(getInitPid(), ifname);
+ std::vector addrs;
+ std::string macaddr;
+ InetAddr addr;
+ int mtu = 0, flags = 0;
+ Attrs attrs = ni.getAttrs();
+ for (const Attr& a : attrs) {
+ switch (a.name) {
+ case AttrName::MAC:
+ macaddr = a.value;
+ break;
+ case AttrName::MTU:
+ mtu = std::stoul(a.value);
+ break;
+ case AttrName::IPV6:
+ case AttrName::IPV4:
+ NetworkInterface::convertAttr2InetAddr(a, addr);
+ addrs.push_back(addr);
+ break;
+ case AttrName::FLAGS:
+ flags = std::stoul(a.value);
+ break;
+ default: //ignore others
+ break;
+ }
+ }
+ return NetworkInterfaceInfo{ifname, ni.status(), macaddr, mtu, flags, addrs};
}
void ContainerImpl::createInterface(const std::string& hostif,
@@ -205,7 +231,7 @@ void ContainerImpl::createInterface(const std::string& hostif,
InterfaceType type,
MacVLanMode mode)
{
- NetworkInterface ni(*this, zoneif);
+ NetworkInterface ni(getInitPid(), zoneif);
ni.create(hostif, type, mode);
}
diff --git a/libs/lxcpp/container-impl.hpp b/libs/lxcpp/container-impl.hpp
index 1bf44b7..3379143 100644
--- a/libs/lxcpp/container-impl.hpp
+++ b/libs/lxcpp/container-impl.hpp
@@ -34,7 +34,6 @@
namespace lxcpp {
-
class ContainerImpl : public virtual Container {
public:
ContainerImpl(const std::string &name, const std::string &path);
@@ -69,15 +68,19 @@ public:
const std::string& cwdInContainer);
// Network interfaces setup/config
+ /**
+ * adds interface configration.
+ * throws NetworkException if zoneif name already on list
+ */
void addInterfaceConfig(const std::string& hostif,
- const std::string& zoneif,
- InterfaceType type,
- MacVLanMode mode);
- void addAddrConfig(const std::string& ifname, const InetAddr& addr);
+ const std::string& zoneif,
+ InterfaceType type,
+ MacVLanMode mode);
+ void addInetConfig(const std::string& ifname, const InetAddr& addr);
// Network interfaces (runtime)
- std::vector getInterfaces();
- NetworkInterfaceInfo getInterfaceInfo(const std::string& ifname);
+ std::vector getInterfaces() const;
+ NetworkInterfaceInfo getInterfaceInfo(const std::string& ifname) const;
void createInterface(const std::string& hostif,
const std::string& zoneif,
InterfaceType type,
@@ -93,7 +96,6 @@ private:
// TODO: convert to ContainerConfig struct
std::vector mNamespaces;
- std::vector mInterfaceConfig;
};
} // namespace lxcpp
diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp
index 88c3ff8..3e126d2 100644
--- a/libs/lxcpp/container.hpp
+++ b/libs/lxcpp/container.hpp
@@ -34,14 +34,12 @@
namespace lxcpp {
-enum class NetStatus {
- DOWN,
- UP
-};
-
struct NetworkInterfaceInfo {
const std::string ifname;
const NetStatus status;
+ const std::string macaddr;
+ const int mtu;
+ const int flags;
const std::vector addrs;
};
@@ -78,14 +76,14 @@ public:
// Network interfaces setup/config
virtual void addInterfaceConfig(const std::string& hostif,
- const std::string& zoneif,
- InterfaceType type,
- MacVLanMode mode) = 0;
- virtual void addAddrConfig(const std::string& ifname, const InetAddr& addr) = 0;
+ const std::string& zoneif,
+ InterfaceType type,
+ MacVLanMode mode) = 0;
+ virtual void addInetConfig(const std::string& ifname, const InetAddr& addr) = 0;
// Network interfaces (runtime)
- virtual std::vector getInterfaces() = 0;
- virtual NetworkInterfaceInfo getInterfaceInfo(const std::string& ifname) = 0;
+ virtual std::vector getInterfaces() const = 0;
+ virtual NetworkInterfaceInfo getInterfaceInfo(const std::string& ifname) const = 0;
virtual void createInterface(const std::string& hostif,
const std::string& zoneif,
InterfaceType type,
diff --git a/libs/lxcpp/network-config.cpp b/libs/lxcpp/network-config.cpp
index 77e220a..17e1449 100644
--- a/libs/lxcpp/network-config.cpp
+++ b/libs/lxcpp/network-config.cpp
@@ -23,25 +23,81 @@
*/
#include "lxcpp/network-config.hpp"
+#include "lxcpp/network.hpp"
#include "lxcpp/exception.hpp"
+#include "logger/logger.hpp"
#include
+
namespace lxcpp {
-void NetworkInterfaceConfig::addNetAddr(const InetAddr& addr)
+const std::string& NetworkInterfaceConfig::getHostIf() const
+{
+ return mHostIf;
+}
+
+const std::string& NetworkInterfaceConfig::getZoneIf() const
+{
+ return mZoneIf;
+}
+
+const InterfaceType& NetworkInterfaceConfig::getType() const
+{
+ return mType;
+}
+
+const MacVLanMode& NetworkInterfaceConfig::getMode() const
+{
+ return mMode;
+}
+
+const std::vector& NetworkInterfaceConfig::getAddrList() const
+{
+ return mIpAddrList;
+}
+
+void NetworkInterfaceConfig::addInetAddr(const InetAddr& addr)
{
std::vector::iterator exists = std::find(mIpAddrList.begin(), mIpAddrList.end(), addr);
if (exists != mIpAddrList.end()) {
- std::string msg("Address alredy assigned");
+ std::string msg("Address already assigned");
throw NetworkException(msg);
}
mIpAddrList.push_back(addr);
}
-void NetworkInterfaceConfig::delNetAddr(const InetAddr& addr)
+void NetworkConfig::addInterfaceConfig(const std::string& hostif,
+ const std::string& zoneif,
+ InterfaceType type,
+ MacVLanMode mode)
{
- std::vector::iterator exists = std::find(mIpAddrList.begin(), mIpAddrList.end(), addr);
- mIpAddrList.erase(exists);
+ auto it = std::find_if(mInterfaces.begin(), mInterfaces.end(),
+ [&zoneif](const NetworkInterfaceConfig& entry) {
+ return entry.getZoneIf() == zoneif;
+ }
+ );
+ if (it != mInterfaces.end()) {
+ std::string msg = "Interface already exists";
+ LOGE(msg);
+ throw NetworkException(msg);
+ }
+ mInterfaces.push_back(NetworkInterfaceConfig(hostif,zoneif,type,mode));
+}
+
+void NetworkConfig::addInetConfig(const std::string& ifname, const InetAddr& addr)
+{
+ auto it = std::find_if(mInterfaces.begin(), mInterfaces.end(),
+ [&ifname](const NetworkInterfaceConfig& entry) {
+ return entry.getZoneIf() == ifname;
+ }
+ );
+
+ if (it == mInterfaces.end()) {
+ std::string msg = "No such interface";
+ LOGE(msg);
+ throw NetworkException(msg);
+ }
+ it->addInetAddr(addr);
}
} //namespace lxcpp
diff --git a/libs/lxcpp/network-config.hpp b/libs/lxcpp/network-config.hpp
index b4e2fe0..c94f45b 100644
--- a/libs/lxcpp/network-config.hpp
+++ b/libs/lxcpp/network-config.hpp
@@ -24,11 +24,15 @@
#ifndef LXCPP_NETWORK_CONFIG_HPP
#define LXCPP_NETWORK_CONFIG_HPP
+#include "config/config.hpp"
+#include "config/fields.hpp"
+
#include
#include
#include
#include
+#include
namespace lxcpp {
@@ -60,11 +64,18 @@ enum class InetAddrType {
IPV6
};
+enum class NetStatus {
+ DOWN,
+ UP
+};
+
+
/**
* Unified ip address
*/
struct InetAddr {
InetAddrType type;
+ uint32_t flags;
int prefix;
union {
struct in_addr ipv4;
@@ -99,22 +110,56 @@ public:
mType(type),
mMode(mode)
{
- // TODO: Remove temporary usage
- (void) mType;
- (void) mMode;
}
- void addNetAddr(const InetAddr&);
- void delNetAddr(const InetAddr&);
+ const std::string& getHostIf() const;
+
+ const std::string& getZoneIf() const;
+
+ const InterfaceType& getType() const;
+
+ const MacVLanMode& getMode() const;
+
+ const std::vector& getAddrList() const;
+
+ void addInetAddr(const InetAddr&);
private:
const std::string mHostIf;
const std::string mZoneIf;
const InterfaceType mType;
const MacVLanMode mMode;
+ //TODO mtu, macaddress, txqueue
+ /*
+ * above are interface parameters which can be read/modified:
+ * MTU (Maximum Transmit Unit) is maximum length of link level packet in TCP stream
+ * MAC address is also called hardware card address
+ * TXQueue is transmit queue length
+ *
+ * I think most usufull would be possibility to set MAC address, other have their
+ * well working defaults but can be tuned to make faster networking (especially localy)
+ */
std::vector mIpAddrList;
};
+/**
+ * Network interface configuration
+ */
+struct NetworkConfig {
+
+ //for convinience
+ void addInterfaceConfig(const std::string& hostif,
+ const std::string& zoneif,
+ InterfaceType type,
+ MacVLanMode mode);
+ void addInetConfig(const std::string& ifname, const InetAddr& addr);
+
+ std::vector mInterfaces;
+
+ //TODO tmporary to allow serialization of this object
+ CONFIG_REGISTER_EMPTY
+};
+
} //namespace lxcpp
#endif // LXCPP_NETWORK_CONFIG_HPP
diff --git a/libs/lxcpp/network.cpp b/libs/lxcpp/network.cpp
index ad01f6f..965f20c 100644
--- a/libs/lxcpp/network.cpp
+++ b/libs/lxcpp/network.cpp
@@ -23,16 +23,172 @@
#include "lxcpp/network.hpp"
+#include "lxcpp/container.hpp"
#include "lxcpp/exception.hpp"
#include "netlink/netlink-message.hpp"
#include "utils/make-clean.hpp"
+#include "utils/text.hpp"
+#include "logger/logger.hpp"
+
+#include
#include
+#include
+
+#define CHANGE_FLAGS_DEFAULT 0xffffffff
+/* from linux/if_addr.h:
+ * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags.
+ * If present, the value from struct ifaddrmsg will be ignored.
+ *
+ * But this FLAG is available since some kernel version
+ * check if one of extended flags id defined
+ */
+#ifndef IFA_F_MANAGETEMPADDR
+#define IFA_FLAGS IFA_UNSPEC
+#endif
using namespace vasum::netlink;
namespace lxcpp {
+namespace {
+std::string toString(const in_addr& addr)
+{
+ char buf[INET_ADDRSTRLEN];
+ const char* ret = ::inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN);
+ if (ret == NULL) {
+ std::string msg = "Can't parse inet v4 addr";
+ LOGE(msg);
+ throw NetworkException(msg);
+ }
+ return ret;
+}
+
+std::string toString(const in6_addr& addr)
+{
+ char buf[INET6_ADDRSTRLEN];
+ const char* ret = ::inet_ntop(AF_INET6, &addr, buf, INET6_ADDRSTRLEN);
+ if (ret == NULL) {
+ std::string msg = "Can't parse inet v6 addr";
+ LOGE(msg);
+ throw NetworkException(msg);
+ }
+ return ret;
+}
+
+uint32_t getInterfaceIndex(const std::string& name)
+{
+ uint32_t index = ::if_nametoindex(name.c_str());
+ if (!index) {
+ std::string msg = "Can't find interface";
+ LOGE(msg);
+ throw NetworkException(msg);
+ }
+ return index;
+}
+
+uint32_t getInterfaceIndex(const std::string& name, pid_t pid)
+{
+ NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST | NLM_F_ACK);
+ ifinfomsg infoPeer = utils::make_clean();
+ infoPeer.ifi_family = AF_UNSPEC;
+ infoPeer.ifi_change = CHANGE_FLAGS_DEFAULT;
+ nlm.put(infoPeer)
+ .put(IFLA_IFNAME, name);
+
+ NetlinkResponse response = send(nlm, pid);
+ if (!response.hasMessage()) {
+ std::string msg = "Can't get interface index";
+ LOGE(msg);
+ throw NetworkException(msg);
+ }
+
+ response.fetch(infoPeer);
+ return infoPeer.ifi_index;
+}
+
+void getAddressAttrs(Attrs& attrs, int family, const std::string& ifname, pid_t pid)
+{
+ uint32_t index = getInterfaceIndex(ifname, pid);
+ NetlinkMessage nlm(RTM_GETADDR, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
+ ifaddrmsg infoAddr = utils::make_clean();
+ infoAddr.ifa_family = family; //test AF_PACKET to get all AF_INET* ?
+ nlm.put(infoAddr);
+
+ NetlinkResponse response = send(nlm, pid);
+ if (!response.hasMessage()) {
+ return ;
+ }
+
+ Attr attr;
+ while (response.hasMessage()) {
+ ifaddrmsg addrmsg;
+ response.fetch(addrmsg);
+ if (addrmsg.ifa_index == index) {
+ InetAddr a;
+ if (addrmsg.ifa_family == AF_INET6) {
+ a.type = InetAddrType::IPV6;
+ } else if (addrmsg.ifa_family == AF_INET) {
+ a.type = InetAddrType::IPV4;
+ } else {
+ std::string msg = "Unsupported inet family";
+ LOGE(msg);
+ throw NetworkException(msg);
+ }
+ a.flags = addrmsg.ifa_flags; // IF_F_SECONDARY = secondary(alias)
+ a.prefix = addrmsg.ifa_prefixlen;
+
+ bool hasLocal = false;
+ while (response.hasAttribute()) {
+
+ int attrType = response.getAttributeType();
+ switch (attrType) {
+
+ // on each case line, int number in comment is value of the enum
+ case IFA_ADDRESS: //1
+ if (hasLocal) {
+ response.skipAttribute();
+ break;
+ }
+ // fall thru
+ case IFA_LOCAL: //2
+ if (addrmsg.ifa_family == AF_INET6) {
+ response.fetch(attrType, a.addr.ipv6);
+ } else if (addrmsg.ifa_family == AF_INET) {
+ response.fetch(attrType, a.addr.ipv4);
+ } else {
+ LOGW("unsupported family " << addrmsg.ifa_family);
+ response.skipAttribute();
+ }
+ hasLocal=true;
+ break;
+
+ case IFA_FLAGS: //8 extended flags - overwrites addrmsg.ifa_flags
+ response.fetch(IFA_FLAGS, a.flags);
+ break;
+
+ case IFA_LABEL: //3 <- should be equal to ifname
+ case IFA_BROADCAST://4
+ case IFA_ANYCAST: //5
+ case IFA_CACHEINFO://6
+ case IFA_MULTICAST://7
+ default:
+ //std::string tmp;
+ //response.fetch(attrType, tmp);
+ //std::cout << "skip(IFA) " << attrType << ":" << tmp << std::endl;
+ response.skipAttribute();
+ break;
+ }
+ }
+ NetworkInterface::convertInetAddr2Attr(a, attr);
+ attrs.push_back(attr);
+ }
+ response.fetchNextMessage();
+ }
+}
+} // anonymous namespace
+
+
void NetworkInterface::create(const std::string& hostif,
InterfaceType type,
MacVLanMode mode)
@@ -70,9 +226,21 @@ void NetworkInterface::createMacVLan(const std::string& /*hostif*/, MacVLanMode
throw NotImplementedException();
}
-void NetworkInterface::move(const std::string& /*hostif*/)
+void NetworkInterface::move(const std::string& hostif)
{
- throw NotImplementedException();
+ uint32_t index = getInterfaceIndex(hostif);
+ NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
+ ifinfomsg infopeer = utils::make_clean();
+ infopeer.ifi_family = AF_UNSPEC;
+ infopeer.ifi_index = index;
+ nlm.put(infopeer)
+ .put(IFLA_NET_NS_PID, mContainerPid);
+ send(nlm);
+
+ //rename to mIfname inside container
+ if (mIfname != hostif) {
+ renameFrom(hostif);
+ }
}
void NetworkInterface::destroy()
@@ -85,7 +253,7 @@ NetStatus NetworkInterface::status()
throw NotImplementedException();
/*
//TODO get container status, if stopped return CONFIGURED
- if (mContainer.getInitPid()<=0) return CONFIGURED;
+ if (mContainerPid<=0) return CONFIGURED;
// read netlink
return DOWN;*/
}
@@ -101,14 +269,152 @@ void NetworkInterface::down()
throw NotImplementedException();
}
-void NetworkInterface::setAttrs(const Attrs& /*attrs*/)
+void NetworkInterface::renameFrom(const std::string& oldif)
{
- throw NotImplementedException();
+ NetlinkMessage nlm(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK);
+ ifinfomsg infoPeer = utils::make_clean();
+ infoPeer.ifi_family = AF_UNSPEC;
+ infoPeer.ifi_index = getInterfaceIndex(oldif, mContainerPid);
+ infoPeer.ifi_change = CHANGE_FLAGS_DEFAULT;
+
+ nlm.put(infoPeer)
+ .put(IFLA_IFNAME, mIfname);
+ send(nlm, mContainerPid);
}
-const Attrs NetworkInterface::getAttrs() const
+void NetworkInterface::addInetAddr(const InetAddr& addr)
{
- throw NotImplementedException();
+ NetlinkMessage nlm(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK);
+ ifaddrmsg infoAddr = utils::make_clean();
+ infoAddr.ifa_index = getInterfaceIndex(mIfname, mContainerPid);
+ infoAddr.ifa_family = addr.type == InetAddrType::IPV4 ? AF_INET : AF_INET6;
+ infoAddr.ifa_prefixlen = addr.prefix;
+ infoAddr.ifa_flags = addr.flags;
+ nlm.put(infoAddr);
+
+ if (addr.type == InetAddrType::IPV6) {
+ nlm.put(IFA_ADDRESS, addr.addr.ipv6);
+ nlm.put(IFA_LOCAL, addr.addr.ipv6);
+ } else if (addr.type == InetAddrType::IPV4) {
+ nlm.put(IFA_ADDRESS, addr.addr.ipv4);
+ nlm.put(IFA_LOCAL, addr.addr.ipv4);
+ }
+
+ send(nlm, mContainerPid);
+}
+
+void NetworkInterface::setAttrs(const Attrs& attrs)
+{
+ //TODO check this: NetlinkMessage nlm(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK);
+ NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK);
+ unsigned mtu=0, link=0, txq=0;
+ ifinfomsg infoPeer = utils::make_clean();
+ infoPeer.ifi_family = AF_UNSPEC;
+ infoPeer.ifi_index = getInterfaceIndex(mIfname, mContainerPid);
+ infoPeer.ifi_change = CHANGE_FLAGS_DEFAULT;
+
+ for (const auto& attr : attrs) {
+ if (attr.name == AttrName::FLAGS) {
+ infoPeer.ifi_flags = stoul(attr.value);
+ } else if (attr.name == AttrName::CHANGE) {
+ infoPeer.ifi_change = stoul(attr.value);
+ } else if (attr.name == AttrName::TYPE) {
+ infoPeer.ifi_type = stoul(attr.value);
+ } else if (attr.name == AttrName::MTU) {
+ mtu = stoul(attr.value);
+ } else if (attr.name == AttrName::LINK) {
+ link = stoul(attr.value);
+ } else if (attr.name == AttrName::TXQLEN) {
+ txq = stoul(attr.value);
+ }
+ }
+ nlm.put(infoPeer);
+ if (mtu) {
+ nlm.put(IFLA_MTU, mtu);
+ }
+ if (link) {
+ nlm.put(IFLA_LINK, link);
+ }
+ if (txq) {
+ nlm.put(IFLA_TXQLEN, txq);
+ }
+
+ NetlinkResponse response = send(nlm, mContainerPid);
+ if (!response.hasMessage()) {
+ throw NetworkException("Can't set interface information");
+ }
+
+ // configure inet addresses
+ InetAddr addr;
+ for (const Attr& a : attrs) {
+ if (convertAttr2InetAddr(a, addr)) {
+ addInetAddr(addr);
+ }
+ }
+}
+
+Attrs NetworkInterface::getAttrs() const
+{
+ NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST | NLM_F_ACK);
+ ifinfomsg infoPeer = utils::make_clean();
+ infoPeer.ifi_family = AF_UNSPEC;
+ infoPeer.ifi_change = CHANGE_FLAGS_DEFAULT;
+ nlm.put(infoPeer)
+ .put(IFLA_IFNAME, mIfname);
+
+ NetlinkResponse response = send(nlm, mContainerPid);
+ if (!response.hasMessage()) {
+ throw NetworkException("Can't get interface information");
+ }
+
+ Attrs attrs;
+ response.fetch(infoPeer);
+ attrs.push_back(Attr{AttrName::FLAGS, std::to_string(infoPeer.ifi_flags)});
+ attrs.push_back(Attr{AttrName::TYPE, std::to_string(infoPeer.ifi_type)});
+
+ while (response.hasAttribute()) {
+ /*
+ * While traditional MAC addresses are all 48 bits in length,
+ * a few types of networks require 64-bit addresses instead.
+ */
+ std::string mac;
+ uint32_t mtu, link, txq;
+ int attrType = response.getAttributeType();
+ switch (attrType) {
+ case IFLA_ADDRESS: //1
+ response.fetch(IFLA_ADDRESS, mac);
+ attrs.push_back(Attr{AttrName::MAC, utils::toHexString(mac.c_str(), mac.size())});
+ break;
+ case IFLA_MTU: //4
+ response.fetch(IFLA_MTU, mtu);
+ attrs.push_back(Attr{AttrName::MTU, std::to_string(mtu)});
+ break;
+ case IFLA_LINK://5
+ response.fetch(IFLA_LINK, link);
+ attrs.push_back(Attr{AttrName::LINK, std::to_string(link)});
+ break;
+ case IFLA_TXQLEN://13
+ response.fetch(IFLA_TXQLEN, txq);
+ attrs.push_back(Attr{AttrName::TXQLEN, std::to_string(txq)});
+ break;
+ case IFLA_BROADCAST://2 MAC broadcast
+ case IFLA_IFNAME: //3
+ case IFLA_QDISC: //6 queue discipline
+ case IFLA_STATS: //7 struct net_device_stats
+ case IFLA_COST: //8
+ case IFLA_PRIORITY: //9
+ case IFLA_MASTER: //10
+ case IFLA_WIRELESS: //11
+ case IFLA_PROTINFO: //12
+ case IFLA_MAP: //14
+ default:
+ response.skipAttribute();
+ break;
+ }
+ }
+ getAddressAttrs(attrs, AF_INET, mIfname, mContainerPid);
+ getAddressAttrs(attrs, AF_INET6, mIfname, mContainerPid);
+ return attrs;
}
std::vector NetworkInterface::getInterfaces(pid_t initpid)
@@ -124,11 +430,87 @@ std::vector NetworkInterface::getInterfaces(pid_t initpid)
while (response.hasMessage()) {
std::string ifName;
response.skip();
- response.fetch(IFLA_IFNAME, ifName);
+ // fetched value contains \0 terminator
+ int len = response.getAttributeLength();
+ response.fetch(IFLA_IFNAME, ifName, len - 1);
iflist.push_back(ifName);
response.fetchNextMessage();
}
return iflist;
}
+void NetworkInterface::convertInetAddr2Attr(const InetAddr& a, Attr& attr)
+{
+ std::string value;
+
+ if (a.type == InetAddrType::IPV6) {
+ value += "ip=" + toString(a.addr.ipv6);
+ } else if (a.type == InetAddrType::IPV4) {
+ value += "ip=" + toString(a.addr.ipv4);
+ } else {
+ throw NetworkException();
+ }
+
+ value += ",pfx=" + std::to_string(a.prefix);
+ value += ",flags=" + std::to_string(a.flags);
+
+ if (a.type == InetAddrType::IPV6) {
+ attr = Attr{AttrName::IPV6, value};
+ } else {
+ attr = Attr{AttrName::IPV4, value};
+ }
+}
+
+bool NetworkInterface::convertAttr2InetAddr(const Attr& attr, InetAddr& addr)
+{
+ std::string::size_type s = 0U;
+ std::string::size_type e = s;
+
+ if (attr.name != AttrName::IPV6 && attr.name != AttrName::IPV4) {
+ return false; //not inet attribute
+ }
+
+ addr.prefix = 0;
+ addr.flags = 0;
+
+ bool addrFound = false;
+ while (e != std::string::npos) {
+ e = attr.value.find(',', s);
+ std::string ss = attr.value.substr(s, e - s);
+ s = e + 1;
+
+ std::string name;
+ std::string value;
+ std::string::size_type p = ss.find('=');
+ if (p != std::string::npos) {
+ name = ss.substr(0, p);
+ value = ss.substr(p + 1);
+ } else {
+ name = ss;
+ //value remains empty
+ }
+
+ if (name == "ip") {
+ if (attr.name == AttrName::IPV6) {
+ addr.type = InetAddrType::IPV6;
+ if (inet_pton(AF_INET6, value.c_str(), &addr.addr.ipv6) != 1) {
+ throw NetworkException("Parse IPV6 address");
+ }
+ } else if (attr.name == AttrName::IPV4) {
+ addr.type = InetAddrType::IPV4;
+ if (inet_pton(AF_INET, value.c_str(), &addr.addr.ipv4) != 1) {
+ throw NetworkException("Parse IPV4 address");
+ }
+ }
+ addrFound = true;
+ } else if (name == "pfx") {
+ addr.prefix = stoul(value);
+ } else if (name == "flags") {
+ addr.flags = stoul(value);
+ }
+ }
+
+ return addrFound;
+}
+
} // namespace lxcpp
diff --git a/libs/lxcpp/network.hpp b/libs/lxcpp/network.hpp
index 8381611..cc0167e 100644
--- a/libs/lxcpp/network.hpp
+++ b/libs/lxcpp/network.hpp
@@ -24,31 +24,65 @@
#ifndef LXCPP_NETWORK_HPP
#define LXCPP_NETWORK_HPP
-#include "lxcpp/container.hpp"
+#include "lxcpp/network-config.hpp"
+
+#include
#include
+#include
namespace lxcpp {
+enum class AttrName {
+ MAC,
+ FLAGS,
+ CHANGE,
+ TYPE,
+ MTU,
+ LINK,
+ TXQLEN,
+ IPV4,
+ IPV6,
+};
+
+inline std::ostream& operator<<(std::ostream& os, const AttrName& a) {
+ switch (a) {
+ case AttrName::MAC: os << "mac"; break;
+ case AttrName::FLAGS: os << "flags"; break;
+ case AttrName::CHANGE: os << "change"; break;
+ case AttrName::TYPE: os << "type"; break;
+ case AttrName::MTU: os << "mtu"; break;
+ case AttrName::LINK: os << "link"; break;
+ case AttrName::TXQLEN: os << "txq"; break;
+ case AttrName::IPV4: os << "ipv4"; break;
+ case AttrName::IPV6: os << "ipv6"; break;
+ }
+ return os;
+}
+
struct Attr {
- std::string name;
+ AttrName name;
std::string value;
};
typedef std::vector Attrs;
-
-/// Network operations to be performed on given container and interface
-/// operates on netlink device
+/**
+ * Network operations to be performed on given container and interface
+ * operates on netlink device
+ */
class NetworkInterface {
public:
- NetworkInterface(Container& c, const std::string& ifname) :
- mContainer(c),
+ /**
+ * Create network interface object for the ifname in the container
+ */
+ NetworkInterface(pid_t pid, const std::string& ifname) :
+ mContainerPid(pid),
mIfname(ifname)
{
- // TODO: Remove temporary usage
- (void) mContainer;
}
+ const std::string& getName() const { return mIfname; }
+
//Network actions on Container
void create(const std::string& hostif, InterfaceType type, MacVLanMode mode=MacVLanMode::PRIVATE);
void destroy();
@@ -56,19 +90,39 @@ public:
NetStatus status();
void up();
void down();
+
+ /**
+ * Rename interface name
+ * Equivalent to: ip link set dev $oldif name $this.mIfname
+ */
+ void renameFrom(const std::string& oldif);
+
void setAttrs(const Attrs& attrs);
- const Attrs getAttrs() const;
+ Attrs getAttrs() const;
+
+ void setMACAddress(const std::string& macaddr);
+ void setMTU(int mtu);
+ void setTxLength(int txlen);
+ void addInetAddr(const InetAddr& addr);
+ void delInetAddr(const InetAddr& addr);
static std::vector getInterfaces(pid_t initpid);
+ static void convertInetAddr2Attr(const InetAddr& addr, Attr& attr);
+ static bool convertAttr2InetAddr(const Attr& attr, InetAddr& addr);
+
private:
void createVeth(const std::string& hostif);
void createBridge(const std::string& hostif);
void createMacVLan(const std::string& hostif, MacVLanMode mode);
+ /**
+ * Move interface to container
+ * Equivalent to: ip link set dev $hostif netns $mContainerPid
+ */
void move(const std::string& hostif);
- Container& mContainer; ///< Container to operate on
- const std::string mIfname; ///< network interface name inside zone
+ pid_t mContainerPid; ///< Container pid to operate on (0=kernel)
+ const std::string mIfname; ///< network interface name inside zone
};
} // namespace lxcpp
diff --git a/server/netdev.cpp b/server/netdev.cpp
index dc8642c..8387c84 100644
--- a/server/netdev.cpp
+++ b/server/netdev.cpp
@@ -428,7 +428,9 @@ std::vector listNetdev(const pid_t& nsPid)
while (response.hasMessage()) {
std::string ifName;
response.skip();
- response.fetch(IFLA_IFNAME, ifName);
+ // fetched value contains \0 terminator
+ int len = response.getAttributeLength();
+ response.fetch(IFLA_IFNAME, ifName, len - 1);
interfaces.push_back(ifName);
response.fetchNextMessage();
}
diff --git a/tests/unit_tests/lxcpp/ut-network.cpp b/tests/unit_tests/lxcpp/ut-network.cpp
new file mode 100644
index 0000000..373ec1b
--- /dev/null
+++ b/tests/unit_tests/lxcpp/ut-network.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief Unit tests of lxcpp network helpers
+ */
+
+#include "config.hpp"
+#include "config/manager.hpp"
+#include "lxcpp/network.hpp"
+#include "ut.hpp"
+
+#include
+#include
+
+namespace {
+
+struct Fixture {
+ Fixture() {}
+ ~Fixture() {}
+};
+
+} // namespace
+
+/*
+ * NOTE: network inerface unit tests are not finished yet
+ * tests are developed/added together with network interface code
+ * and container code development
+ */
+
+BOOST_FIXTURE_TEST_SUITE(LxcppNetworkSuite, Fixture)
+
+using namespace lxcpp;
+
+BOOST_AUTO_TEST_CASE(ListInterfaces)
+{
+ std::vector iflist;
+ BOOST_CHECK_NO_THROW(iflist = NetworkInterface::getInterfaces(0);)
+ for (const auto& i : iflist) {
+ std::cout << i << std::endl;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(DetailedListInterfaces)
+{
+ std::vector iflist;
+ BOOST_CHECK_NO_THROW(iflist = NetworkInterface::getInterfaces(0);)
+ for (const auto& i : iflist) {
+ NetworkInterface ni(1,i);
+ std::cout << "Attrs of " << i << std::endl;
+ Attrs attrs;
+ BOOST_CHECK_NO_THROW(attrs = ni.getAttrs();)
+ for (const Attr& a : attrs) {
+ std::cout << a.name << "=" << a.value << "; ";
+ }
+ std::cout << std::endl;
+ }
+}
+BOOST_AUTO_TEST_CASE(NetworkConfigSerialization)
+{
+ NetworkConfig cfg;
+ std::string json;
+ BOOST_CHECK_NO_THROW(json = config::saveToJsonString(cfg);)
+ std::cout << json << std::endl;
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--
2.7.4
From e1624f3797d5c9a50f5f4b8bfd0ce4970d0ed5f4 Mon Sep 17 00:00:00 2001
From: Pawel Kubik
Date: Fri, 18 Sep 2015 14:41:31 +0200
Subject: [PATCH 06/16] Fixed test scripts
[Feature] N/A
[Cause] Unit tests using fixtures can't be run separately,
because their names contains bash special characters.
[Solution] Put test names inside quotes.
[Verification] Install, launch single test case with fixture.
Change-Id: I61e426957e080b1a145bd901c155677775d571ba
---
tests/scripts/vsm_launch_test.py | 5 +++++
tests/scripts/vsm_test_parser.py | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/tests/scripts/vsm_launch_test.py b/tests/scripts/vsm_launch_test.py
index 038ba30..dd5831f 100755
--- a/tests/scripts/vsm_launch_test.py
+++ b/tests/scripts/vsm_launch_test.py
@@ -5,6 +5,7 @@ from vsm_test_parser import Logger, Parser
import subprocess
import argparse
import os
+import re
_defLaunchArgs = ["--report_format=XML",
"--catch_system_errors=no",
@@ -38,6 +39,10 @@ def launchTest(cmd=[], externalToolCmd=[], parsing=True):
if externalToolCmd and not _checkIfBinExists(externalToolCmd[0]):
return
+ cmd[1:] = ["'{0}'".format(arg) if re.search("^\s*[^']*/.*<.*>\s*$", arg)
+ else arg
+ for arg in cmd[1:]]
+
log.info("Starting " + cmd[0] + " ...")
if parsing:
diff --git a/tests/scripts/vsm_test_parser.py b/tests/scripts/vsm_test_parser.py
index d0d4fa7..fc0eae6 100644
--- a/tests/scripts/vsm_test_parser.py
+++ b/tests/scripts/vsm_test_parser.py
@@ -80,7 +80,7 @@ class Logger(object):
commandPrefix = "vsm_launch_test.py " + bin + " -t "
self.infoTitle("Some tests failed. Use following command(s) to launch them explicitly:")
for test in self.__failedTests:
- self.error(self.__indentChar + commandPrefix + test)
+ self.error(self.__indentChar + commandPrefix + "'{0}'".format(test))
def terminatedBySignal(self, bin, signum):
self.error("\n=========== FAILED ===========\n")
--
2.7.4
From fe7acf72de44d39b5cb434fd9119364fc2ba44e2 Mon Sep 17 00:00:00 2001
From: Lukasz Pawelczyk
Date: Thu, 17 Sep 2015 18:18:04 +0200
Subject: [PATCH 07/16] lxcpp: Terminal preparation part 1 (host)
[Feature] Prepare pseudoterminals for the container
[Verification] Build, install, run tests
Changes in this commit:
- PrepHostTerminal command and surrounding function (openPty)
- Terminal(s)Config
- Changes to Start::daemonize() to do its job better
- fd-utils helpers for FD flags
- set CLOEXEC on FDs received through libConfig
Change-Id: I432447900c189bb50669267ff4422c36860b5481
---
common/utils/channel.cpp | 6 +-
common/utils/fd-utils.cpp | 32 ++++++
common/utils/fd-utils.hpp | 10 ++
libs/config/fdstore.cpp | 2 +-
libs/lxcpp/CMakeLists.txt | 2 +-
libs/lxcpp/commands/prep-host-terminal.cpp | 55 ++++++++++
libs/lxcpp/commands/prep-host-terminal.hpp | 57 +++++++++++
libs/lxcpp/commands/start.cpp | 60 ++++++-----
libs/lxcpp/container-config.hpp | 12 ++-
libs/lxcpp/container-impl.cpp | 16 +++
libs/lxcpp/container-impl.hpp | 2 +
libs/lxcpp/container.hpp | 2 +
libs/lxcpp/exception.hpp | 5 +
libs/lxcpp/guard/main.cpp | 9 +-
libs/lxcpp/terminal-config.hpp | 76 ++++++++++++++
libs/lxcpp/terminal.cpp | 155 +++++++++++++++++++++++++++++
libs/lxcpp/terminal.hpp | 59 +++++++++++
libs/lxcpp/utils.cpp | 44 +-------
libs/lxcpp/utils.hpp | 10 --
19 files changed, 526 insertions(+), 88 deletions(-)
create mode 100644 libs/lxcpp/commands/prep-host-terminal.cpp
create mode 100644 libs/lxcpp/commands/prep-host-terminal.hpp
create mode 100644 libs/lxcpp/terminal-config.hpp
create mode 100644 libs/lxcpp/terminal.cpp
create mode 100644 libs/lxcpp/terminal.hpp
diff --git a/common/utils/channel.cpp b/common/utils/channel.cpp
index 3a0dd31..52047ee 100644
--- a/common/utils/channel.cpp
+++ b/common/utils/channel.cpp
@@ -113,11 +113,7 @@ void Channel::setCloseOnExec(const bool closeOnExec)
{
const int fd = getFD();
- if (closeOnExec) {
- ::fcntl(fd, F_SETFD, ::fcntl(fd, F_GETFD) | FD_CLOEXEC);
- } else {
- ::fcntl(fd, F_SETFD, ::fcntl(fd, F_GETFD) & ~FD_CLOEXEC);
- }
+ utils::setCloseOnExec(fd, closeOnExec);
}
void Channel::closeSocket(int socketIndex)
diff --git a/common/utils/fd-utils.cpp b/common/utils/fd-utils.cpp
index 3b7b998..3e0db3e 100644
--- a/common/utils/fd-utils.cpp
+++ b/common/utils/fd-utils.cpp
@@ -93,6 +93,28 @@ void waitForEvent(int fd,
}
}
+void setFDFlag(const int fd, const int getOp, const int setOp, const int flag, const bool set)
+{
+ int ret = ::fcntl(fd, getOp);
+ if (ret == -1) {
+ std::string msg = "fcntl(): Failed to get FD flags: " + getSystemErrorMessage();
+ LOGE(msg);
+ throw UtilsException(msg);
+ }
+
+ if (set) {
+ ret = ::fcntl(fd, setOp, ret | flag);
+ } else {
+ ret = ::fcntl(fd, setOp, ret & ~flag);
+ }
+
+ if (ret == -1) {
+ std::string msg = "fcntl(): Failed to set FD flag: " + getSystemErrorMessage();
+ LOGE(msg);
+ throw UtilsException(msg);
+ }
+}
+
} // namespace
void close(int fd)
@@ -348,5 +370,15 @@ bool fdSend(int socket, int fd, const unsigned int timeoutMS)
return true;
}
+void setCloseOnExec(int fd, bool closeOnExec)
+{
+ setFDFlag(fd, F_GETFD, F_SETFD, FD_CLOEXEC, closeOnExec);
+}
+
+void setNonBlocking(int fd, bool nonBlocking)
+{
+ setFDFlag(fd, F_GETFL, F_SETFL, O_NONBLOCK, nonBlocking);
+}
+
} // namespace utils
diff --git a/common/utils/fd-utils.hpp b/common/utils/fd-utils.hpp
index 56e3f41..91bbff4 100644
--- a/common/utils/fd-utils.hpp
+++ b/common/utils/fd-utils.hpp
@@ -86,6 +86,16 @@ bool fdSend(int socket, int fd, const unsigned int timeoutMS = 5000);
*/
int fdRecv(int socket, const unsigned int timeoutMS = 5000);
+/**
+ * Set or remove CLOEXEC on a file descriptor
+ */
+void setCloseOnExec(int fd, bool closeOnExec);
+
+/**
+ * Set or remove NONBLOCK on a file descriptor
+ */
+void setNonBlocking(int fd, bool nonBlocking);
+
} // namespace utils
#endif // COMMON_UTILS_FD_HPP
diff --git a/libs/config/fdstore.cpp b/libs/config/fdstore.cpp
index cc0b903..44d2418 100644
--- a/libs/config/fdstore.cpp
+++ b/libs/config/fdstore.cpp
@@ -262,7 +262,7 @@ int FDStore::receiveFD(const unsigned int timeoutMS)
// Receive
for(;;) {
- ssize_t ret = ::recvmsg(mFD, &msgh, MSG_WAITALL);
+ ssize_t ret = ::recvmsg(mFD, &msgh, MSG_WAITALL | MSG_CMSG_CLOEXEC);
if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
// Neglected errors, retry
diff --git a/libs/lxcpp/CMakeLists.txt b/libs/lxcpp/CMakeLists.txt
index 8f391e8..d5e205b 100644
--- a/libs/lxcpp/CMakeLists.txt
+++ b/libs/lxcpp/CMakeLists.txt
@@ -51,7 +51,7 @@ PKG_CHECK_MODULES(LXCPP_DEPS REQUIRED glib-2.0)
INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER})
INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS} ${LXCPP_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS})
-TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${Boost_LIBRARIES} Logger Config)
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${Boost_LIBRARIES} Logger Config util)
## Generate the pc file ########################################################
CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY)
diff --git a/libs/lxcpp/commands/prep-host-terminal.cpp b/libs/lxcpp/commands/prep-host-terminal.cpp
new file mode 100644
index 0000000..f219ff9
--- /dev/null
+++ b/libs/lxcpp/commands/prep-host-terminal.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Implementation of host terminal preparation
+ */
+
+#include "lxcpp/commands/prep-host-terminal.hpp"
+#include "lxcpp/terminal.hpp"
+
+#include "logger/logger.hpp"
+
+
+namespace lxcpp {
+
+
+PrepHostTerminal::PrepHostTerminal(TerminalsConfig &terminals)
+ : mTerminals(terminals)
+{
+}
+
+PrepHostTerminal::~PrepHostTerminal()
+{
+}
+
+void PrepHostTerminal::execute()
+{
+ LOGD("Creating " << mTerminals.count << " pseudoterminal(s) on the host side:");
+
+ for (int i = 0; i < mTerminals.count; ++i)
+ {
+ const auto pty = lxcpp::openPty(true);
+ LOGD(pty.second << " has been created");
+ mTerminals.PTYs.emplace_back(pty.first, pty.second);
+ }
+}
+
+
+} // namespace lxcpp
diff --git a/libs/lxcpp/commands/prep-host-terminal.hpp b/libs/lxcpp/commands/prep-host-terminal.hpp
new file mode 100644
index 0000000..f7153b2
--- /dev/null
+++ b/libs/lxcpp/commands/prep-host-terminal.hpp
@@ -0,0 +1,57 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Headers for host terminal preparation
+ */
+
+#ifndef LXCPP_COMMANDS_PREP_HOST_TERMINAL_HPP
+#define LXCPP_COMMANDS_PREP_HOST_TERMINAL_HPP
+
+#include "lxcpp/commands/command.hpp"
+#include "lxcpp/terminal-config.hpp"
+
+
+namespace lxcpp {
+
+
+class PrepHostTerminal final: Command {
+public:
+ /**
+ * Prepares the terminal on the host side.
+ *
+ * It creates a number of pseudoterminals and stores them
+ * to be passed to the guard and prepared for init process.
+ *
+ * @param config container's config
+ */
+ PrepHostTerminal(TerminalsConfig &config);
+ ~PrepHostTerminal();
+
+ void execute();
+
+private:
+ TerminalsConfig &mTerminals;
+};
+
+
+} // namespace lxcpp
+
+
+#endif // LXCPP_COMMANDS_PREP_HOST_TERMINAL_HPP
diff --git a/libs/lxcpp/commands/start.cpp b/libs/lxcpp/commands/start.cpp
index f68654a..32a3054 100644
--- a/libs/lxcpp/commands/start.cpp
+++ b/libs/lxcpp/commands/start.cpp
@@ -25,11 +25,14 @@
#include "lxcpp/exception.hpp"
#include "lxcpp/process.hpp"
#include "lxcpp/utils.hpp"
+#include "lxcpp/terminal.hpp"
#include "logger/logger.hpp"
#include "config/manager.hpp"
#include
+#include
+#include
namespace lxcpp {
@@ -94,41 +97,44 @@ void Start::parent(const pid_t pid)
void Start::daemonize()
{
+ // Prepare a clean daemonized environment for a guard process:
+
+ // Set a new session so the process looses its control terminal
+ if (::setsid() < 0) {
+ ::_exit(EXIT_FAILURE);
+ }
+
// Double fork() with exit() to reattach the process under the host's init
+ // and to make sure that the child (guard) is not a process group leader
+ // and cannot reacquire its control terminal
pid_t pid = ::fork();
- if (pid < 0) {
+ if (pid < 0) { // fork failed
+ ::_exit(EXIT_FAILURE);
+ }
+ if (pid > 0) { // exit in parent process
+ ::_exit(EXIT_SUCCESS);
+ }
+
+ // Chdir to / so it's independent on other directories
+ if (::chdir("/") < 0) {
::_exit(EXIT_FAILURE);
}
- if (pid == 0) {
- // Prepare a clean environment for a guard process:
- // - chdir to / so it's independent on other directories
- // - null std* fds so it's properly dettached from the terminal
- // - set a new session so it cannot reacquire a terminal
-
- if (::chdir("/") < 0) {
- ::_exit(EXIT_FAILURE);
- }
- if (nullStdFDs() <0) {
- ::_exit(EXIT_FAILURE);
- }
- if (::setsid() < 0) {
- ::_exit(EXIT_FAILURE);
- }
-
- // Add name and path of the container to argv. They are not used, but will
- // identify the container in the process list in case setProcTitle() fails
- // and will guarantee we have enough argv memory to write the title we want.
- const char *argv[] = {mGuardPath.c_str(),
- mChannelFD.c_str(),
- mConfig.mName.c_str(),
- mConfig.mRootPath.c_str(),
- NULL};
- ::execve(argv[0], const_cast(argv), NULL);
+ // Null std* fds so it's properly dettached from the terminal
+ if (nullStdFDs() < 0) {
::_exit(EXIT_FAILURE);
}
- ::_exit(EXIT_SUCCESS);
+ // Add name and path of the container to argv. They are not used, but will
+ // identify the container in the process list in case setProcTitle() fails
+ // and will guarantee we have enough argv memory to write the title we want.
+ const char *argv[] = {mGuardPath.c_str(),
+ mChannelFD.c_str(),
+ mConfig.mName.c_str(),
+ mConfig.mRootPath.c_str(),
+ NULL};
+ ::execve(argv[0], const_cast(argv), NULL);
+ ::_exit(EXIT_FAILURE);
}
diff --git a/libs/lxcpp/container-config.hpp b/libs/lxcpp/container-config.hpp
index 54422bf..c84b4ef 100644
--- a/libs/lxcpp/container-config.hpp
+++ b/libs/lxcpp/container-config.hpp
@@ -26,6 +26,7 @@
#include "lxcpp/logger-config.hpp"
#include "lxcpp/network-config.hpp"
+#include "lxcpp/terminal-config.hpp"
#include
#include
@@ -100,6 +101,14 @@ struct ContainerConfig {
*/
LoggerConfig mLogger;
+ /**
+ * Configuration for terminal(s), from API point of view, only their number.
+ *
+ * Set: setTerminalCount()
+ * Get: none
+ */
+ TerminalsConfig mTerminals;
+
ContainerConfig() : mGuardPid(-1), mInitPid(-1) {}
CONFIG_REGISTER
@@ -109,7 +118,8 @@ struct ContainerConfig {
mGuardPid,
mInitPid,
mInit,
- mLogger
+ mLogger,
+ mTerminals
)
};
diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp
index a524231..715dad8 100644
--- a/libs/lxcpp/container-impl.cpp
+++ b/libs/lxcpp/container-impl.cpp
@@ -29,6 +29,7 @@
#include "lxcpp/capability.hpp"
#include "lxcpp/commands/attach.hpp"
#include "lxcpp/commands/start.hpp"
+#include "lxcpp/commands/prep-host-terminal.hpp"
#include "logger/logger.hpp"
#include "utils/exception.hpp"
@@ -128,9 +129,24 @@ void ContainerImpl::setLogger(const logger::LogType type,
mConfig.mLogger.set(type, level, arg);
}
+void ContainerImpl::setTerminalCount(const unsigned int count)
+{
+ if (count == 0) {
+ const std::string msg = "Container needs at least one terminal";
+ LOGE(msg);
+ throw ConfigureException(msg);
+ }
+
+ mConfig.mTerminals.count = count;
+}
+
void ContainerImpl::start()
{
// TODO: check config consistency and completeness somehow
+
+ PrepHostTerminal terminal(mConfig.mTerminals);
+ terminal.execute();
+
Start start(mConfig);
start.execute();
}
diff --git a/libs/lxcpp/container-impl.hpp b/libs/lxcpp/container-impl.hpp
index 3379143..97b9155 100644
--- a/libs/lxcpp/container-impl.hpp
+++ b/libs/lxcpp/container-impl.hpp
@@ -54,6 +54,8 @@ public:
const logger::LogLevel level,
const std::string &arg);
+ void setTerminalCount(const unsigned int count);
+
const std::vector& getNamespaces() const;
// Execution actions
diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp
index 3e126d2..bf10a76 100644
--- a/libs/lxcpp/container.hpp
+++ b/libs/lxcpp/container.hpp
@@ -63,6 +63,8 @@ public:
const logger::LogLevel level,
const std::string &arg) = 0;
+ virtual void setTerminalCount(const unsigned int count) = 0;
+
// Execution actions
virtual void start() = 0;
virtual void stop() = 0;
diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp
index 11a6a0e..387e2eb 100644
--- a/libs/lxcpp/exception.hpp
+++ b/libs/lxcpp/exception.hpp
@@ -71,6 +71,11 @@ struct UtilityException: public Exception {
: Exception(message) {}
};
+struct TerminalException: public Exception {
+ explicit TerminalException(const std::string& message = "Error during a terminal operation")
+ : Exception(message) {}
+};
+
struct BadArgument: public Exception {
explicit BadArgument(const std::string& message = "Bad argument passed")
: Exception(message) {}
diff --git a/libs/lxcpp/guard/main.cpp b/libs/lxcpp/guard/main.cpp
index c8db30b..1065ecb 100644
--- a/libs/lxcpp/guard/main.cpp
+++ b/libs/lxcpp/guard/main.cpp
@@ -35,15 +35,18 @@ int main(int argc, char *argv[])
::_exit(EXIT_FAILURE);
}
+ int channel = std::stoi(argv[1]);
+
// NOTE: this might not be required now, but I leave it here not to forget.
// We need to investigate this with vasum and think about possibility of
// poorly written software that leaks file descriptors and might use LXCPP.
#if 0
for(int fd = 3; fd < ::sysconf(_SC_OPEN_MAX); ++fd) {
- utils::close(fd);
+ if (fd != channel) {
+ utils::close(fd);
+ }
}
#endif
- int fd = std::stoi(argv[1]);
- return lxcpp::startGuard(fd);
+ return lxcpp::startGuard(channel);
}
diff --git a/libs/lxcpp/terminal-config.hpp b/libs/lxcpp/terminal-config.hpp
new file mode 100644
index 0000000..3d6675a
--- /dev/null
+++ b/libs/lxcpp/terminal-config.hpp
@@ -0,0 +1,76 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsumg.com)
+ * @brief Terminal configuration
+ */
+
+#ifndef LXCPP_TERMINAL_CONFIG_HPP
+#define LXCPP_TERMINAL_CONFIG_HPP
+
+#include "config/config.hpp"
+#include "config/fields.hpp"
+
+#include
+#include
+
+
+namespace lxcpp {
+
+
+struct TerminalConfig {
+ config::FileDescriptor masterFD;
+ std::string ptsName;
+
+ TerminalConfig()
+ : masterFD(-1)
+ {}
+
+ TerminalConfig(const int masterFD, const std::string &ptsName)
+ : masterFD(masterFD),
+ ptsName(ptsName)
+ {}
+
+ CONFIG_REGISTER
+ (
+ masterFD,
+ ptsName
+ )
+};
+
+struct TerminalsConfig {
+ int count;
+ std::vector PTYs;
+
+ TerminalsConfig(const int count = 1)
+ : count(count)
+ {}
+
+ CONFIG_REGISTER
+ (
+ count,
+ PTYs
+ )
+};
+
+
+} //namespace lxcpp
+
+
+#endif // LXCPP_TERMINAL_CONFIG_HPP
diff --git a/libs/lxcpp/terminal.cpp b/libs/lxcpp/terminal.cpp
new file mode 100644
index 0000000..ce77cd5
--- /dev/null
+++ b/libs/lxcpp/terminal.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Terminal helpers implementation
+ */
+
+#include "lxcpp/exception.hpp"
+
+#include "logger/logger.hpp"
+#include "utils/exception.hpp"
+#include "utils/fd-utils.hpp"
+
+#include
+#include
+#include
+#include
+
+
+namespace lxcpp {
+
+
+namespace {
+
+void openpty(int *master, int *slave)
+{
+ // Do not use other parameters, they are not 100% safe
+ if (-1 == ::openpty(master, slave, NULL, NULL, NULL)) {
+ const std::string msg = "openpty() failed: " + utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw TerminalException(msg);
+ }
+}
+
+void tcgetattr(const int fd, struct termios *termios_p)
+{
+ if (-1 == ::tcgetattr(fd, termios_p)) {
+ const std::string msg = "tcgetattr() failed: " + utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw TerminalException(msg);
+ }
+}
+
+void tcsetattr(const int fd, const int optional_actions, const struct termios *termios_p)
+{
+ if (-1 == ::tcsetattr(fd, optional_actions, termios_p)) {
+ const std::string msg = "tcsetattr() failed: " + utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw TerminalException(msg);
+ }
+}
+
+std::string ttyname_r(const int fd)
+{
+ char ptsName[PATH_MAX];
+ int rc = ::ttyname_r(fd, ptsName, PATH_MAX);
+
+ if (rc != 0) {
+ const std::string msg = "ttyname_r() failed: " + utils::getSystemErrorMessage(rc);
+ LOGE(msg);
+ throw TerminalException(msg);
+ }
+
+ return ptsName;
+}
+
+} // namespace
+
+
+/*
+ * This function has to be safe in regard to signal(7)
+ */
+int nullStdFDs()
+{
+ int ret = -1;
+
+ int fd = TEMP_FAILURE_RETRY(::open("/dev/null", O_RDWR | O_CLOEXEC));
+ if (fd == -1) {
+ goto err;
+ }
+
+ if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDIN_FILENO))) {
+ goto err_close;
+ }
+
+ if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDOUT_FILENO))) {
+ goto err_close;
+ }
+
+ if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDERR_FILENO))) {
+ goto err_close;
+ }
+
+ if (-1 == TEMP_FAILURE_RETRY(::close(fd))) {
+ goto err;
+ }
+
+ return 0;
+
+err_close:
+ TEMP_FAILURE_RETRY(::close(fd));
+err:
+ return ret;
+}
+
+std::pair openPty(bool rawMode)
+{
+ int master, slave;
+ std::string ptsName;
+
+ try {
+ lxcpp::openpty(&master, &slave);
+
+ utils::setCloseOnExec(master, true);
+ utils::setNonBlocking(master, true);
+
+ if (rawMode) {
+ struct termios ttyAttr;
+
+ lxcpp::tcgetattr(slave, &ttyAttr);
+ ::cfmakeraw(&ttyAttr);
+ lxcpp::tcsetattr(slave, TCSADRAIN, &ttyAttr);
+ }
+
+ ptsName = lxcpp::ttyname_r(slave);
+
+ } catch(std::exception&) {
+ TEMP_FAILURE_RETRY(::close(master));
+ TEMP_FAILURE_RETRY(::close(slave));
+
+ throw;
+ }
+
+ utils::close(slave);
+ return std::pair(master, ptsName);
+}
+
+
+} // namespace lxcpp
diff --git a/libs/lxcpp/terminal.hpp b/libs/lxcpp/terminal.hpp
new file mode 100644
index 0000000..85ae6e2
--- /dev/null
+++ b/libs/lxcpp/terminal.hpp
@@ -0,0 +1,59 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Terminal helpers headers
+ */
+
+#ifndef LXCPP_TERMINAL_HPP
+#define LXCPP_TERMINAL_HPP
+
+
+namespace lxcpp {
+
+
+/**
+ * Nullifies all standard file descriptors (stdin, stdout, stderr)
+ * replacing them with file descriptor to /dev/null. Used to
+ * as a part of a process to detach a process from a control terminal.
+ *
+ * This function has to be safe in regard to signal(7)
+ *
+ * @returns an error code in case of failure.
+ */
+int nullStdFDs();
+
+/**
+ * This function creates a new pair of virtual character devices
+ * using a pseudtoreminal interface. It also configures as much as it
+ * can so the devices are immediately usable.
+ *
+ * @param rawMode Whether to set the terminal in the raw mode (termios(2))
+ *
+ * @returns file descriptor to the master device and the path/name of
+ * the pts slace device.
+ */
+std::pair openPty(bool rawMode);
+
+
+} // namespace lxcpp
+
+
+
+#endif // LXCPP_TERMINAL_HPP
diff --git a/libs/lxcpp/utils.cpp b/libs/lxcpp/utils.cpp
index 41e76b5..685d915 100644
--- a/libs/lxcpp/utils.cpp
+++ b/libs/lxcpp/utils.cpp
@@ -21,16 +21,16 @@
* @brief LXCPP utils implementation
*/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
#include "lxcpp/exception.hpp"
#include "logger/logger.hpp"
#include "utils/fd-utils.hpp"
#include "utils/exception.hpp"
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
#include
#include
#include
@@ -41,42 +41,6 @@
namespace lxcpp {
-/*
- * This function has to be safe in regard to signal(7)
- */
-int nullStdFDs()
-{
- int ret = -1;
-
- int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR | O_CLOEXEC));
- if (fd == -1) {
- goto err;
- }
-
- if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDIN_FILENO))) {
- goto err_close;
- }
-
- if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDOUT_FILENO))) {
- goto err_close;
- }
-
- if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDERR_FILENO))) {
- goto err_close;
- }
-
- if (-1 == TEMP_FAILURE_RETRY(::close(fd))) {
- goto err_close;
- }
-
- return 0;
-
-err_close:
- TEMP_FAILURE_RETRY(::close(fd));
-err:
- return ret;
-}
-
void setProcTitle(const std::string &title)
{
std::ifstream f("/proc/self/stat");
diff --git a/libs/lxcpp/utils.hpp b/libs/lxcpp/utils.hpp
index 2a59303..e4c158b 100644
--- a/libs/lxcpp/utils.hpp
+++ b/libs/lxcpp/utils.hpp
@@ -29,16 +29,6 @@
namespace lxcpp {
-/**
- * Nullifies all standard file descriptors (stdin, stdout, stderr)
- * replacing them with file descriptor to /dev/null. Used to
- * as a part of a process to detach a process from a control terminal.
- *
- * This function has to be safe in regard to signal(7)
- *
- * @returns an error code in case of failure.
- */
-int nullStdFDs();
/**
* Changes the tittle of a current process title (e.g. visible in ps tool).
--
2.7.4
From 08a871f9e354e79e755402cd0a97dc6d4501ef47 Mon Sep 17 00:00:00 2001
From: Lukasz Pawelczyk
Date: Fri, 18 Sep 2015 16:26:58 +0200
Subject: [PATCH 08/16] lxcpp: Terminal preparation part 2 (guest)
[Feature] Make use of the created pseudoterminals in the container
[Verification] Build, install, run tests
Changes in this commit:
- PrepGuestTerminal command
- it's main function: setupIOControlTTY()
- some more utils/terminal wrappers for syscalls
- long overdue open(2) wrapper
Change-Id: I235baec044ed82d3376cba3f2e5b4d18f5b1dd71
---
common/utils/fd-utils.cpp | 59 +++++++++++++++++++++++++-
common/utils/fd-utils.hpp | 17 ++++++++
libs/lxcpp/commands/attach.cpp | 8 +---
libs/lxcpp/commands/prep-guest-terminal.cpp | 64 +++++++++++++++++++++++++++++
libs/lxcpp/commands/prep-guest-terminal.hpp | 58 ++++++++++++++++++++++++++
libs/lxcpp/commands/prep-host-terminal.cpp | 3 +-
libs/lxcpp/container-impl.cpp | 34 +++++++++++++++
libs/lxcpp/credentials.cpp | 12 ++++++
libs/lxcpp/credentials.hpp | 4 +-
libs/lxcpp/guard/guard.cpp | 4 ++
libs/lxcpp/guard/main.cpp | 6 +--
libs/lxcpp/process.cpp | 10 +----
libs/lxcpp/terminal.cpp | 32 +++++++++++++++
libs/lxcpp/terminal.hpp | 10 +++++
14 files changed, 299 insertions(+), 22 deletions(-)
create mode 100644 libs/lxcpp/commands/prep-guest-terminal.cpp
create mode 100644 libs/lxcpp/commands/prep-guest-terminal.hpp
diff --git a/common/utils/fd-utils.cpp b/common/utils/fd-utils.cpp
index 3e0db3e..9bd7d29 100644
--- a/common/utils/fd-utils.cpp
+++ b/common/utils/fd-utils.cpp
@@ -22,6 +22,10 @@
* @brief File descriptor utility functions
*/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
#include "config.hpp"
#include "utils/fd-utils.hpp"
@@ -32,9 +36,11 @@
#include
#include
#include
+#include
#include
#include
#include
+#include
#include
namespace fs = boost::filesystem;
@@ -117,6 +123,31 @@ void setFDFlag(const int fd, const int getOp, const int setOp, const int flag, c
} // namespace
+
+int open(const std::string &path, int flags, mode_t mode)
+{
+ assert(!(flags & O_CREAT || flags & O_TMPFILE) || mode >= 0);
+
+ int fd;
+
+ for (;;) {
+ fd = ::open(path.c_str(), flags, mode);
+
+ if (-1 == fd) {
+ if (errno == EINTR) {
+ LOGT("open() interrupted by a signal, retrying");
+ continue;
+ }
+ const std::string msg = "open() failed: " + getSystemErrorMessage();
+ LOGE(msg);
+ throw UtilsException(msg);
+ }
+ break;
+ }
+
+ return fd;
+}
+
void close(int fd)
{
if (fd < 0) {
@@ -126,7 +157,7 @@ void close(int fd)
for (;;) {
if (-1 == ::close(fd)) {
if (errno == EINTR) {
- LOGT("Close interrupted by a signal, retrying");
+ LOGT("close() interrupted by a signal, retrying");
continue;
}
LOGE("Error in close: " << getSystemErrorMessage());
@@ -148,6 +179,32 @@ void shutdown(int fd)
}
}
+int ioctl(int fd, unsigned long request, void *argp)
+{
+ int ret = ::ioctl(fd, request, argp);
+ if (ret == -1) {
+ const std::string msg = "ioctl() failed: " + getSystemErrorMessage();
+ LOGE(msg);
+ throw UtilsException(msg);
+ }
+ return ret;
+}
+
+int dup2(int oldFD, int newFD, bool closeOnExec)
+{
+ int flags = 0;
+ if (closeOnExec) {
+ flags |= O_CLOEXEC;
+ }
+ int fd = dup3(oldFD, newFD, flags);
+ if (fd == -1) {
+ const std::string msg = "dup3() failed: " + getSystemErrorMessage();
+ LOGE(msg);
+ throw UtilsException(msg);
+ }
+ return fd;
+}
+
void write(int fd, const void* bufferPtr, const size_t size, int timeoutMS)
{
chr::high_resolution_clock::time_point deadline = chr::high_resolution_clock::now() +
diff --git a/common/utils/fd-utils.hpp b/common/utils/fd-utils.hpp
index 91bbff4..60aed45 100644
--- a/common/utils/fd-utils.hpp
+++ b/common/utils/fd-utils.hpp
@@ -25,11 +25,18 @@
#ifndef COMMON_UTILS_FD_HPP
#define COMMON_UTILS_FD_HPP
+#include
#include
+#include
namespace utils {
/**
+ * Open a file.
+ */
+int open(const std::string &path, int flags, mode_t mode = -1);
+
+/**
* Close the file descriptor.
*/
void close(int fd);
@@ -40,6 +47,16 @@ void close(int fd);
void shutdown(int fd);
/**
+ * Operation on a special file
+ */
+int ioctl(int fd, unsigned long request, void *argp);
+
+/**
+ * Duplicate one file desciptor onto another
+ */
+int dup2(int olfFD, int newFD, bool closeOnExec = false);
+
+/**
* Write to a file descriptor, throw on error.
*
* @param fd file descriptor
diff --git a/libs/lxcpp/commands/attach.cpp b/libs/lxcpp/commands/attach.cpp
index 419f651..e1bdfef 100644
--- a/libs/lxcpp/commands/attach.cpp
+++ b/libs/lxcpp/commands/attach.cpp
@@ -132,13 +132,7 @@ Attach::Attach(lxcpp::ContainerImpl& container,
mEnvToKeep(envToKeep),
mEnvToSet(envToSet)
{
- mTTYFD = ::open(ttyPath.c_str(), O_RDWR | O_NOCTTY);
- if (mTTYFD < 0) {
- const std::string msg = "open() failed: " +
- utils::getSystemErrorMessage();
- LOGE(msg);
- throw BadArgument(msg);
- }
+ mTTYFD = utils::open(ttyPath, O_RDWR | O_NOCTTY);
}
Attach::~Attach()
diff --git a/libs/lxcpp/commands/prep-guest-terminal.cpp b/libs/lxcpp/commands/prep-guest-terminal.cpp
new file mode 100644
index 0000000..f496f86
--- /dev/null
+++ b/libs/lxcpp/commands/prep-guest-terminal.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Implementation of guest terminal preparation
+ */
+
+#include "lxcpp/commands/prep-guest-terminal.hpp"
+#include "lxcpp/terminal.hpp"
+
+#include "utils/fd-utils.hpp"
+#include "logger/logger.hpp"
+
+
+namespace lxcpp {
+
+
+PrepGuestTerminal::PrepGuestTerminal(TerminalsConfig &terminals)
+ : mTerminals(terminals)
+{
+}
+
+PrepGuestTerminal::~PrepGuestTerminal()
+{
+}
+
+void PrepGuestTerminal::execute()
+{
+ LOGD("Preparing " << mTerminals.count << " pseudoterminal(s) on the guest side.");
+
+ // TODO when /dev/ is already namespaced, create:
+ // /dev/pts/x (N times) (or mount devpts?)
+ // symlink /dev/console -> first PTY
+ // symlink /dev/ttyY -> /dev/pts/X (N times)
+ //for (int i = 0; i < mTerminals.count; ++i) {}
+
+ // Setup first PTY as a controlling terminal (/dev/console).
+ // This way simple programs in the container can work
+ // and we will be able to see the output of a container's init
+ // before the launch of getty processes.
+ int fd = utils::open(mTerminals.PTYs[0].ptsName,
+ O_RDWR | O_CLOEXEC | O_NOCTTY);
+ setupIOControlTTY(fd);
+
+}
+
+
+} // namespace lxcpp
diff --git a/libs/lxcpp/commands/prep-guest-terminal.hpp b/libs/lxcpp/commands/prep-guest-terminal.hpp
new file mode 100644
index 0000000..1086c3b
--- /dev/null
+++ b/libs/lxcpp/commands/prep-guest-terminal.hpp
@@ -0,0 +1,58 @@
+/*
+ * 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 Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+ * @brief Headers for guest terminal preparation
+ */
+
+#ifndef LXCPP_COMMANDS_PREP_GUEST_TERMINAL_HPP
+#define LXCPP_COMMANDS_PREP_GUEST_TERMINAL_HPP
+
+#include "lxcpp/commands/command.hpp"
+#include "lxcpp/terminal-config.hpp"
+
+
+namespace lxcpp {
+
+
+class PrepGuestTerminal final: Command {
+public:
+ /**
+ * Prepares the terminal on the guest side.
+ *
+ * It fills the /dev/ directory of a container with appropriate
+ * entries representing the created PTYs. It also takes already
+ * created PTYs and sets the first one as a controlling terminal.
+ *
+ * @param config container's config
+ */
+ PrepGuestTerminal(TerminalsConfig &config);
+ ~PrepGuestTerminal();
+
+ void execute();
+
+private:
+ TerminalsConfig &mTerminals;
+};
+
+
+} // namespace lxcpp
+
+
+#endif // LXCPP_COMMANDS_PREP_GUEST_TERMINAL_HPP
diff --git a/libs/lxcpp/commands/prep-host-terminal.cpp b/libs/lxcpp/commands/prep-host-terminal.cpp
index f219ff9..1dc4f3d 100644
--- a/libs/lxcpp/commands/prep-host-terminal.cpp
+++ b/libs/lxcpp/commands/prep-host-terminal.cpp
@@ -43,8 +43,7 @@ void PrepHostTerminal::execute()
{
LOGD("Creating " << mTerminals.count << " pseudoterminal(s) on the host side:");
- for (int i = 0; i < mTerminals.count; ++i)
- {
+ for (int i = 0; i < mTerminals.count; ++i) {
const auto pty = lxcpp::openPty(true);
LOGD(pty.second << " has been created");
mTerminals.PTYs.emplace_back(pty.first, pty.second);
diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp
index 715dad8..7b715f3 100644
--- a/libs/lxcpp/container-impl.cpp
+++ b/libs/lxcpp/container-impl.cpp
@@ -40,6 +40,34 @@
#include
#include
+#include
+#include
+#include
+#include
+
+
+namespace {
+
+// TODO: UGLY: REMOVEME:
+// It will be removed as soon as Container::console() will get implemented
+// I need it for now to know I didn't brake anything. It will be eradicated.
+void readTerminal(const lxcpp::TerminalConfig &term)
+{
+ char *buf = NULL;
+ size_t size = 0;
+ ssize_t ret;
+
+ printf("%s output:\n", term.ptsName.c_str());
+ usleep(10000);
+
+ FILE *fp = fdopen(term.masterFD.value, "r");
+ while((ret = getline(&buf, &size, fp)) != -1L) {
+ printf("%s", buf);
+ }
+ free(buf);
+}
+
+} // namespace
namespace lxcpp {
@@ -149,10 +177,16 @@ void ContainerImpl::start()
Start start(mConfig);
start.execute();
+
+ // TODO: UGLY: REMOVEME: read from 1st terminal
+ readTerminal(mConfig.mTerminals.PTYs[0]);
}
void ContainerImpl::stop()
{
+ // TODO: things to do when shuttting down the container:
+ // - close PTY master FDs from the config so we won't keep PTYs open
+
throw NotImplementedException();
}
diff --git a/libs/lxcpp/credentials.cpp b/libs/lxcpp/credentials.cpp
index 692be25..c127170 100644
--- a/libs/lxcpp/credentials.cpp
+++ b/libs/lxcpp/credentials.cpp
@@ -62,5 +62,17 @@ void setuid(const uid_t uid)
}
}
+pid_t setsid()
+{
+ pid_t pid = ::setsid();
+ if (pid == -1) {
+ const std::string msg = "setsid() failed: " +
+ utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw CredentialSetupException(msg);
+ }
+ return pid;
+}
+
} // namespace lxcpp
diff --git a/libs/lxcpp/credentials.hpp b/libs/lxcpp/credentials.hpp
index ab1a490..aa56aca 100644
--- a/libs/lxcpp/credentials.hpp
+++ b/libs/lxcpp/credentials.hpp
@@ -36,6 +36,8 @@ void setgid(const gid_t gid);
void setuid(const uid_t uid);
+pid_t setsid();
+
} // namespace lxcpp
-#endif // LXCPP_CREDENTIALS_HPP
\ No newline at end of file
+#endif // LXCPP_CREDENTIALS_HPP
diff --git a/libs/lxcpp/guard/guard.cpp b/libs/lxcpp/guard/guard.cpp
index 63c7263..952cdf5 100644
--- a/libs/lxcpp/guard/guard.cpp
+++ b/libs/lxcpp/guard/guard.cpp
@@ -24,6 +24,7 @@
#include "lxcpp/utils.hpp"
#include "lxcpp/guard/guard.hpp"
#include "lxcpp/process.hpp"
+#include "lxcpp/commands/prep-guest-terminal.hpp"
#include "config/manager.hpp"
#include "logger/logger.hpp"
@@ -80,6 +81,9 @@ int startGuard(int channelFD)
if (pid == 0) {
// TODO: container preparation part 2
+ PrepGuestTerminal terminals(cfg.mTerminals);
+ terminals.execute();
+
startContainer(cfg);
::_exit(EXIT_FAILURE);
}
diff --git a/libs/lxcpp/guard/main.cpp b/libs/lxcpp/guard/main.cpp
index 1065ecb..78c7476 100644
--- a/libs/lxcpp/guard/main.cpp
+++ b/libs/lxcpp/guard/main.cpp
@@ -35,18 +35,18 @@ int main(int argc, char *argv[])
::_exit(EXIT_FAILURE);
}
- int channel = std::stoi(argv[1]);
+ int channelFD = std::stoi(argv[1]);
// NOTE: this might not be required now, but I leave it here not to forget.
// We need to investigate this with vasum and think about possibility of
// poorly written software that leaks file descriptors and might use LXCPP.
#if 0
for(int fd = 3; fd < ::sysconf(_SC_OPEN_MAX); ++fd) {
- if (fd != channel) {
+ if (fd != channelFD) {
utils::close(fd);
}
}
#endif
- return lxcpp::startGuard(channel);
+ return lxcpp::startGuard(channelFD);
}
diff --git a/libs/lxcpp/process.cpp b/libs/lxcpp/process.cpp
index 96475d5..0353d82 100644
--- a/libs/lxcpp/process.cpp
+++ b/libs/lxcpp/process.cpp
@@ -79,13 +79,7 @@ pid_t clone(int (*function)(void *),
void setns(const pid_t pid, const std::vector& namespaces)
{
- int dirFD = ::open(getNsPath(pid).c_str(), O_DIRECTORY | O_CLOEXEC);
- if(dirFD < 0) {
- const std::string msg = "open() failed: " +
- utils::getSystemErrorMessage();
- LOGE(msg);
- throw ProcessSetupException(msg);
- }
+ int dirFD = utils::open(getNsPath(pid), O_DIRECTORY | O_CLOEXEC);
// Open FDs connected with the requested namespaces
std::vector fds(namespaces.size(), -1);
@@ -162,4 +156,4 @@ void unshare(const Namespace ns)
throw ProcessSetupException(msg);
}
}
-} // namespace lxcpp
\ No newline at end of file
+} // namespace lxcpp
diff --git a/libs/lxcpp/terminal.cpp b/libs/lxcpp/terminal.cpp
index ce77cd5..72c57af 100644
--- a/libs/lxcpp/terminal.cpp
+++ b/libs/lxcpp/terminal.cpp
@@ -22,6 +22,7 @@
*/
#include "lxcpp/exception.hpp"
+#include "lxcpp/credentials.hpp"
#include "logger/logger.hpp"
#include "utils/exception.hpp"
@@ -119,6 +120,37 @@ err:
return ret;
}
+bool isatty(int fd)
+{
+ int ret = ::isatty(fd);
+ if (ret) {
+ return true;
+ }
+ if (errno == EINVAL || errno == ENOTTY) {
+ return false;
+ }
+
+ const std::string msg = "isatty() failed: " + utils::getSystemErrorMessage();
+ LOGE(msg);
+ throw TerminalException(msg);
+}
+
+void setupIOControlTTY(const int ttyFD)
+{
+ if (!lxcpp::isatty(ttyFD)) {
+ const std::string msg = "setupIOControlTTY(): file descriptor passed is not a terminal";
+ LOGE(msg);
+ throw TerminalException(msg);
+ }
+
+ lxcpp::setsid();
+ utils::ioctl(ttyFD, TIOCSCTTY, NULL);
+
+ utils::dup2(ttyFD, STDIN_FILENO);
+ utils::dup2(ttyFD, STDOUT_FILENO);
+ utils::dup2(ttyFD, STDERR_FILENO);
+}
+
std::pair openPty(bool rawMode)
{
int master, slave;
diff --git a/libs/lxcpp/terminal.hpp b/libs/lxcpp/terminal.hpp
index 85ae6e2..421e4ce 100644
--- a/libs/lxcpp/terminal.hpp
+++ b/libs/lxcpp/terminal.hpp
@@ -40,6 +40,16 @@ namespace lxcpp {
int nullStdFDs();
/**
+ * Checks if a file descriptor is a terminal
+ */
+bool isatty(int fd);
+
+/**
+ * Setups the passed fd as a new control and IO (in, out, err) terminal
+ */
+void setupIOControlTTY(const int ttyFD);
+
+/**
* This function creates a new pair of virtual character devices
* using a pseudtoreminal interface. It also configures as much as it
* can so the devices are immediately usable.
--
2.7.4
From d59013e9bc3dd7060947f2cc2ff74fd03efa8fee Mon Sep 17 00:00:00 2001
From: Jan Olszak
Date: Thu, 17 Sep 2015 14:55:25 +0200
Subject: [PATCH 09/16] lxcpp: Attach process helper
[Feature] N/A
[Cause] Attach should work in multi-threaded programs
[Solution] Moved part of Attach implementation to a helper binary
[Verification] Build, install, run test
Change-Id: Ibdf5e0049ed41fdbbdb67a5f11de8aa415bdb1a5
---
libs/lxcpp/CMakeLists.txt | 9 +-
libs/lxcpp/attach/CMakeLists.txt | 37 +++++++
libs/lxcpp/attach/attach-config.hpp | 120 ++++++++++++++++++++++
libs/lxcpp/attach/attach-helper.cpp | 109 ++++++++++++++++++++
libs/lxcpp/attach/attach-helper.hpp | 51 ++++++++++
libs/lxcpp/attach/main.cpp | 63 ++++++++++++
libs/lxcpp/commands/attach.cpp | 195 ++++++------------------------------
libs/lxcpp/commands/attach.hpp | 36 ++-----
libs/lxcpp/config.hpp | 78 +++++++++++++++
libs/lxcpp/container-impl.cpp | 6 +-
libs/lxcpp/container-impl.hpp | 2 +-
libs/lxcpp/container.hpp | 4 +-
libs/lxcpp/utils.cpp | 64 ++++++++++++
libs/lxcpp/utils.hpp | 4 +
packaging/vasum.spec | 1 +
15 files changed, 581 insertions(+), 198 deletions(-)
create mode 100644 libs/lxcpp/attach/CMakeLists.txt
create mode 100644 libs/lxcpp/attach/attach-config.hpp
create mode 100644 libs/lxcpp/attach/attach-helper.cpp
create mode 100644 libs/lxcpp/attach/attach-helper.hpp
create mode 100644 libs/lxcpp/attach/main.cpp
create mode 100644 libs/lxcpp/config.hpp
diff --git a/libs/lxcpp/CMakeLists.txt b/libs/lxcpp/CMakeLists.txt
index d5e205b..9e49843 100644
--- a/libs/lxcpp/CMakeLists.txt
+++ b/libs/lxcpp/CMakeLists.txt
@@ -22,6 +22,9 @@ PROJECT(lxcpp)
SET(GUARD_CODENAME "${PROJECT_NAME}-guard")
ADD_SUBDIRECTORY(guard)
+SET(ATTACH_CODENAME "${PROJECT_NAME}-attach")
+ADD_SUBDIRECTORY(attach)
+
MESSAGE(STATUS "")
MESSAGE(STATUS "Generating makefile for the liblxcpp...")
FILE(GLOB HEADERS *.hpp)
@@ -40,7 +43,11 @@ ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_COMMANDS})
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
SOVERSION ${_LIB_SOVERSION_}
VERSION ${_LIB_VERSION_}
- COMPILE_DEFINITIONS GUARD_PATH="${LIBEXEC_DIR}/${GUARD_CODENAME}"
+)
+
+TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME}
+ PRIVATE GUARD_PATH="${LIBEXEC_DIR}/${GUARD_CODENAME}"
+ PRIVATE ATTACH_PATH="${LIBEXEC_DIR}/${ATTACH_CODENAME}"
)
ADD_DEPENDENCIES(${PROJECT_NAME} Common Logger)
diff --git a/libs/lxcpp/attach/CMakeLists.txt b/libs/lxcpp/attach/CMakeLists.txt
new file mode 100644
index 0000000..cdd40ca
--- /dev/null
+++ b/libs/lxcpp/attach/CMakeLists.txt
@@ -0,0 +1,37 @@
+# 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 CMakeLists.txt
+# @author Jan Olszak (j.olszak@samsung.com)
+#
+
+MESSAGE(STATUS "")
+MESSAGE(STATUS "Generating makefile for the Attach...")
+FILE(GLOB attach_SRCS *.cpp *.hpp)
+
+
+## Setup target ################################################################
+ADD_EXECUTABLE(${ATTACH_CODENAME} ${attach_SRCS})
+
+
+## Link libraries ##############################################################
+PKG_CHECK_MODULES(ATTACH_DEPS REQUIRED glib-2.0)
+INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER})
+INCLUDE_DIRECTORIES(SYSTEM ${ATTACH_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS})
+TARGET_LINK_LIBRARIES(${ATTACH_CODENAME} Common lxcpp Config)
+
+
+## Install #####################################################################
+INSTALL(TARGETS ${ATTACH_CODENAME} DESTINATION ${LIBEXEC_DIR})
diff --git a/libs/lxcpp/attach/attach-config.hpp b/libs/lxcpp/attach/attach-config.hpp
new file mode 100644
index 0000000..9788abe
--- /dev/null
+++ b/libs/lxcpp/attach/attach-config.hpp
@@ -0,0 +1,120 @@
+/*
+ * 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 Internal structure sent between Attach command and AttachHelper
+ */
+
+#ifndef LXCPP_ATTACH_ATTACH_CONFIG_HPP
+#define LXCPP_ATTACH_ATTACH_CONFIG_HPP
+
+#include "lxcpp/namespace.hpp"
+
+#include
+#include
+
+#include
+
+#include
+#include
+
+namespace lxcpp {
+
+struct AttachConfig {
+
+ /// Arguments passed by user, argv[0] is the binary's path in container
+ std::vector argv;
+
+ /// PID of the container's init process
+ pid_t initPid;
+
+ /// Namespaces to which we'll attach
+ std::vector namespaces;
+
+ /// User ID to set
+ uid_t uid;
+
+ /// Group ID to set
+ gid_t gid;
+
+ /// PTS that will become the control terminal for the attached process
+ int ttyFD;
+
+ /// Supplementary groups to set
+ std::vector supplementaryGids;
+
+ /// Mask of capabilities that will be available
+ int capsToKeep;
+
+ /// Work directory for the attached process
+ std::string workDirInContainer;
+
+ /// Environment variables that will be kept
+ std::vector envToKeep;
+
+ /// Environment variables that will be set/updated for the attached process
+ std::vector> envToSet;
+
+ AttachConfig() = default;
+
+ AttachConfig(const std::vector& argv,
+ const pid_t initPid,
+ const std::vector& namespaces,
+ const uid_t uid,
+ const gid_t gid,
+ const std::vector& supplementaryGids,
+ const int capsToKeep,
+ const std::string& workDirInContainer,
+ const std::vector& envToKeep,
+ const std::vector>& envToSet)
+ : argv(argv),
+ initPid(initPid),
+ namespaces(namespaces),
+ uid(uid),
+ gid(gid),
+ ttyFD(-1),
+ supplementaryGids(supplementaryGids),
+ capsToKeep(capsToKeep),
+ workDirInContainer(workDirInContainer),
+ envToKeep(envToKeep),
+ envToSet(envToSet)
+ {}
+
+ CONFIG_REGISTER
+ (
+ //TODO: Uncomment and fix cstring serialization
+ // argv,
+ initPid,
+ //TODO: Uncomment and fix Namespace serialization (or remove Namespace)
+ // namespaces,
+ uid,
+ gid,
+ ttyFD,
+ supplementaryGids,
+ capsToKeep,
+ workDirInContainer,
+ envToKeep
+ //TODO: Uncomment and fix std::pair serialization
+ // envToSet
+ )
+};
+
+} // namespace lxcpp
+
+#endif // LXCPP_ATTACH_ATTACH_CONFIG_HPP
\ No newline at end of file
diff --git a/libs/lxcpp/attach/attach-helper.cpp b/libs/lxcpp/attach/attach-helper.cpp
new file mode 100644
index 0000000..321502f
--- /dev/null
+++ b/libs/lxcpp/attach/attach-helper.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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 Implementation of attaching to a container
+ */
+
+#include "lxcpp/attach/attach-helper.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 "lxcpp/credentials.hpp"
+#include "lxcpp/utils.hpp"
+
+#include "utils/exception.hpp"
+#include "utils/fd-utils.hpp"
+#include "logger/logger.hpp"
+#include "config/manager.hpp"
+
+#include
+#include
+#include
+
+#include
+
+namespace lxcpp {
+
+namespace {
+
+int child(void* data)
+{
+ AttachConfig& config = *static_cast(data);
+
+ // Setup /proc /sys mount
+ setupMountPoints();
+
+ // Setup capabilities
+ dropCapsFromBoundingExcept(config.capsToKeep);
+
+ // Setup environment variables
+ clearenvExcept(config.envToKeep);
+ setenv(config.envToSet);
+
+ // Set uid/gids
+ lxcpp::setgid(config.gid);
+ setgroups(config.supplementaryGids);
+ lxcpp::setuid(config.uid);
+
+ // Set control TTY
+ if(!setupControlTTY(config.ttyFD)) {
+ ::_exit(EXIT_FAILURE);
+ }
+
+ // Run user's binary
+ ::execve(config.argv[0], const_cast(config.argv.data()), nullptr);
+ return EXIT_FAILURE;
+}
+
+} // namespace
+
+AttachHelper::AttachHelper(const int channelFD)
+ : mChannel(channelFD)
+{
+ mChannel.setCloseOnExec(true);
+ config::loadFromFD(mChannel.getFD(), mConfig);
+}
+
+AttachHelper::~AttachHelper()
+{
+ utils::close(mConfig.ttyFD);
+}
+
+void AttachHelper::execute()
+{
+ // Move to the right namespaces
+ lxcpp::setns(mConfig.initPid, mConfig.namespaces);
+
+ // Change the current work directory
+ // workDirInContainer is a path relative to the container's root
+ lxcpp::chdir(mConfig.workDirInContainer);
+
+ // Unsharing PID namespace won't affect the returned childPid
+ // CLONE_PARENT: Child's PPID == Caller's PID
+ const pid_t childPid = lxcpp::clone(child,
+ &mConfig,
+ CLONE_PARENT);
+ mChannel.write(childPid);
+}
+
+} // namespace lxcpp
diff --git a/libs/lxcpp/attach/attach-helper.hpp b/libs/lxcpp/attach/attach-helper.hpp
new file mode 100644
index 0000000..5362a0c
--- /dev/null
+++ b/libs/lxcpp/attach/attach-helper.hpp
@@ -0,0 +1,51 @@
+/*
+ * 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 Implementation of attaching to a container
+ */
+
+#ifndef LXCPP_ATTACH_ATTACH_HELPER_HPP
+#define LXCPP_ATTACH_ATTACH_HELPER_HPP
+
+#include "lxcpp/attach/attach-config.hpp"
+
+#include "utils/channel.hpp"
+
+namespace lxcpp {
+
+/**
+ * Implementation of the Intermediate helper process.
+ * @see Attach
+ */
+class AttachHelper {
+public:
+ AttachHelper(const int channelFD);
+ ~AttachHelper();
+
+ void execute();
+
+private:
+ utils::Channel mChannel;
+ AttachConfig mConfig;
+};
+
+} // namespace lxcpp
+
+#endif // LXCPP_ATTACH_ATTACH_HELPER_HPP
\ No newline at end of file
diff --git a/libs/lxcpp/attach/main.cpp b/libs/lxcpp/attach/main.cpp
new file mode 100644
index 0000000..d5924ec
--- /dev/null
+++ b/libs/lxcpp/attach/main.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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 Main file for the Intermediate process (libexec)
+ */
+
+#include "lxcpp/attach/attach-helper.hpp"
+
+#include "utils/fd-utils.hpp"
+#include "utils/typeinfo.hpp"
+
+// TODO: Implement passing logger configuration and uncomment this.
+// #include "logger/logger.hpp"
+
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ if (argc == 1) {
+ std::cout << "This file should not be executed by hand" << std::endl;
+ ::_exit(EXIT_FAILURE);
+ }
+
+ // NOTE: this might not be required now, but I leave it here not to forget.
+ // We need to investigate this with vasum and think about possibility of
+ // poorly written software that leaks file descriptors and might use LXCPP.
+#if 0
+ for(int fd = 3; fd < ::sysconf(_SC_OPEN_MAX); ++fd) {
+ if(fd != std::stoi(argv[1])) {
+ utils::close(fd);
+ }
+ }
+#endif
+
+ try {
+ int fd = std::stoi(argv[1]);
+ lxcpp::AttachHelper attachHelper(fd);
+ attachHelper.execute();
+ return EXIT_SUCCESS;
+ } catch(std::exception& e) {
+ // TODO: Implement passing logger configuration and uncomment this.
+ // LOGE("Unexpected: " << utils::getTypeName(e) << ": " << e.what());
+ return EXIT_FAILURE;
+ }
+}
diff --git a/libs/lxcpp/commands/attach.cpp b/libs/lxcpp/commands/attach.cpp
index e1bdfef..2bfa592 100644
--- a/libs/lxcpp/commands/attach.cpp
+++ b/libs/lxcpp/commands/attach.cpp
@@ -24,96 +24,17 @@
#include "lxcpp/commands/attach.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 "lxcpp/credentials.hpp"
#include "utils/exception.hpp"
#include "utils/fd-utils.hpp"
#include "logger/logger.hpp"
#include
-#include
-#include
-#include
-
-#include
namespace lxcpp {
-namespace {
-
-void setupMountPoints()
-{
- /* TODO: Uncomment when preparing the final attach() version
-
- // TODO: This unshare should be optional only if we attach to PID/NET namespace, but not MNT.
- // Otherwise container already has remounted /proc /sys
- lxcpp::unshare(Namespace::MNT);
-
- if (isMountPointShared("/")) {
- // TODO: Handle case when the container rootfs or mount location is MS_SHARED, but not '/'
- lxcpp::mount(nullptr, "/", nullptr, MS_SLAVE | MS_REC, nullptr);
- }
-
- if(isMountPoint("/proc")) {
- lxcpp::umount("/proc", MNT_DETACH);
- lxcpp::mount("none", "/proc", "proc", 0, nullptr);
- }
-
- if(isMountPoint("/sys")) {
- lxcpp::umount("/sys", MNT_DETACH);
- lxcpp::mount("none", "/sys", "sysfs", 0, nullptr);
- }
-
- */
-}
-
-bool setupControlTTY(const int ttyFD)
-{
- if (!::isatty(ttyFD)) {
- return false;
- }
-
- if (::setsid() < 0) {
- return false;
- }
-
- if (::ioctl(ttyFD, TIOCSCTTY, NULL) < 0) {
- return false;
- }
-
- if (::dup2(ttyFD, STDIN_FILENO) < 0) {
- return false;
- }
-
- if (::dup2(ttyFD, STDOUT_FILENO) < 0) {
- return false;
- }
-
- if (::dup2(ttyFD, STDERR_FILENO) < 0) {
- return false;
- }
-
- return true;
-}
-
-int execFunction(void* call)
-{
- try {
- return (*static_cast(call))();
- } catch(...) {
- return -1; // Non-zero on failure
- }
- return 0; // Success
-}
-
-} // namespace
-
-Attach::Attach(lxcpp::ContainerImpl& container,
- Container::AttachCall& userCall,
+Attach::Attach(const lxcpp::ContainerImpl& container,
+ const std::vector& argv,
const uid_t uid,
const gid_t gid,
const std::string& ttyPath,
@@ -122,112 +43,62 @@ Attach::Attach(lxcpp::ContainerImpl& container,
const std::string& workDirInContainer,
const std::vector& envToKeep,
const std::vector>& envToSet)
- : mContainer(container),
- mUserCall(userCall),
- mUid(uid),
- mGid(gid),
- mSupplementaryGids(supplementaryGids),
- mCapsToKeep(capsToKeep),
- mWorkDirInContainer(workDirInContainer),
- mEnvToKeep(envToKeep),
- mEnvToSet(envToSet)
+ : mIntermChannel(false),
+ mConfig(argv,
+ container.getInitPid(),
+ container.getNamespaces(),
+ uid,
+ gid,
+ supplementaryGids,
+ capsToKeep,
+ workDirInContainer,
+ envToKeep,
+ envToSet)
{
- mTTYFD = utils::open(ttyPath, O_RDWR | O_NOCTTY);
+ // Set TTY
+ if (ttyPath.empty()) {
+ mConfig.ttyFD = -1;
+ } else {
+ mConfig.ttyFD = utils::open(ttyPath, O_RDWR | O_NOCTTY);
+ }
}
Attach::~Attach()
{
- utils::close(mTTYFD);
+ utils::close(mConfig.ttyFD);
}
void Attach::execute()
{
- // Channels for setup synchronization
- utils::Channel intermChannel;
-
- Call call = std::bind(&Attach::child,
- mUserCall,
- mUid,
- mGid,
- mTTYFD,
- mSupplementaryGids,
- mCapsToKeep,
- mEnvToKeep,
- mEnvToSet);
+ // Channels for passing configuration and synchronization
+ const std::string mIntermChannelFDStr = std::to_string(mIntermChannel.getRightFD());
const pid_t interPid = lxcpp::fork();
if (interPid > 0) {
- intermChannel.setLeft();
- parent(intermChannel, interPid);
- intermChannel.shutdown();
- } else {
- // TODO: only safe functions mentioned in signal(7) should be used below.
- // This is not the case now, needs fixing.
- intermChannel.setRight();
- interm(intermChannel, call);
- intermChannel.shutdown();
- ::_exit(EXIT_SUCCESS);
- }
-}
-
-int Attach::child(const Container::AttachCall& call,
- const uid_t uid,
- const gid_t gid,
- const int ttyFD,
- const std::vector& supplementaryGids,
- const int capsToKeep,
- const std::vector& envToKeep,
- const std::vector>& envToSet)
-{
- // Setup /proc /sys mount
- setupMountPoints();
+ mIntermChannel.setLeft();
- // Setup capabilities
- dropCapsFromBoundingExcept(capsToKeep);
+ parent(interPid);
- // Setup environment variables
- clearenvExcept(envToKeep);
- setenv(envToSet);
-
- // Set uid/gids
- lxcpp::setgid(gid);
- setgroups(supplementaryGids);
-
- lxcpp::setuid(uid);
+ } else {
+ mIntermChannel.setRight();
- // Set control TTY
- if(!setupControlTTY(ttyFD)) {
+ const char *argv[] = {ATTACH_PATH,
+ mIntermChannelFDStr.c_str(),
+ NULL
+ };
+ ::execve(argv[0], const_cast(argv), nullptr);
::_exit(EXIT_FAILURE);
}
-
- // Run user's code
- return call();
}
-void Attach::parent(utils::Channel& intermChannel, const pid_t interPid)
+void Attach::parent(const pid_t interPid)
{
// TODO: Setup cgroups etc
- const pid_t childPid = intermChannel.read();
+ const pid_t childPid = mIntermChannel.read();
// Wait for all processes
lxcpp::waitpid(interPid);
lxcpp::waitpid(childPid);
}
-void Attach::interm(utils::Channel& intermChannel, Call& call)
-{
- lxcpp::setns(mContainer.getInitPid(), mContainer.getNamespaces());
-
- // Change the current work directory
- // workDirInContainer is a path relative to the container's root
- lxcpp::chdir(mWorkDirInContainer);
-
- // PID namespace won't affect the returned pid
- // CLONE_PARENT: Child's PPID == Caller's PID
- const pid_t childPid = lxcpp::clone(execFunction,
- &call,
- CLONE_PARENT);
- intermChannel.write(childPid);
-}
-
} // namespace lxcpp
diff --git a/libs/lxcpp/commands/attach.hpp b/libs/lxcpp/commands/attach.hpp
index 2c1f365..ce39b83 100644
--- a/libs/lxcpp/commands/attach.hpp
+++ b/libs/lxcpp/commands/attach.hpp
@@ -25,6 +25,7 @@
#define LXCPP_COMMANDS_ATTACH_HPP
#include "lxcpp/commands/command.hpp"
+#include "lxcpp/attach/attach-config.hpp"
#include "lxcpp/container-impl.hpp"
#include "utils/channel.hpp"
@@ -36,7 +37,6 @@ namespace lxcpp {
class Attach final: Command {
public:
- typedef std::function Call;
/**
* Runs call in the container's context
@@ -45,17 +45,18 @@ public:
* It will not be stored for future use like most other commands.
*
* @param container container to which it attaches
- * @param userCall user's function to run
+ * @param argv path and arguments for the user's executable
* @param uid uid in the container
* @param gid gid in the container
+ * @param ttyPath path of the TTY in the host
* @param supplementaryGids supplementary groups in container
* @param capsToKeep capabilities that will be kept
* @param workDirInContainer work directory set for the new process
* @param envToKeep environment variables that will be kept
* @param envToSet new environment variables that will be set
*/
- Attach(lxcpp::ContainerImpl& container,
- Container::AttachCall& userCall,
+ Attach(const lxcpp::ContainerImpl& container,
+ const std::vector& argv,
const uid_t uid,
const gid_t gid,
const std::string& ttyPath,
@@ -69,32 +70,11 @@ public:
void execute();
private:
- const lxcpp::ContainerImpl& mContainer;
- const Container::AttachCall& mUserCall;
- const uid_t mUid;
- const gid_t mGid;
- int mTTYFD;
- const std::vector& mSupplementaryGids;
- const int mCapsToKeep;
- const std::string& mWorkDirInContainer;
- const std::vector& mEnvToKeep;
- const std::vector>& mEnvToSet;
+ utils::Channel mIntermChannel;
+ AttachConfig mConfig;
- // Methods for different stages of setting up the attachment
- static int child(const Container::AttachCall& call,
- const uid_t uid,
- const gid_t gid,
- const int ttyFD,
- const std::vector& supplementaryGids,
- const int capsToKeep,
- const std::vector& envToKeep,
- const std::vector>& envToSet);
+ void parent(const pid_t pid);
- void parent(utils::Channel& intermChannel,
- const pid_t pid);
-
- void interm(utils::Channel& intermChannel,
- Call& call);
};
} // namespace lxcpp
diff --git a/libs/lxcpp/config.hpp b/libs/lxcpp/config.hpp
new file mode 100644
index 0000000..753430e
--- /dev/null
+++ b/libs/lxcpp/config.hpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Lukasz Pawelczyk (l.pawelczyk@partner.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 Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com)
+ * @brief Configuration file for the code
+ */
+
+
+#ifndef COMMON_CONFIG_HPP
+#define COMMON_CONFIG_HPP
+
+
+#ifdef __clang__
+#define CLANG_VERSION (__clang__major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
+#endif // __clang__
+
+#if defined __GNUC__ && !defined __clang__ // clang also defines GCC versions
+#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#endif // __GNUC__
+
+
+#ifdef GCC_VERSION
+
+#if GCC_VERSION < 40800
+// GCC 4.8 is the first where those defines are not required for
+// std::this_thread::sleep_for() and ::yield(). They might exist though
+// in previous versions depending on the build configuration of the GCC.
+#ifndef _GLIBCXX_USE_NANOSLEEP
+#define _GLIBCXX_USE_NANOSLEEP
+#endif // _GLIBCXX_USE_NANOSLEEP
+#ifndef _GLIBCXX_USE_SCHED_YIELD
+#define _GLIBCXX_USE_SCHED_YIELD
+#endif // _GLIBCXX_USE_SCHED_YIELD
+#endif // GCC_VERSION < 40800
+
+#if GCC_VERSION < 40700
+// Those appeared in 4.7 with full c++11 support
+#define final
+#define override
+#define thread_local __thread // use GCC extension instead of C++11
+#define steady_clock monotonic_clock
+#endif // GCC_VERSION < 40700
+
+#endif // GCC_VERSION
+
+// Variadic macros support for boost preprocessor should be enabled
+// manually for clang since they are marked as untested feature
+// (boost trunk if fixed but the latest 1.55 version is not,
+// see boost/preprocessor/config/config.hpp)
+#ifdef __clang__
+#define BOOST_PP_VARIADICS 1
+#endif
+
+// This has to be defined always when the boost has not been compiled
+// using C++11. Headers detect that you are compiling using C++11 and
+// blindly and wrongly assume that boost has been as well.
+#ifndef BOOST_NO_CXX11_SCOPED_ENUMS
+#define BOOST_NO_CXX11_SCOPED_ENUMS 1
+#endif
+
+#endif // COMMON_CONFIG_HPP
diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp
index 7b715f3..5301cb5 100644
--- a/libs/lxcpp/container-impl.cpp
+++ b/libs/lxcpp/container-impl.cpp
@@ -205,11 +205,11 @@ void ContainerImpl::reboot()
throw NotImplementedException();
}
-void ContainerImpl::attach(Container::AttachCall& call,
+void ContainerImpl::attach(const std::vector& argv,
const std::string& cwdInContainer)
{
Attach attach(*this,
- call,
+ argv,
/*uid in container*/ 0,
/*gid in container*/ 0,
"/dev/tty",
@@ -217,7 +217,7 @@ void ContainerImpl::attach(Container::AttachCall& call,
/*capsToKeep*/ 0,
cwdInContainer,
/*envToKeep*/ {},
- /*envInContainer*/ {{"container","lxcpp"}});
+ /*envInContainer*/ {{"container","lxcpp"}});
// TODO: Env variables should agree with the ones already in the container
attach.execute();
}
diff --git a/libs/lxcpp/container-impl.hpp b/libs/lxcpp/container-impl.hpp
index 97b9155..b0786a1 100644
--- a/libs/lxcpp/container-impl.hpp
+++ b/libs/lxcpp/container-impl.hpp
@@ -66,7 +66,7 @@ public:
void reboot();
// Other
- void attach(Container::AttachCall& attachCall,
+ void attach(const std::vector& argv,
const std::string& cwdInContainer);
// Network interfaces setup/config
diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp
index bf10a76..96af842 100644
--- a/libs/lxcpp/container.hpp
+++ b/libs/lxcpp/container.hpp
@@ -45,8 +45,6 @@ struct NetworkInterfaceInfo {
class Container {
public:
- typedef std::function AttachCall;
-
virtual ~Container() {};
// Configuration
@@ -73,7 +71,7 @@ public:
virtual void reboot() = 0;
// Other
- virtual void attach(AttachCall& attachCall,
+ virtual void attach(const std::vector& argv,
const std::string& cwdInContainer) = 0;
// Network interfaces setup/config
diff --git a/libs/lxcpp/utils.cpp b/libs/lxcpp/utils.cpp
index 685d915..0c731b5 100644
--- a/libs/lxcpp/utils.cpp
+++ b/libs/lxcpp/utils.cpp
@@ -26,6 +26,9 @@
#endif
#include "lxcpp/exception.hpp"
+#include "lxcpp/namespace.hpp"
+#include "lxcpp/filesystem.hpp"
+#include "lxcpp/process.hpp"
#include "logger/logger.hpp"
#include "utils/fd-utils.hpp"
@@ -35,7 +38,10 @@
#include
#include
#include
+
#include
+#include
+#include
namespace lxcpp {
@@ -82,5 +88,63 @@ void setProcTitle(const std::string &title)
::strcpy(mem, title.c_str());
}
+void setupMountPoints()
+{
+#if 0
+ // TODO: This unshare should be optional only if we attach to PID/NET namespace, but not MNT.
+ // Otherwise container already has remounted /proc /sys
+ lxcpp::unshare(Namespace::MNT);
+
+ if (isMountPointShared("/")) {
+ // TODO: Handle case when the container rootfs or mount location is MS_SHARED, but not '/'
+ lxcpp::mount(nullptr, "/", nullptr, MS_SLAVE | MS_REC, nullptr);
+ }
+
+ if(isMountPoint("/proc")) {
+ lxcpp::umount("/proc", MNT_DETACH);
+ lxcpp::mount("none", "/proc", "proc", 0, nullptr);
+ }
+
+ if(isMountPoint("/sys")) {
+ lxcpp::umount("/sys", MNT_DETACH);
+ lxcpp::mount("none", "/sys", "sysfs", 0, nullptr);
+ }
+#endif
+}
+
+bool setupControlTTY(const int ttyFD)
+{
+ if (ttyFD != -1) {
+ return true;
+ }
+
+ if (!::isatty(ttyFD)) {
+ return false;
+ }
+
+ if (::setsid() < 0) {
+ return false;
+ }
+
+ if (::ioctl(ttyFD, TIOCSCTTY, NULL) < 0) {
+ return false;
+ }
+
+ if (::dup2(ttyFD, STDIN_FILENO) < 0) {
+ return false;
+ }
+
+ if (::dup2(ttyFD, STDOUT_FILENO) < 0) {
+ return false;
+ }
+
+ if (::dup2(ttyFD, STDERR_FILENO) < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+
} // namespace lxcpp
diff --git a/libs/lxcpp/utils.hpp b/libs/lxcpp/utils.hpp
index e4c158b..c4d469b 100644
--- a/libs/lxcpp/utils.hpp
+++ b/libs/lxcpp/utils.hpp
@@ -37,6 +37,10 @@ namespace lxcpp {
*/
void setProcTitle(const std::string &title);
+void setupMountPoints();
+
+bool setupControlTTY(const int ttyFD);
+
} // namespace lxcpp
diff --git a/packaging/vasum.spec b/packaging/vasum.spec
index 7709ab4..546c782 100644
--- a/packaging/vasum.spec
+++ b/packaging/vasum.spec
@@ -488,6 +488,7 @@ The package provides liblxcpp library.
%defattr(644,root,root,755)
%{_libdir}/liblxcpp.so.0
%attr(755,root,root) %{_libexecdir}/lxcpp-guard
+%attr(755,root,root) %{_libexecdir}/lxcpp-attach
%attr(755,root,root) %{_libdir}/liblxcpp.so.%{version}
%package -n liblxcpp-devel
--
2.7.4
From 4753f1ecfcb0cd625156b57f9212050225eb68c0 Mon Sep 17 00:00:00 2001
From: Krzysztof Dynowski
Date: Wed, 23 Sep 2015 10:54:20 +0200
Subject: [PATCH 10/16] hotfix: expression always true, use ::ioctl
[Feature/Bug] mistake in assert check
[Cause] compilation error, testcase failure
[Solution] N/A
[Verification] Build and run tests
Change-Id: Ia9696593c5641a8cc5a2a8b2dc3a9c023609d864
---
common/utils/fd-utils.cpp | 2 +-
server/input-monitor.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/common/utils/fd-utils.cpp b/common/utils/fd-utils.cpp
index 9bd7d29..08603fa 100644
--- a/common/utils/fd-utils.cpp
+++ b/common/utils/fd-utils.cpp
@@ -126,7 +126,7 @@ void setFDFlag(const int fd, const int getOp, const int setOp, const int flag, c
int open(const std::string &path, int flags, mode_t mode)
{
- assert(!(flags & O_CREAT || flags & O_TMPFILE) || mode >= 0);
+ assert(!(flags & O_CREAT || flags & O_TMPFILE) || mode != static_cast(-1));
int fd;
diff --git a/server/input-monitor.cpp b/server/input-monitor.cpp
index 45982af..5ac6e68 100644
--- a/server/input-monitor.cpp
+++ b/server/input-monitor.cpp
@@ -131,7 +131,7 @@ bool isDeviceWithName(const boost::regex& deviceNameRegex,
}
char name[DEVICE_NAME_LENGTH];
- if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
+ if (::ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
LOGD("Failed to get the device name of: " << path);
if (::close(fd) < 0) {
LOGE("Error during closing file " << path);
--
2.7.4
From 19b4d6c1e2ed32f0355a8cef0d94519f298d5015 Mon Sep 17 00:00:00 2001
From: Krzysztof Dynowski
Date: Wed, 23 Sep 2015 10:54:20 +0200
Subject: [PATCH 11/16] hotfix2: assert condition
[Feature/Bug] wrong assert condition
[Cause] testcase failure
[Solution] N/A
[Verification] Build and run tests
Change-Id: I2ad2e674205fbc927cb85251c0cbe037bca039fb
---
common/utils/fd-utils.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/utils/fd-utils.cpp b/common/utils/fd-utils.cpp
index 08603fa..08c52fe 100644
--- a/common/utils/fd-utils.cpp
+++ b/common/utils/fd-utils.cpp
@@ -126,7 +126,7 @@ void setFDFlag(const int fd, const int getOp, const int setOp, const int flag, c
int open(const std::string &path, int flags, mode_t mode)
{
- assert(!(flags & O_CREAT || flags & O_TMPFILE) || mode != static_cast(-1));
+ assert(!((flags & O_CREAT) == O_CREAT || (flags & O_TMPFILE) == O_TMPFILE) || mode != static_cast(-1));
int fd;
--
2.7.4
From 583de1c43bd062edc5db45905f1c10de9de829be Mon Sep 17 00:00:00 2001
From: Pawel Kubik
Date: Fri, 25 Sep 2015 14:48:50 +0200
Subject: [PATCH 12/16] Improved coverage report instructions.
[Feature] More detailed per-file coverage report instructions.
[Cause] N/A
[Solution] N/A
[Verification] Follow new instructions.
Change-Id: I75c563e8627f2f2e5aa22329e231f18fc4f1841a
---
doc/coverage_report.md | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/doc/coverage_report.md b/doc/coverage_report.md
index cb9ef8e..4fb5cbe 100644
--- a/doc/coverage_report.md
+++ b/doc/coverage_report.md
@@ -14,8 +14,11 @@ Requirements
Instructions
------------
-All command should be run from within your build directory. **repodir** is a
-path to your repository root.
+All command should be run from within your build directory. Replace following expressions:
+ - **repodir** - with a path to your repository root.
+ - **covdir** - with a path you'd like to place your coverage report
+
+-------------------------------------------------------------------------------
1. Generate your build using CCOV profile
```bash
@@ -33,8 +36,8 @@ sudo vsm_all_tests.py
3. Generate HTML report
```bash
-gcovr -e tests -s -v -r repodir --html -o coverage.html
+gcovr -e tests -s -v -r repodir --html --html-details -o covdir/index.html
```
-4. Coverage report consists of single page **coverage.html**. Find it in your
- build directory and open in a web browser.
+4. Open *index.html* in a web browser to see generated documentation. Click on any source file
+ to see line coverage visualization.
--
2.7.4
From d1d008881304e7b310ead5968fee2e1dd4783789 Mon Sep 17 00:00:00 2001
From: Pawel Kubik
Date: Fri, 25 Sep 2015 14:10:29 +0200
Subject: [PATCH 13/16] Fixed dbus testing container configuration.
[Feature] Fix
[Cause] Zone stopped immediately after start.
[Solution] Added sleep-loop to prevent zone from stopping.
[Verification] Build (best under CCOV config), install, run:
sudo vsm_launch_test.py vasum-server-unit-tests \
-t 'ZoneSuite/DbusConnection'
Change-Id: I1ffc9eb047f08173314c16c60ef505f0d81c11c6
---
tests/unit_tests/configs/templates/console-dbus.conf.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/unit_tests/configs/templates/console-dbus.conf.in b/tests/unit_tests/configs/templates/console-dbus.conf.in
index 2dee28b..8ab8b98 100644
--- a/tests/unit_tests/configs/templates/console-dbus.conf.in
+++ b/tests/unit_tests/configs/templates/console-dbus.conf.in
@@ -1,6 +1,6 @@
{
"zoneTemplate" : "minimal.sh",
- "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; /bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/dbus/ut-dbus-system.conf --fork"],
+ "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; /bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/dbus/ut-dbus-system.conf --fork; while true; do sleep 0.1; done"],
"requestedState" : "running",
"ipv4Gateway" : "",
"ipv4" : "",
--
2.7.4
From 9aebe3b497f5c36681afb0334c8d4595638ca42e Mon Sep 17 00:00:00 2001
From: Krzysztof Dynowski
Date: Thu, 3 Sep 2015 09:34:37 +0200
Subject: [PATCH 14/16] lxcpp: network implementation (part 2)
[Feature] Network implementation for lxcpp (create/destroy, add/del ip addr)
[Cause] N/A
[Solution] N/A
[Verification] Build, install, run tests
Change-Id: I1286efb4893b9b77bebf20f0e40b9fd06611e48b
---
common/netlink/netlink-message.hpp | 1 +
common/netlink/netlink.hpp | 1 +
libs/config/CMakeLists.txt | 2 +-
libs/lxcpp/commands/netcreate.cpp | 45 ++-
libs/lxcpp/commands/netcreate.hpp | 75 ++++-
libs/lxcpp/container-impl.cpp | 47 +--
libs/lxcpp/container-impl.hpp | 7 +-
libs/lxcpp/container.hpp | 6 +-
libs/lxcpp/network-config.cpp | 50 +++-
libs/lxcpp/network-config.hpp | 143 ++++-----
libs/lxcpp/network.cpp | 532 ++++++++++++++++++++--------------
libs/lxcpp/network.hpp | 268 +++++++++++++++--
tests/unit_tests/lxcpp/ut-network.cpp | 129 +++++++--
tests/unit_tests/server/ut-zone.cpp | 2 -
14 files changed, 912 insertions(+), 396 deletions(-)
diff --git a/common/netlink/netlink-message.hpp b/common/netlink/netlink-message.hpp
index 73e6a4c..3ee729b 100644
--- a/common/netlink/netlink-message.hpp
+++ b/common/netlink/netlink-message.hpp
@@ -35,6 +35,7 @@
#include
#include
+//FIXME remove from namespace vasum
namespace vasum {
namespace netlink {
diff --git a/common/netlink/netlink.hpp b/common/netlink/netlink.hpp
index 8d33957..56eff0b 100644
--- a/common/netlink/netlink.hpp
+++ b/common/netlink/netlink.hpp
@@ -28,6 +28,7 @@
#include