From c0c76a68a17ee4a7137a8f516087c8389a3eba07 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Wed, 2 Sep 2015 17:04:45 +0200 Subject: [PATCH 01/16] lxcpp: Command implementation [Feature] Base class for commands Attach command [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: Id9ed43c145704f5d9d21f1aa210694fed1615c57 --- .../commands/{attach-manager.cpp => attach.cpp} | 55 ++++++++++++---------- .../commands/{attach-manager.hpp => attach.hpp} | 51 +++++++++++--------- libs/lxcpp/commands/command.hpp | 36 ++++++++++++++ libs/lxcpp/container-impl.cpp | 15 +++--- 4 files changed, 103 insertions(+), 54 deletions(-) rename libs/lxcpp/commands/{attach-manager.cpp => attach.cpp} (71%) rename libs/lxcpp/commands/{attach-manager.hpp => attach.hpp} (54%) create mode 100644 libs/lxcpp/commands/command.hpp diff --git a/libs/lxcpp/commands/attach-manager.cpp b/libs/lxcpp/commands/attach.cpp similarity index 71% rename from libs/lxcpp/commands/attach-manager.cpp rename to libs/lxcpp/commands/attach.cpp index 1a274d3..98a4599 100644 --- a/libs/lxcpp/commands/attach-manager.cpp +++ b/libs/lxcpp/commands/attach.cpp @@ -21,7 +21,7 @@ * @brief Implementation of attaching to a container */ -#include "lxcpp/commands/attach-manager.hpp" +#include "lxcpp/commands/attach.hpp" #include "lxcpp/exception.hpp" #include "lxcpp/process.hpp" #include "lxcpp/filesystem.hpp" @@ -69,7 +69,7 @@ void setupMountPoints() int execFunction(void* call) { try { - return (*static_cast(call))(); + return (*static_cast(call))(); } catch(...) { return -1; // Non-zero on failure } @@ -78,29 +78,35 @@ int execFunction(void* call) } // namespace -AttachManager::AttachManager(lxcpp::ContainerImpl& container) - : mContainer(container) +Attach::Attach(lxcpp::ContainerImpl& container, + Container::AttachCall& userCall, + const int capsToKeep, + const std::string& workDirInContainer, + const std::vector& envToKeep, + const std::vector>& envToSet) + : mContainer(container), + mUserCall(userCall), + mCapsToKeep(capsToKeep), + mWorkDirInContainer(workDirInContainer), + mEnvToKeep(envToKeep), + mEnvToSet(envToSet) { } -AttachManager::~AttachManager() +Attach::~Attach() { } -void AttachManager::attach(Container::AttachCall& userCall, - const int capsToKeep, - const std::string& workDirInContainer, - const std::vector& envToKeep, - const std::vector>& envToSet) +void Attach::execute() { // Channels for setup synchronization utils::Channel intermChannel; - Call call = std::bind(&AttachManager::child, - std::move(userCall), - capsToKeep, - std::move(envToKeep), - std::move(envToSet)); + Call call = std::bind(&Attach::child, + mUserCall, + mCapsToKeep, + mEnvToKeep, + mEnvToSet); const pid_t interPid = lxcpp::fork(); if (interPid > 0) { @@ -109,16 +115,16 @@ void AttachManager::attach(Container::AttachCall& userCall, intermChannel.shutdown(); } else { intermChannel.setRight(); - interm(intermChannel, workDirInContainer, call); + interm(intermChannel, call); intermChannel.shutdown(); ::_exit(0); } } -int AttachManager::child(const Container::AttachCall& call, - const int capsToKeep, - const std::vector& envToKeep, - const std::vector>& envToSet) +int Attach::child(const Container::AttachCall& call, + const int capsToKeep, + const std::vector& envToKeep, + const std::vector>& envToSet) { // Setup capabilities dropCapsFromBoundingExcept(capsToKeep); @@ -134,7 +140,7 @@ int AttachManager::child(const Container::AttachCall& call, return call(); } -void AttachManager::parent(utils::Channel& intermChannel, const pid_t interPid) +void Attach::parent(utils::Channel& intermChannel, const pid_t interPid) { // TODO: Setup cgroups etc const pid_t childPid = intermChannel.read(); @@ -144,15 +150,13 @@ void AttachManager::parent(utils::Channel& intermChannel, const pid_t interPid) lxcpp::waitpid(childPid); } -void AttachManager::interm(utils::Channel& intermChannel, - const std::string& workDirInContainer, - Call& call) +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(workDirInContainer); + lxcpp::chdir(mWorkDirInContainer); // PID namespace won't affect the returned pid // CLONE_PARENT: Child's PPID == Caller's PID @@ -160,7 +164,6 @@ void AttachManager::interm(utils::Channel& intermChannel, &call, CLONE_PARENT); intermChannel.write(childPid); - } } // namespace lxcpp diff --git a/libs/lxcpp/commands/attach-manager.hpp b/libs/lxcpp/commands/attach.hpp similarity index 54% rename from libs/lxcpp/commands/attach-manager.hpp rename to libs/lxcpp/commands/attach.hpp index f286564..342b613 100644 --- a/libs/lxcpp/commands/attach-manager.hpp +++ b/libs/lxcpp/commands/attach.hpp @@ -21,9 +21,10 @@ * @brief Implementation of attaching to a container */ -#ifndef LXCPP_ATTACH_MANAGER_HPP -#define LXCPP_ATTACH_MANAGER_HPP +#ifndef LXCPP_COMMANDS_ATTACH_HPP +#define LXCPP_COMMANDS_ATTACH_HPP +#include "lxcpp/commands/command.hpp" #include "lxcpp/container-impl.hpp" #include "utils/channel.hpp" @@ -31,31 +32,40 @@ namespace lxcpp { -class AttachManager final { +class Attach final: Command { public: typedef std::function Call; - AttachManager(lxcpp::ContainerImpl& container); - ~AttachManager(); - /** - * Runs the call in the container's context + * Runs call in the container's context + * + * Object attach should be used immediately after creation. + * It will not be stored for future use like most other commands. * - * @param call function to run inside container - * @param capsToKeep mask of the capabilities that shouldn't be dropped - * @param workDirInContainer Current Work Directory. Path relative to container's root - * @param envToKeep environment variables to keep in container - * @param envToSet environment variables to add/modify in container + * @param container container to which it attaches + * @param userCall user's function to run + * @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 */ - void attach(Container::AttachCall& call, - const int capsToKeep, - const std::string& workDirInContainer, - const std::vector& envToKeep, - const std::vector>& envToSet); + Attach(lxcpp::ContainerImpl& container, + Container::AttachCall& userCall, + const int capsToKeep, + const std::string& workDirInContainer, + const std::vector& envToKeep, + const std::vector>& envToSet); + ~Attach(); -private: + void execute(); +private: const lxcpp::ContainerImpl& mContainer; + const Container::AttachCall& mUserCall; + const int mCapsToKeep; + const std::string& mWorkDirInContainer; + const std::vector& mEnvToKeep; + const std::vector>& mEnvToSet; // Methods for different stages of setting up the attachment static int child(const Container::AttachCall& call, @@ -67,10 +77,9 @@ private: const pid_t pid); void interm(utils::Channel& intermChannel, - const std::string& workDirInContainer, - Container::AttachCall& call); + Call& call); }; } // namespace lxcpp -#endif // LXCPP_ATTACH_MANAGER_HPP \ No newline at end of file +#endif // LXCPP_COMMANDS_ATTACH_HPP \ No newline at end of file diff --git a/libs/lxcpp/commands/command.hpp b/libs/lxcpp/commands/command.hpp new file mode 100644 index 0000000..cd301ee --- /dev/null +++ b/libs/lxcpp/commands/command.hpp @@ -0,0 +1,36 @@ +/* + * 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 Command interface definition + */ + +#ifndef LXCPP_COMMANDS_COMMAND_HPP +#define LXCPP_COMMANDS_COMMAND_HPP + +namespace lxcpp { + +class Command { +public: + virtual void execute() = 0; +}; + +} // namespace lxcpp + +#endif // LXCPP_COMMANDS_COMMAND_HPP \ No newline at end of file diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 0d8d5b1..7189bc7 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -27,7 +27,7 @@ #include "lxcpp/filesystem.hpp" #include "lxcpp/namespace.hpp" #include "lxcpp/capability.hpp" -#include "lxcpp/commands/attach-manager.hpp" +#include "lxcpp/commands/attach.hpp" #include "utils/exception.hpp" @@ -107,13 +107,14 @@ std::string ContainerImpl::getRootPath() void ContainerImpl::attach(Container::AttachCall& call, const std::string& cwdInContainer) { - AttachManager attachManager(*this); + Attach attach(*this, + call, + /*capsToKeep*/ 0, + cwdInContainer, + /*envToKeep*/ {}, + /*envInContainer*/ {{"container","lxcpp"}}); // TODO: Env variables should agree with the ones already in the container - attachManager.attach(call, - /*capsToKeep*/ 0, - cwdInContainer, - /*envToKeep*/ {}, - /*envInContainer*/{{"container","lxcpp"}} ); + attach.execute(); } const std::vector& ContainerImpl::getNamespaces() const -- 2.7.4 From ff9f7d8f7100c3dca173de14e3253e25b677f370 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Thu, 3 Sep 2015 20:50:19 +0200 Subject: [PATCH 02/16] lxcpp: UID/GID setting in Attach [Feature] UID/GID setting [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: Iaa83cab137df53a1391f01c0a29ef236da030aee --- libs/lxcpp/commands/attach.cpp | 25 ++++++++++++++-- libs/lxcpp/commands/attach.hpp | 14 +++++++++ libs/lxcpp/container-impl.cpp | 3 ++ libs/lxcpp/credentials.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++ libs/lxcpp/credentials.hpp | 43 +++++++++++++++++++++++++++ libs/lxcpp/exception.hpp | 5 ++++ 6 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 libs/lxcpp/credentials.cpp create mode 100644 libs/lxcpp/credentials.hpp diff --git a/libs/lxcpp/commands/attach.cpp b/libs/lxcpp/commands/attach.cpp index 98a4599..0ff856e 100644 --- a/libs/lxcpp/commands/attach.cpp +++ b/libs/lxcpp/commands/attach.cpp @@ -28,6 +28,7 @@ #include "lxcpp/namespace.hpp" #include "lxcpp/capability.hpp" #include "lxcpp/environment.hpp" +#include "lxcpp/credentials.hpp" #include "utils/exception.hpp" @@ -80,12 +81,18 @@ int execFunction(void* call) Attach::Attach(lxcpp::ContainerImpl& container, Container::AttachCall& userCall, + 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) : mContainer(container), mUserCall(userCall), + mUid(uid), + mGid(gid), + mSupplementaryGids(supplementaryGids), mCapsToKeep(capsToKeep), mWorkDirInContainer(workDirInContainer), mEnvToKeep(envToKeep), @@ -104,6 +111,9 @@ void Attach::execute() Call call = std::bind(&Attach::child, mUserCall, + mUid, + mGid, + mSupplementaryGids, mCapsToKeep, mEnvToKeep, mEnvToSet); @@ -122,20 +132,29 @@ void Attach::execute() } int Attach::child(const Container::AttachCall& call, + const uid_t uid, + const gid_t gid, + const std::vector& supplementaryGids, const int capsToKeep, const std::vector& envToKeep, const std::vector>& envToSet) { - // Setup capabilities - dropCapsFromBoundingExcept(capsToKeep); - // Setup /proc /sys mount setupMountPoints(); + // Setup capabilities + dropCapsFromBoundingExcept(capsToKeep); + // Setup environment variables clearenvExcept(envToKeep); setenv(envToSet); + // Set uid/gids + lxcpp::setgid(gid); + setgroups(supplementaryGids); + + lxcpp::setuid(uid); + // Run user's code return call(); } diff --git a/libs/lxcpp/commands/attach.hpp b/libs/lxcpp/commands/attach.hpp index 342b613..36c57ba 100644 --- a/libs/lxcpp/commands/attach.hpp +++ b/libs/lxcpp/commands/attach.hpp @@ -28,6 +28,8 @@ #include "lxcpp/container-impl.hpp" #include "utils/channel.hpp" +#include + #include namespace lxcpp { @@ -44,6 +46,9 @@ public: * * @param container container to which it attaches * @param userCall user's function to run + * @param uid uid in the container + * @param gid gid in the container + * @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 @@ -51,6 +56,9 @@ public: */ Attach(lxcpp::ContainerImpl& container, Container::AttachCall& userCall, + const uid_t uid, + const gid_t gid, + const std::vector& supplementaryGids, const int capsToKeep, const std::string& workDirInContainer, const std::vector& envToKeep, @@ -62,6 +70,9 @@ public: private: const lxcpp::ContainerImpl& mContainer; const Container::AttachCall& mUserCall; + const uid_t mUid; + const gid_t mGid; + const std::vector& mSupplementaryGids; const int mCapsToKeep; const std::string& mWorkDirInContainer; const std::vector& mEnvToKeep; @@ -69,6 +80,9 @@ private: // 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 std::vector& supplementaryGids, const int capsToKeep, const std::vector& envToKeep, const std::vector>& envToSet); diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 7189bc7..02e9f3a 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -109,6 +109,9 @@ void ContainerImpl::attach(Container::AttachCall& call, { Attach attach(*this, call, + /*uid in container*/ 0, + /*gid in container*/ 0, + /*supplementary gids in container*/ {}, /*capsToKeep*/ 0, cwdInContainer, /*envToKeep*/ {}, diff --git a/libs/lxcpp/credentials.cpp b/libs/lxcpp/credentials.cpp new file mode 100644 index 0000000..692be25 --- /dev/null +++ b/libs/lxcpp/credentials.cpp @@ -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 Jan Olszak (j.olszak@samsung.com) + * @brief Process credentials handling + */ + +#include "lxcpp/credentials.hpp" +#include "lxcpp/exception.hpp" + +#include "logger/logger.hpp" +#include "utils/exception.hpp" + +#include +#include + +namespace lxcpp { + +void setgroups(const std::vector& gids) +{ + if(-1 == ::setgroups(gids.size(), gids.data())) { + const std::string msg = "setgroups() failed: " + + utils::getSystemErrorMessage(); + LOGE(msg); + throw CredentialSetupException(msg); + } +} + +void setgid(const gid_t gid) +{ + if(-1 == ::setgid(gid)) { + const std::string msg = "setgid() failed: " + + utils::getSystemErrorMessage(); + LOGE(msg); + throw CredentialSetupException(msg); + } +} + +void setuid(const uid_t uid) +{ + if(-1 == ::setuid(uid)) { + const std::string msg = "setuid() failed: " + + utils::getSystemErrorMessage(); + LOGE(msg); + throw CredentialSetupException(msg); + } +} + +} // namespace lxcpp + diff --git a/libs/lxcpp/credentials.hpp b/libs/lxcpp/credentials.hpp new file mode 100644 index 0000000..df00ce5 --- /dev/null +++ b/libs/lxcpp/credentials.hpp @@ -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 Jan Olszak (j.olszak@samsung.com) + * @brief Process credentials handling + */ + +#ifndef LXCPP_CREDENTIALS_HPP +#define LXCPP_CREDENTIALS_HPP + +#include + +#include + +namespace lxcpp { + +void setgroups(const std::vector& groups); + +void setgid(const gid_t gid); + +void setuid(const uid_t uid); + + + +} // namespace lxcpp + +#endif // LXCPP_CREDENTIALS_HPP \ No newline at end of file diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index 8c11131..037da41 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -56,6 +56,11 @@ struct EnvironmentSetupException: public Exception { : Exception(message) {} }; +struct CredentialSetupException: public Exception { + CredentialSetupException(const std::string& message = "Error during handling environment variables") + : Exception(message) {} +}; + struct CapabilitySetupException: public Exception { CapabilitySetupException(const std::string& message = "Error during a capability operation") : Exception(message) {} -- 2.7.4 From 26530f30e16b55c2de880fe3a9b1d4a767c48287 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Fri, 4 Sep 2015 13:58:47 +0200 Subject: [PATCH 03/16] Adjust tests to lxc-1.1.3 [Feature] Adjust tests to lxc-1.1.3 [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I26d3abed39b60f5072399edcb116567d125d82f0 --- tests/unit_tests/configs/templates/buggy-template.conf | 2 +- tests/unit_tests/configs/templates/console-dbus.conf.in | 2 +- tests/unit_tests/configs/templates/console-ipc.conf.in | 2 +- tests/unit_tests/configs/templates/default.conf | 2 +- tests/unit_tests/configs/templates/minimal.sh | 2 -- tests/unit_tests/configs/templates/missing.conf | 2 +- tests/unit_tests/configs/templates/test-no-shutdown.conf | 2 +- tests/unit_tests/lxc/ut-zone.cpp | 10 +++++----- 8 files changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/unit_tests/configs/templates/buggy-template.conf b/tests/unit_tests/configs/templates/buggy-template.conf index 2ce4024..1f78be4 100644 --- a/tests/unit_tests/configs/templates/buggy-template.conf +++ b/tests/unit_tests/configs/templates/buggy-template.conf @@ -1,6 +1,6 @@ { "zoneTemplate" : "/buggy/path", - "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; read"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; while true; do sleep 0.1; done"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/configs/templates/console-dbus.conf.in b/tests/unit_tests/configs/templates/console-dbus.conf.in index 1ef567f..2dee28b 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; read"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; /bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/dbus/ut-dbus-system.conf --fork"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/configs/templates/console-ipc.conf.in b/tests/unit_tests/configs/templates/console-ipc.conf.in index dce9410..5abf8ba 100644 --- a/tests/unit_tests/configs/templates/console-ipc.conf.in +++ b/tests/unit_tests/configs/templates/console-ipc.conf.in @@ -1,6 +1,6 @@ { "zoneTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; read"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; while true; do sleep 0.1; done"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/configs/templates/default.conf b/tests/unit_tests/configs/templates/default.conf index 276adc9..006b9e4 100644 --- a/tests/unit_tests/configs/templates/default.conf +++ b/tests/unit_tests/configs/templates/default.conf @@ -1,6 +1,6 @@ { "zoneTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; read"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; while true; do sleep 0.1; done"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/configs/templates/minimal.sh b/tests/unit_tests/configs/templates/minimal.sh index 948cf01..12b921a 100755 --- a/tests/unit_tests/configs/templates/minimal.sh +++ b/tests/unit_tests/configs/templates/minimal.sh @@ -59,8 +59,6 @@ lxc.tty = 0 #lxc.loglevel = TRACE #lxc.logfile = /tmp/${name}.log -lxc.cgroup.devices.deny = a - lxc.mount.auto = proc sys cgroup lxc.mount.entry = /bin bin none ro,bind 0 0 lxc.mount.entry = /etc etc none ro,bind 0 0 diff --git a/tests/unit_tests/configs/templates/missing.conf b/tests/unit_tests/configs/templates/missing.conf index 4d5abd6..88679e5 100644 --- a/tests/unit_tests/configs/templates/missing.conf +++ b/tests/unit_tests/configs/templates/missing.conf @@ -1,6 +1,6 @@ { "zoneTemplate" : "missing.sh", - "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; read"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; while true; do sleep 0.1; done"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/configs/templates/test-no-shutdown.conf b/tests/unit_tests/configs/templates/test-no-shutdown.conf index 026c3e7..a60520f 100644 --- a/tests/unit_tests/configs/templates/test-no-shutdown.conf +++ b/tests/unit_tests/configs/templates/test-no-shutdown.conf @@ -1,6 +1,6 @@ { "zoneTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/bash"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; while true; do sleep 0.1; done"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/lxc/ut-zone.cpp b/tests/unit_tests/lxc/ut-zone.cpp index 7dae96e..47c1414 100644 --- a/tests/unit_tests/lxc/ut-zone.cpp +++ b/tests/unit_tests/lxc/ut-zone.cpp @@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE(StartShutdown) const char* argv[] = { "/bin/bash", "-c", - "trap exit SIGTERM; read", + "trap exit SIGTERM; while true; do sleep 0.1; done", NULL }; BOOST_CHECK(lxc.start(argv)); @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(FreezeUnfreeze) const char* argv[] = { "/bin/bash", "-c", - "trap exit SIGTERM; read", + "trap exit SIGTERM; while true; do sleep 0.1; done", NULL }; BOOST_CHECK(lxc.start(argv)); @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(FreezeStop) const char* argv[] = { "/bin/bash", "-c", - "trap exit SIGTERM; read", + "trap exit SIGTERM; while true; do sleep 0.1; done", NULL }; BOOST_CHECK(lxc.start(argv)); @@ -226,7 +226,7 @@ BOOST_AUTO_TEST_CASE(Repeat) const char* argv[] = { "/bin/bash", "-c", - "trap exit SIGTERM; read", + "trap exit SIGTERM; while true; do sleep 0.1; done", NULL }; BOOST_CHECK(lxc.start(argv)); @@ -259,7 +259,7 @@ BOOST_AUTO_TEST_CASE(CreateFile) const char* argv[] = { "/bin/bash", "-c", - "trap exit SIGTERM; read", + "trap exit SIGTERM; while true; do sleep 0.1; done", NULL }; BOOST_REQUIRE(lxc.start(argv)); -- 2.7.4 From ba34f2d1fed77882d019c0460007177f50693261 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 29 Jul 2015 13:27:25 +0200 Subject: [PATCH 04/16] lxcpp: Changes to the ContainerImpl class API for libConfig usage [Feature] Changes to the ContainerImpl class API for libConfig usage. PersistentFileBackend for logger. [Verification] Build, install, run tests. Change-Id: I3e7290df2bf42df9e067fe6734b96dcf5f3aa20b --- libs/logger/backend-persistent-file.cpp | 46 ++++++++++++ libs/logger/backend-persistent-file.hpp | 52 ++++++++++++++ libs/logger/logger.hpp | 2 + libs/lxcpp/container-impl.cpp | 86 +++++++++++++++++------ libs/lxcpp/container-impl.hpp | 55 +++++++++++---- libs/lxcpp/container.hpp | 20 +++--- libs/lxcpp/exception.hpp | 7 +- libs/lxcpp/lxcpp.cpp | 4 +- libs/lxcpp/lxcpp.hpp | 2 +- tests/unit_tests/lxcpp/lxcpp-api-compile-test.cpp | 3 +- tests/unit_tests/lxcpp/ut-container.cpp | 2 +- 11 files changed, 227 insertions(+), 52 deletions(-) create mode 100644 libs/logger/backend-persistent-file.cpp create mode 100644 libs/logger/backend-persistent-file.hpp diff --git a/libs/logger/backend-persistent-file.cpp b/libs/logger/backend-persistent-file.cpp new file mode 100644 index 0000000..8aa53cb --- /dev/null +++ b/libs/logger/backend-persistent-file.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Pawelczyk (l.pawelczyk@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@samsung.com) + * @brief Persistent file backend for logger + */ + +#include "logger/config.hpp" +#include "logger/formatter.hpp" +#include "logger/backend-persistent-file.hpp" + +#include + +namespace logger { + +void PersistentFileBackend::log(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func, + const std::string& message) +{ + mOut << LogFormatter::getHeader(logLevel, file, line, func); + mOut << message; + mOut << std::endl; + mOut.flush(); +} + + +} // namespace logger diff --git a/libs/logger/backend-persistent-file.hpp b/libs/logger/backend-persistent-file.hpp new file mode 100644 index 0000000..74d2def --- /dev/null +++ b/libs/logger/backend-persistent-file.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Pawelczyk (l.pawelczyk@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@samsung.com) + * @brief Persistent file backend for logger + */ + +#ifndef COMMON_LOGGER_BACKEND_PERSISTENT_FILE_HPP +#define COMMON_LOGGER_BACKEND_PERSISTENT_FILE_HPP + +#include "logger/backend.hpp" + +#include + +namespace logger { + +class PersistentFileBackend : public LogBackend { +public: + PersistentFileBackend(const std::string& filePath) : + mfilePath(filePath), + mOut(mfilePath, std::ios::app) {} + + void log(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func, + const std::string& message) override; +private: + std::string mfilePath; + std::ofstream mOut; +}; + +} // namespace logger + +#endif // COMMON_LOGGER_BACKEND_PERSISTENT_FILE_HPP diff --git a/libs/logger/logger.hpp b/libs/logger/logger.hpp index bedddb0..0a1ebe6 100644 --- a/libs/logger/logger.hpp +++ b/libs/logger/logger.hpp @@ -36,6 +36,7 @@ * Logger::setLogBackend(new NullLogger()); * Logger::setLogBackend(new SystemdJournalBackend()); * Logger::setLogBackend(new FileBackend("/tmp/logs.txt")); + * Logger::setLogBackend(new PersistentFileBackend("/tmp/logs.txt")); * Logger::setLogBackend(new SyslogBackend()); * Logger::setLogBackend(new StderrBackend()); * @@ -62,6 +63,7 @@ #include "logger/level.hpp" #include "logger/backend-file.hpp" #include "logger/backend-stderr.hpp" +#include "logger/backend-persistent-file.hpp" #include #include diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 02e9f3a..73e5254 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -29,77 +29,118 @@ #include "lxcpp/capability.hpp" #include "lxcpp/commands/attach.hpp" +#include "logger/logger.hpp" #include "utils/exception.hpp" #include #include +#include +#include +#include + namespace lxcpp { -ContainerImpl::ContainerImpl() +ContainerImpl::ContainerImpl(const std::string &name, const std::string &path) { -} + if (name.empty()) { + const std::string msg = "Name cannot be empty"; + LOGE(msg); + throw ConfigureException(msg); + } -ContainerImpl::~ContainerImpl() -{ + if (path.empty()) { + const std::string msg = "Path cannot be empty"; + LOGE(msg); + throw ConfigureException(msg); + } + + if(::access(path.c_str(), X_OK) < 0) { + const std::string msg = "Path must point to a traversable directory"; + LOGE(msg); + throw ConfigureException(msg); + } + + mConfig.mName = name; + mConfig.mRootPath = path; } -std::string ContainerImpl::getName() +// TODO: the aim of this constructor is to create a new ContainerImpl based on an already +// running container. It should talk to its guard and receive its current config. +ContainerImpl::ContainerImpl(pid_t /*guardPid*/) { throw NotImplementedException(); } -void ContainerImpl::setName(const std::string& /* name */) +ContainerImpl::~ContainerImpl() { - throw NotImplementedException(); } -void ContainerImpl::start() +const std::string& ContainerImpl::getName() const { - throw NotImplementedException(); + return mConfig.mName; } -void ContainerImpl::stop() +const std::string& ContainerImpl::getRootPath() const { - throw NotImplementedException(); + return mConfig.mRootPath; } -void ContainerImpl::freeze() +const std::vector& ContainerImpl::getInit() { - throw NotImplementedException(); + return mConfig.mInit; } -void ContainerImpl::unfreeze() +void ContainerImpl::setInit(const std::vector &init) { - throw NotImplementedException(); + if (init.empty() || init[0].empty()) { + const std::string msg = "Init path cannot be empty"; + LOGE(msg); + throw ConfigureException(msg); + } + + std::string path = mConfig.mRootPath + "/" + init[0]; + + if (::access(path.c_str(), X_OK) < 0) { + const std::string msg = "Init path must point to an executable file"; + LOGE(msg); + throw ConfigureException(msg); + } + + mConfig.mInit = init; } -void ContainerImpl::reboot() +pid_t ContainerImpl::getGuardPid() const { - throw NotImplementedException(); + return mConfig.mGuardPid; } pid_t ContainerImpl::getInitPid() const { - return mInitPid; + return mConfig.mInitPid; } -void ContainerImpl::create() +void ContainerImpl::start() { throw NotImplementedException(); } -void ContainerImpl::destroy() +void ContainerImpl::stop() { throw NotImplementedException(); } -void ContainerImpl::setRootPath(const std::string& /* path */) +void ContainerImpl::freeze() { throw NotImplementedException(); } -std::string ContainerImpl::getRootPath() +void ContainerImpl::unfreeze() +{ + throw NotImplementedException(); +} + +void ContainerImpl::reboot() { throw NotImplementedException(); } @@ -125,7 +166,6 @@ const std::vector& ContainerImpl::getNamespaces() const return mNamespaces; } - void ContainerImpl::addInterfaceConfig(const std::string& hostif, const std::string& zoneif, InterfaceType type, diff --git a/libs/lxcpp/container-impl.hpp b/libs/lxcpp/container-impl.hpp index c862473..5435d49 100644 --- a/libs/lxcpp/container-impl.hpp +++ b/libs/lxcpp/container-impl.hpp @@ -24,6 +24,11 @@ #ifndef LXCPP_CONTAINER_IMPL_HPP #define LXCPP_CONTAINER_IMPL_HPP +#include +#include +#include +#include + #include "lxcpp/container.hpp" #include "lxcpp/namespace.hpp" #include "lxcpp/network.hpp" @@ -32,28 +37,50 @@ 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: - ContainerImpl(); + ContainerImpl(const std::string &name, const std::string &path); + ContainerImpl(pid_t guardPid); ~ContainerImpl(); - std::string getName(); - void setName(const std::string& name); + // Configuration + const std::string& getName() const; + const std::string& getRootPath() const; + + pid_t getGuardPid() const; + pid_t getInitPid() const; - //Execution actions + const std::vector& getInit(); + void setInit(const std::vector &init); + + const std::vector& getNamespaces() const; + + // Execution actions void start(); void stop(); void freeze(); void unfreeze(); void reboot(); - pid_t getInitPid() const; - const std::vector& getNamespaces() const; - - //Filesystem actions - void create(); - void destroy(); - void setRootPath(const std::string& path); - std::string getRootPath(); // Other void attach(Container::AttachCall& attachCall, @@ -80,7 +107,9 @@ public: void delAddr(const std::string& ifname, const InetAddr& addr); private: - pid_t mInitPid; + ContainerConfig mConfig; + + // TODO: convert to ContainerConfig struct std::vector mNamespaces; std::vector mInterfaceConfig; }; diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp index 882aa87..192f2df 100644 --- a/libs/lxcpp/container.hpp +++ b/libs/lxcpp/container.hpp @@ -50,22 +50,22 @@ public: virtual ~Container() {}; - virtual std::string getName() = 0; - virtual void setName(const std::string& name) = 0; + // Configuration + virtual const std::string& getName() const = 0; + virtual const std::string& getRootPath() const = 0; - //Execution actions + virtual pid_t getGuardPid() const = 0; + virtual pid_t getInitPid() const = 0; + + virtual const std::vector& getInit() = 0; + virtual void setInit(const std::vector &init) = 0; + + // Execution actions virtual void start() = 0; virtual void stop() = 0; virtual void freeze() = 0; virtual void unfreeze() = 0; virtual void reboot() = 0; - virtual pid_t getInitPid() const = 0; - - //Filesystem actions - virtual void create() = 0; - virtual void destroy() = 0; - virtual void setRootPath(const std::string& path) = 0; - virtual std::string getRootPath() = 0; // Other virtual void attach(AttachCall& attachCall, diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index 037da41..af81779 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -42,7 +42,7 @@ struct NotImplementedException: public Exception { }; struct ProcessSetupException: public Exception { - ProcessSetupException(const std::string& message = "Error during setting up a process") + ProcessSetupException(const std::string& message = "Error while setting up a process") : Exception(message) {} }; @@ -81,6 +81,11 @@ struct NetworkException : public Exception { : Exception(message) {} }; +struct ConfigureException: public Exception { + ConfigureException(const std::string& message = "Error while configuring a container") + : Exception(message) {} +}; + } // namespace lxcpp #endif // LXCPP_EXCEPTION_HPP diff --git a/libs/lxcpp/lxcpp.cpp b/libs/lxcpp/lxcpp.cpp index 97c3866..35cd3d6 100644 --- a/libs/lxcpp/lxcpp.cpp +++ b/libs/lxcpp/lxcpp.cpp @@ -25,9 +25,9 @@ namespace lxcpp { -Container* createContainer() +Container* createContainer(const std::string& name, const std::string& path) { - return new ContainerImpl(); + return new ContainerImpl(name, path); } } // namespace lxcpp diff --git a/libs/lxcpp/lxcpp.hpp b/libs/lxcpp/lxcpp.hpp index 5eb3f57..c2b3029 100644 --- a/libs/lxcpp/lxcpp.hpp +++ b/libs/lxcpp/lxcpp.hpp @@ -28,7 +28,7 @@ namespace lxcpp { -Container* createContainer(); +Container* createContainer(const std::string &name, const std::string &path); } // namespace lxcpp diff --git a/tests/unit_tests/lxcpp/lxcpp-api-compile-test.cpp b/tests/unit_tests/lxcpp/lxcpp-api-compile-test.cpp index 2e72bfb..f6d48c2 100644 --- a/tests/unit_tests/lxcpp/lxcpp-api-compile-test.cpp +++ b/tests/unit_tests/lxcpp/lxcpp-api-compile-test.cpp @@ -27,6 +27,7 @@ using namespace lxcpp; int main(int /*argc*/, const char * /*argv*/ []) { - Container* c = createContainer(); + Container* c = createContainer("Name", "/"); + delete c; } diff --git a/tests/unit_tests/lxcpp/ut-container.cpp b/tests/unit_tests/lxcpp/ut-container.cpp index 6177502..35672e0 100644 --- a/tests/unit_tests/lxcpp/ut-container.cpp +++ b/tests/unit_tests/lxcpp/ut-container.cpp @@ -44,7 +44,7 @@ using namespace lxcpp; BOOST_AUTO_TEST_CASE(ConstructorDestructor) { - auto c = createContainer(); + auto c = createContainer("FirstTestContainer", "/"); delete c; } -- 2.7.4 From 500d09337df5b74b5f292b8d0d275607de1aa1b1 Mon Sep 17 00:00:00 2001 From: "Maciej J. Karpiuk" Date: Fri, 4 Sep 2015 16:39:29 +0200 Subject: [PATCH 05/16] server: file logging added to logging backends [Feature] new logging backend support: file [Cause] N/A [Solution] one more option to logging-backend [Verification] try to log to file and user specified filename Change-Id: Iae51c076c1b52439ff6388cf50b85dc14165a59e --- server/main.cpp | 15 +++++++++++++-- zone-daemon/main.cpp | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/server/main.cpp b/server/main.cpp index af30cd2..81f908f 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -64,7 +64,8 @@ int main(int argc, char* argv[]) #else const char *defaultLoggingBackend = "syslog"; #endif - po::options_description desc("Allowed options"); + // 100 - wider terminal, nicer option descriptions + po::options_description desc("Allowed options", 100); desc.add_options() ("help,h", "print this help") @@ -72,11 +73,13 @@ int main(int argc, char* argv[]) ("daemon,d", "Run server as daemon") ("log-level,l", po::value()->default_value("DEBUG"), "set log level") ("log-backend,b", po::value()->default_value(defaultLoggingBackend), - "set log backend [stderr,syslog" + "set log backend [stderr,syslog,file" #ifdef HAVE_SYSTEMD ",journal" #endif "]") + ("log-file,f", po::value()->default_value("vasum.log"), + "set filename for file logging, optional") ("check,c", "check runtime environment and exit") ("version,v", "show application version") ; @@ -127,6 +130,14 @@ int main(int argc, char* argv[]) if(logBackend.compare("stderr") == 0) { Logger::setLogBackend(new StderrBackend()); } + else if(logBackend.compare("file") == 0) { + const std::string logFilename = vm["log-file"].as(); + if(logFilename.empty()) { + std::cerr << "Error: invalid log file provided for file logging backend" << std::endl; + return 1; + } + Logger::setLogBackend(new FileBackend(logFilename)); + } #ifdef HAVE_SYSTEMD else if(logBackend.compare("journal") == 0) { Logger::setLogBackend(new SystemdJournalBackend()); diff --git a/zone-daemon/main.cpp b/zone-daemon/main.cpp index 82b152e..4e59091 100644 --- a/zone-daemon/main.cpp +++ b/zone-daemon/main.cpp @@ -61,18 +61,21 @@ int main(int argc, char* argv[]) const char *defaultLoggingBackend = "syslog"; #endif - po::options_description desc("Allowed options"); + // 100 - wider terminal, nicer option descriptions + po::options_description desc("Allowed options", 100); desc.add_options() ("help,h", "print this help") ("daemon,d", "Run server as daemon") ("log-level,l", po::value()->default_value("DEBUG"), "set log level") ("log-backend,b", po::value()->default_value(defaultLoggingBackend), - "set log backend [stderr,syslog" + "set log backend [stderr,syslog,file" #ifdef HAVE_SYSTEMD ",journal" #endif "]") + ("log-file,f", po::value()->default_value("zoned.log"), + "set filename for file logging, optional") ("version,v", "show application version") ; @@ -119,6 +122,14 @@ int main(int argc, char* argv[]) if(logBackend.compare("stderr") == 0) { Logger::setLogBackend(new StderrBackend()); } + else if(logBackend.compare("file") == 0) { + const std::string logFilename = vm["log-file"].as(); + if(logFilename.empty()) { + std::cerr << "Error: invalid log file provided for file logging backend" << std::endl; + return 1; + } + Logger::setLogBackend(new FileBackend(logFilename)); + } #ifdef HAVE_SYSTEMD else if(logBackend.compare("journal") == 0) { Logger::setLogBackend(new SystemdJournalBackend()); -- 2.7.4 From 3b14d399c8dfe556cd4a253db8e06e4f4ce79633 Mon Sep 17 00:00:00 2001 From: "Maciej J. Karpiuk" Date: Fri, 4 Sep 2015 12:45:38 +0200 Subject: [PATCH 06/16] libIpc: doxygen docs added [Feature] libIpc doxygen docs enabled and enhanced [Cause] documentation task in progress, libIpc was not yet included [Solution] write missing docs, create group [Verification] build docs and check libIpc module Change-Id: Ic8e5261200da9714b478461fe830fabbaa3b5bc9 --- libs/ipc/client.hpp | 99 +++++++++++++++++++++++-------- libs/ipc/epoll/event-poll.hpp | 54 ++++++++++++++++- libs/ipc/epoll/events.hpp | 12 +++- libs/ipc/exception.hpp | 36 ++++++++++- libs/ipc/internals/processor.hpp | 17 +++--- libs/ipc/method-result.hpp | 4 ++ libs/ipc/service.hpp | 125 +++++++++++++++++++++++++++++---------- libs/ipc/types.hpp | 54 ++++++++++++++++- 8 files changed, 330 insertions(+), 71 deletions(-) diff --git a/libs/ipc/client.hpp b/libs/ipc/client.hpp index e083166..a26ccbc 100644 --- a/libs/ipc/client.hpp +++ b/libs/ipc/client.hpp @@ -19,6 +19,7 @@ /** * @file * @author Jan Olszak (j.olszak@samsung.com) + * @defgroup libIpc libIpc * @brief Handling client connections */ @@ -36,29 +37,68 @@ namespace ipc { /** - * This class wraps communication via UX sockets for client applications. + * @brief This class wraps communication via UX sockets for client applications. * It uses serialization mechanism from Config. * - * For message format @see ipc::Processor + * @code + * // eventPoll - epoll wrapper class + * // address - server socket address + * ipc::epoll::EventPoll examplePoll; + * ipc::Client myClient(examplePoll, address); + * myClient.start(); // connect to the service + * // call method synchronously + * const auto result = mClient.callSync( + * api::ipc::METHOD_GET_ZONE_ID_LIST, + * std::make_shared()); + * // call method asynchronously + * // first: declare lambda function to call on completion + * auto asyncResult = [result](ipc::Result&& out) { + * if (out.isValid()) { + * // got successful response! + * } + * }; + * std::string id = "example_zone_id"; + * mClient.callAsync(api::ipc::METHOD_DESTROY_ZONE, + * std::make_shared(api::ZoneId{id}), + * asyncResult); + * @endcode + * + * @see libConfig + * @see ipc::Processor + * @see ipc::epoll::EventPoll + * + * @ingroup libIpc */ class Client { public: /** - * @param eventPoll event poll - * @param serverPath path to the server's socket + * Constructs the Client, but doesn't start it. + * Once set-up, call start() to connect client to the server. + * + * @param eventPoll event poll + * @param serverPath path to the server's socket */ Client(epoll::EventPoll& eventPoll, const std::string& serverPath); ~Client(); + /** + * Copying Client class is prohibited. + */ Client(const Client&) = delete; + /** + * Copying Client class is prohibited. + */ Client& operator=(const Client&) = delete; /** * Starts processing + * @note if the Client is already running, it quits immediately (no exception thrown) */ void start(); /** + * Is the communication thread running? + * * @return is the communication thread running */ bool isStarted(); @@ -66,21 +106,23 @@ public: /** * Stops processing * - * @param wait does it block waiting for all internals to stop + * @param wait should the call block while waiting for all internals to stop? By default true - do block. */ void stop(bool wait = true); /** * Set the callback called for each new connection to a peer * - * @param newPeerCallback the callback + * @param newPeerCallback the callback to call on new connection event + * @note if callback is already set, it will be overridden */ void setNewPeerCallback(const PeerCallback& newPeerCallback); /** * Set the callback called when connection to a peer is lost * - * @param removedPeerCallback the callback + * @param removedPeerCallback the callback to call on peer disconnected event + * @note if callback is already set, it will be overridden */ void setRemovedPeerCallback(const PeerCallback& removedPeerCallback); @@ -89,8 +131,10 @@ public: * When a message with the given method id is received * the data will be parsed and passed to this callback. * - * @param methodID API dependent id of the method - * @param method method handling implementation + * @param methodID API dependent id of the method + * @param method method handling implementation + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive */ template void setMethodHandler(const MethodID methodID, @@ -101,28 +145,32 @@ public: * When a message with the given method id is received * the data will be parsed and passed to this callback. * - * @param methodID API dependent id of the method - * @param signal signal handling implementation - * @tparam ReceivedDataType data type to serialize + * @param methodID API dependent id of the method + * @param signal data processing callback + * @tparam ReceivedDataType data type to receive */ template void setSignalHandler(const MethodID methodID, const typename SignalHandler::type& signal); /** - * Removes the callback + * Removes the callback associated with specific method id. * - * @param methodID API dependent id of the method + * @param methodID API dependent id of the method + * @see setMethodHandler() + * @see setSignalHandler() */ void removeMethod(const MethodID methodID); /** * Synchronous method call. * - * @param methodID API dependent id of the method - * @param data data to send - * @param timeoutMS how long to wait for the return value before throw - * @return result data + * @param methodID API dependent id of the method + * @param data data to send + * @param timeoutMS optional, how long to wait for the return value before throw (milliseconds, default: 5000) + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive + * @return pointer to the call result data */ template std::shared_ptr callSync(const MethodID methodID, @@ -133,10 +181,11 @@ public: * Asynchronous method call. The return callback will be called on * return data arrival. It will be run in the PROCESSOR thread. * - * - * @param methodID API dependent id of the method - * @param data data to send - * @param resultCallback callback for result serialization and handling + * @param methodID API dependent id of the method + * @param data data to send + * @param resultCallback callback processing the return data + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive */ template void callAsync(const MethodID methodID, @@ -148,9 +197,9 @@ public: * There is no return value from the peer * Sends any data only if a peer registered this a signal * - * @param methodID API dependent id of the method - * @param data data to sent - * @tparam SentDataType data type to send + * @param methodID API dependent id of the method + * @param data data to send + * @tparam SentDataType data type to send */ template void signal(const MethodID methodID, diff --git a/libs/ipc/epoll/event-poll.hpp b/libs/ipc/epoll/event-poll.hpp index ba82497..ceb5717 100644 --- a/libs/ipc/epoll/event-poll.hpp +++ b/libs/ipc/epoll/event-poll.hpp @@ -35,23 +35,71 @@ namespace ipc { namespace epoll { +/** + * @brief This class waits on registered file descriptor for events. + * It uses epoll mechanism. + * + * @see ipc::epoll::Events + * + * @ingroup Types + */ class EventPoll { public: + /** + * Generic function type used as callback for epoll events. + * + * @param fd descriptor that triggered the event + * @param events event mask that occured + * @see ipc::epoll::Events + */ typedef std::function Callback; + /** + * Constructs the EventPoll and initializes the underlaying epoll mechanism. + * @throw UtilsException thrown if epoll initialization failed + */ EventPoll(); ~EventPoll(); + /** + * Returns epoll handle. + * @return handle or -1 if not initialized + */ int getPollFD() const; + /** + * Add descriptor and it's watched events. + * + * @param fd descriptor to watch + * @param events events to associate with the descriptor + * @param callback callback to call once the event occurs + * @throw UtilsException thrown if descriptor already registered or add fail + * @see ipc::epoll::Events + */ void addFD(const int fd, const Events events, Callback&& callback); + + /** + * Modify watched events for descriptor. + * @param fd watched descriptor, already registered + * @param events events to associate with the descriptor + * @throw UtilsException if descriptor not found or epoll modify fail + * @see ipc::epoll::Events + */ void modifyFD(const int fd, const Events events); + + /** + * Remove descriptor from the watch list. + * @param fd watched descriptor + */ void removeFD(const int fd); /** - * Dispatch at most one signaled FD - * @param timeoutMs how long should wait in case of no pending events - * (0 - return immediately, -1 - wait forever) + * Wait for events on descriptor on the watch list. + * Dispatch at most one signaled FD. + * + * @param timeoutMs how long should wait in case of no pending events + * (0 - return immediately, -1 - wait forever) + * @throw UtilsException if epoll_wait fails * @return false on timeout */ bool dispatchIteration(const int timeoutMs); diff --git a/libs/ipc/epoll/events.hpp b/libs/ipc/epoll/events.hpp index 093542b..219bcd2 100644 --- a/libs/ipc/epoll/events.hpp +++ b/libs/ipc/epoll/events.hpp @@ -31,8 +31,18 @@ namespace ipc { namespace epoll { -typedef unsigned int Events; ///< bitmask of EPOLL* constants +/** + * @brief bitmask of EPOLL* constants + * @ingroup Types + */ +typedef unsigned int Events; +/** + * Convert event mask into readable string. + * Values will be comma separated. + * @param events event type mask to convert + * @return string describing the mask + */ std::string eventsToString(Events events); } // namespace epoll diff --git a/libs/ipc/exception.hpp b/libs/ipc/exception.hpp index 271cf9a..140619c 100644 --- a/libs/ipc/exception.hpp +++ b/libs/ipc/exception.hpp @@ -31,48 +31,82 @@ namespace ipc { /** - * Base class for exceptions in IPC + * @brief Base class for all exceptions in libIpc. + * @ingroup Types + * @defgroup IPCException IPCException */ struct IPCException: public std::runtime_error { IPCException(const std::string& message) : std::runtime_error(message) {} }; +/** + * Exception to indicate error while reading/parsing data from the socket. + * @ingroup IPCException + */ struct IPCParsingException: public IPCException { IPCParsingException(const std::string& message = "Exception during reading/parsing data from the socket") : IPCException(message) {} }; +/** + * Exception to indicate error while writing/serializing data to the socket. + * @ingroup IPCException + */ struct IPCSerializationException: public IPCException { IPCSerializationException(const std::string& message = "Exception during writing/serializing data to the socket") : IPCException(message) {} }; +/** + * Exception to indicate that requested peer is not available, i.e. might got disconnected. + * @ingroup IPCException + */ struct IPCPeerDisconnectedException: public IPCException { IPCPeerDisconnectedException(const std::string& message = "No such peer. Might got disconnected.") : IPCException(message) {} }; +/** + * Exception to indicate that peer performed a forbidden action. + * @ingroup IPCException + */ struct IPCNaughtyPeerException: public IPCException { IPCNaughtyPeerException(const std::string& message = "Peer performed a forbidden action.") : IPCException(message) {} }; +/** + * Exception to indicate error while removing peer + * @ingroup IPCException + */ struct IPCRemovedPeerException: public IPCException { IPCRemovedPeerException(const std::string& message = "Removing peer") : IPCException(message) {} }; +/** + * Exception to indicate error while closing IPC channel + * @ingroup IPCException + */ struct IPCClosingException: public IPCException { IPCClosingException(const std::string& message = "Closing IPC") : IPCException(message) {} }; +/** + * Exception to indicate timeout event error + * @ingroup IPCException + */ struct IPCTimeoutException: public IPCException { IPCTimeoutException(const std::string& message) : IPCException(message) {} }; +/** + * Exception to indicate user error + * @ingroup IPCException + */ struct IPCUserException: public IPCException { IPCUserException(const int code, const std::string& message) : IPCException(message), diff --git a/libs/ipc/internals/processor.hpp b/libs/ipc/internals/processor.hpp index 2706792..e383a57 100644 --- a/libs/ipc/internals/processor.hpp +++ b/libs/ipc/internals/processor.hpp @@ -246,21 +246,24 @@ public: const MessageID messageID); /** - * Removes the callback + * Removes the callback associated with specific method id. * - * @param methodID API dependent id of the method + * @param methodID API dependent id of the method + * @see setMethodHandler() + * @see setSignalHandler() */ void removeMethod(const MethodID methodID); /** * Synchronous method call. * - * @param methodID API dependent id of the method - * @param peerID id of the peer - * @param data data to send - * @param timeoutMS how long to wait for the return value before throw - * @tparam SentDataType data type to send + * @param methodID API dependent id of the method + * @param peerID id of the peer + * @param data data to send + * @param timeoutMS optional, how long to wait for the return value before throw (milliseconds, default: 5000) + * @tparam SentDataType data type to send * @tparam ReceivedDataType data type to receive + * @return call result data */ template std::shared_ptr callSync(const MethodID methodID, diff --git a/libs/ipc/method-result.hpp b/libs/ipc/method-result.hpp index 26369ed..c1729f7 100644 --- a/libs/ipc/method-result.hpp +++ b/libs/ipc/method-result.hpp @@ -33,6 +33,10 @@ namespace ipc { class Processor; +/** + * @brief Class used to obtain method call result code. + * @ingroup Types + */ class MethodResult { public: typedef std::shared_ptr Pointer; diff --git a/libs/ipc/service.hpp b/libs/ipc/service.hpp index 5e73a71..a5f7c86 100644 --- a/libs/ipc/service.hpp +++ b/libs/ipc/service.hpp @@ -38,28 +38,72 @@ namespace ipc { /** - * This class wraps communication via UX sockets. + * @brief This class wraps communication via UX sockets. * It uses serialization mechanism from Config. * - * For message format @see ipc::Processor + * @code + * // eventPoll - epoll wrapper class + * // address - server socket address + * ipc::epoll::EventPoll examplePoll; + * // create callbacks for connected / disconnected events + * ipc::PeerCallback connectedCallback = [this](const ipc::PeerID peerID, + * const ipc::FileDescriptor) { + * // new connection came! + * }; + * ipc::PeerCallback disconnectedCallback = [this](const ipc::PeerID peerID, + * const ipc::FileDescriptor) { + * // connection disconnected! + * }; + * // create the service + * ipc::Service myService(eventPoll, "/tmp/example_service.socket", + * connectedCallback, disconnectedCallback)); + * // add example method handler + * auto exampleMethodHandler = [&](const PeerID, std::shared_ptr& data, MethodResult::Pointer methodResult) { + * // got example method call! Incoming data in "data" argument + * // respond with some data + * auto returnData = std::make_shared(data->intVal); + * methodResult->set(returnData); + * }; + * const MethodID exampleMethodID = 1234; + * myService.setMethodHandler(exampleMethodID, exampleMethodHandler); + * myService.start(); // start the service, clients may connect via /tmp/example_service.socket + * @endcode + * + * @see libConfig + * @see ipc::Processor + * + * @ingroup libIpc */ class Service { public: /** - * @param eventPoll event poll - * @param path path to the socket + * Constructs the Service, but doesn't start it. + * The object is ready to add methods. + * Once set-up, call start() to start the service. + * + * @param eventPoll event poll + * @param path path to the socket + * @param addPeerCallback optional on new peer connection callback + * @param removePeerCallback optional on peer removal callback */ Service(epoll::EventPoll& eventPoll, const std::string& path, const PeerCallback& addPeerCallback = nullptr, const PeerCallback& removePeerCallback = nullptr); - ~Service(); + virtual ~Service(); + /** + * Copying Service class is prohibited. + */ Service(const Service&) = delete; + /** + * Copying Service class is prohibited. + */ Service& operator=(const Service&) = delete; /** * Starts processing + * @note if the service is already running, it quits immediately (no exception thrown) */ void start(); @@ -71,62 +115,79 @@ public: /** * Stops all working threads * - * @param wait does it block waiting for all internals to stop + * @param wait should the call block while waiting for all internals to stop? By default true - do block. */ void stop(bool wait = true); /** * Set the callback called for each new connection to a peer * - * @param newPeerCallback the callback + * @param newPeerCallback the callback to call on new connection event + * @note if callback is already set, it will be overridden */ void setNewPeerCallback(const PeerCallback& newPeerCallback); /** * Set the callback called when connection to a peer is lost * - * @param removedPeerCallback the callback + * @param removedPeerCallback the callback to call on peer disconnected event + * @note if callback is already set, it will be overridden */ void setRemovedPeerCallback(const PeerCallback& removedPeerCallback); /** - * Saves the callback connected to the method id. - * When a message with the given method id is received - * the data will be parsed and passed to this callback. + * Saves the callbacks connected to the method id. + * When a message with the given method id is received, + * the data will be passed to the serialization callback through file descriptor. + * + * Then the process callback will be called with the parsed data. * - * @param methodID API dependent id of the method - * @param method method handling implementation + * @param methodID API dependent id of the method + * @param method data processing callback + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive */ template void setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method); /** - * Saves the callback connected to the method id. - * When a message with the given method id is received - * the data will be parsed and passed to this callback. + * Saves the callbacks connected to the method id. + * When a message with the given method id is received, + * the data will be passed to the serialization callback through file descriptor. + * + * Then the process callback will be called with the parsed data. + * There is no return data to send back. * - * @param methodID API dependent id of the method - * @param handler handling implementation - * @tparam ReceivedDataType data type to serialize + * Adding signal sends a registering message to all peers + * + * @param methodID API dependent id of the method + * @param handler data processing callback + * @tparam ReceivedDataType data type to receive */ template void setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler); /** - * Removes the callback + * Removes the callback associated with specific method id. * - * @param methodID API dependent id of the method + * @param methodID API dependent id of the method + * @see setMethodHandler() + * @see setSignalHandler() */ void removeMethod(const MethodID methodID); /** * Synchronous method call. * - * @param methodID API dependent id of the method - * @param data data to send - * @return result data + * @param methodID API dependent id of the method + * @param peerID id of the peer + * @param data data to send + * @param timeoutMS optional, how long to wait for the return value before throw (milliseconds, default: 5000) + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive + * @return pointer to the call result data */ template std::shared_ptr callSync(const MethodID methodID, @@ -138,10 +199,12 @@ public: * Asynchronous method call. The return callback will be called on * return data arrival. It will be run in the PROCESSOR thread. * - * - * @param methodID API dependent id of the method - * @param data data to send - * @param resultCallback callback for result serialization and handling + * @param methodID API dependent id of the method + * @param peerID id of the peer + * @param data data to send + * @param resultCallback callback processing the return data + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive */ template void callAsync(const MethodID methodID, @@ -154,9 +217,9 @@ public: * There is no return value from the peer * Sends any data only if a peer registered this a signal * - * @param methodID API dependent id of the method - * @param data data to sent - * @tparam SentDataType data type to send + * @param methodID API dependent id of the method + * @param data data to send + * @tparam SentDataType data type to send */ template void signal(const MethodID methodID, diff --git a/libs/ipc/types.hpp b/libs/ipc/types.hpp index fad01b3..c9b270b 100644 --- a/libs/ipc/types.hpp +++ b/libs/ipc/types.hpp @@ -31,19 +31,67 @@ namespace ipc { +/** + * @brief Generic types used in libIpc. + * + * @ingroup libIpc + * @defgroup Types libIpc tools + */ + typedef int FileDescriptor; typedef unsigned int MethodID; typedef std::string MessageID; typedef std::string PeerID; -typedef std::function PeerCallback; -typedef std::function& data)> SerializeCallback; -typedef std::function(int fd)> ParseCallback; +/** + * Generic function type used as callback for peer events. + * + * @param peerID peer identifier that event relates to + * @param fd event origin + * @ingroup Types + */ +typedef std::function PeerCallback; + +/** + * Generic function type used as callback for serializing and + * saving serialized data to the descriptor. + * + * @param fd descriptor to save the serialized data to + * @param data data to serialize + * @ingroup Types + */ +typedef std::function& data)> SerializeCallback; + +/** + * Generic function type used as callback for reading and parsing data. + * + * @param fd descriptor to read the data from + * @ingroup Types + */ +typedef std::function(ipc::FileDescriptor fd)> ParseCallback; +/** + * Generate an unique message id. + * + * @return new, unique MessageID + * @ingroup Types + */ MessageID getNextMessageID(); + +/** + * Generate an unique peer id. + * + * @return new, unique PeerID + * @ingroup Types + */ PeerID getNextPeerID(); +/** + * Generic type used as a callback function for handling signals. + * @tparam ReceivedDataType type of received data + * @ingroup Types + */ template struct SignalHandler { typedef std::function Date: Tue, 1 Sep 2015 16:14:23 +0200 Subject: [PATCH 07/16] Add colorful output for the CLI [Feature] Colorful CLI output [Cause] N/A [Solution] N/A [Verification] Build, install, run CLI Change-Id: I2123fbd6c5b94ed20eaa278ce00e371e86ff61f0 --- cli/main.cpp | 132 ++++++++++++++++++++++++++++++--------- cli/support/vsm-completion.sh.in | 5 +- 2 files changed, 104 insertions(+), 33 deletions(-) diff --git a/cli/main.cpp b/cli/main.cpp index 537ad69..7320490 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -24,6 +24,7 @@ #include "command-line-interface.hpp" #include "cli-exception.hpp" +#include "utils/ccolor.hpp" #include #include @@ -38,17 +39,48 @@ #include #include #include +#include #include #include using namespace vasum::cli; -namespace fs = boost::filesystem; +namespace fs = boost::filesystem; +namespace po = boost::program_options; namespace { static int interactiveMode = 0; +static bool useColors = false; + +const std::string getStrongColor() +{ + if (useColors) { + return utils::getConsoleEscapeSequence(utils::Attributes::BOLD, utils::Color::RED); + } else { + return ""; + } +} + +const std::string getBoldColor() +{ + if (useColors) { + return utils::getConsoleEscapeSequence(utils::Attributes::BOLD, utils::Color::GREEN); + } else { + return ""; + } +} + +const std::string getDefaultColor() +{ + if (useColors) { + return utils::getConsoleEscapeSequence(utils::Attributes::DEFAULT, utils::Color::DEFAULT); + } else { + return ""; + } +} + std::vector commands = { { create_zone, @@ -257,12 +289,13 @@ void printUsage(std::ostream& out, const std::string& name, unsigned int mode) if (mode == MODE_COMMAND_LINE) { out << "Description:\n" << "\tCommand line tool to manage vasum containers.\n" - << "\tCalled without parameters enters interactive mode.\n" + << "\tCalled without positional parameters enters interactive mode.\n\n" << "Options:\n" - << "\t-h,help print this help\n" - << "\t-f read and execute commands from file\n\n"; + << "\t-h,help print this help\n" + << "\t-f read and execute commands from file\n" + << "\t--color=[=WHEN] colorize the output. WHEN can be never, always or auto\n\n"; } - out << "command can be one of the following:\n"; + out << "Command can be one of the following:\n"; for (const auto& command : commands) { if (command.isAvailable(mode)) { @@ -278,7 +311,8 @@ void printUsage(std::ostream& out, const std::string& name, unsigned int mode) } } - out << "\nType '" << n << "command help' to read about a specific one.\n"; + out << "\nType '" << n << getStrongColor() << "command help" + << getDefaultColor() << "' to read about a specific one.\n"; } int connect() @@ -407,10 +441,11 @@ static int processStream(std::istream& stream) } int rc = EXIT_FAILURE; + const std::string prompt = getBoldColor() + "vsm> " + getDefaultColor(); std::string ln; - while (readline_from("vsm> ", stream, ln)) { + while (readline_from(prompt, stream, ln)) { if (ln.empty() || ln[0] == '#') { //skip empty line or comment - continue; + continue; } std::istringstream iss(ln); @@ -446,7 +481,7 @@ static int processFile(const std::string& fn) void printList(const std::vector& list) { for (const auto& i : list) { - std::cout << i << std::endl; + std::cout << getBoldColor() << i << getDefaultColor() << std::endl; } } @@ -482,23 +517,23 @@ int bashComplMode(int argc, const char *argv[]) return rc; } -int cliMode(const int argc, const char** argv) +int cliMode(const int argc, const char* name, const char** argv) { - if (std::string(argv[1]) == "-h" || std::string(argv[1]) == "help") { - printUsage(std::cout, argv[0], MODE_COMMAND_LINE); - return EXIT_SUCCESS; - } - - if (commandMap.find(argv[1]) == commandMap.end()) { - printUsage(std::cout, argv[0], MODE_COMMAND_LINE); - return EXIT_FAILURE; - } + if (argc > 0) { + if (std::string(argv[0]) == "-h" || std::string(argv[0]) == "help") { + printUsage(std::cout, name, MODE_COMMAND_LINE); + return EXIT_SUCCESS; + } - // pass all the arguments excluding argv[0] - the executable name - Args commandArgs(argv + 1, argv + argc); - int rc = executeCommand(commandArgs, MODE_COMMAND_LINE); + if (commandMap.find(argv[0]) == commandMap.end()) { + printUsage(std::cout, name, MODE_COMMAND_LINE); + return EXIT_FAILURE; + } - return rc; + Args commandArgs(argv, argv + argc); + return executeCommand(commandArgs, MODE_COMMAND_LINE); + } + return EXIT_SUCCESS; } fs::path getHomePath() { @@ -506,6 +541,30 @@ fs::path getHomePath() { return fs::path(h ? h : ""); } +void setColorUsage(const std::string& value) { + if (value == "always") { + useColors = true; + } else if (value == "never"){ + useColors = false; + } else if (value == "auto") { + if (isatty(fileno(stdout)) == 1) { + useColors = true; + } else { + useColors = false; + } + } +} + +bool checkColorOption(const std::string& arg) { + const std::string colorOption = "--color="; + if (arg.find(colorOption) == 0) { + const std::string value = arg.substr(colorOption.length()); + setColorUsage(value); + return true; + } else { + return false; + } +} } // namespace @@ -518,26 +577,39 @@ int main(const int argc, const char *argv[]) int rc = EXIT_FAILURE; if (argc > 1) { - //process arguments if (std::string(argv[1]) == "--bash-completion") { - rc = bashComplMode(argc - 2, argv + 2); + interactiveMode = MODE_COMMAND_LINE; + int argShift; + if (argc > 2) { + argShift = (checkColorOption(argv[2]) ? 1 : 0) + 2; + } else { + argShift = 2; + } + useColors = false; + rc = bashComplMode(argc - argShift, argv + argShift); } else if (std::string(argv[1]) == "-f") { + interactiveMode = MODE_COMMAND_LINE; if (argc < 3) { std::cerr << "Filename expected" << std::endl; rc = EXIT_FAILURE; - } - else { + } else { rc = processFile(std::string(argv[2])); } } else { - rc = cliMode(argc, argv); + int argShift = (checkColorOption(argv[1]) ? 1 : 0) + 1; + + if (argc - argShift > 0) { + interactiveMode = MODE_COMMAND_LINE; + rc = cliMode(argc - argShift, argv[0], argv + argShift); + } } + } - } else { + if (interactiveMode != MODE_COMMAND_LINE) { fs::path historyfile(".vsm_history"); - if (isatty(0) == 1) { + if (isatty(fileno(stdin)) == 1) { fs::path home = getHomePath(); if (!home.empty()) { historyfile = home / historyfile; diff --git a/cli/support/vsm-completion.sh.in b/cli/support/vsm-completion.sh.in index 1177348..74a02a5 100755 --- a/cli/support/vsm-completion.sh.in +++ b/cli/support/vsm-completion.sh.in @@ -2,9 +2,8 @@ [ -z "$BASH_VERSION" ] && return __@PROJECT_NAME@_cli() { - local exe=$1 cur=$2 prev=$3 - words=`@CLI_CODENAME@ --bash-completion "${COMP_WORDS[@]:1}"` - COMPREPLY=($(compgen -W "$words" -- $cur)) + words=`@CLI_CODENAME@ --bash-completion ${COMP_WORDS[COMP_CWORD]}` + COMPREPLY=($(compgen -W "$words" -- ${COMP_WORDS[COMP_CWORD]})) } complete -F __@PROJECT_NAME@_cli vsm -- 2.7.4 From 9c895ec3e042205df243e175a06967a975d8f645 Mon Sep 17 00:00:00 2001 From: Pawel Kubik Date: Mon, 7 Sep 2015 11:17:45 +0200 Subject: [PATCH 08/16] cppcheck fixes [Feature] Small code fixes based on cppcheck [Cause] Minimizing possible runtime errors [Solution] Fix the code using cppcheck suggestions, suppress false-positives [Verification] Compile, run cppcheck Change-Id: I94fab8e50879f78f3ccb503fd18606e9cbfabfb5 --- cli/cli-exception.hpp | 4 +-- client/exception.hpp | 10 +++--- client/vasum-client-impl.cpp | 1 - common/api/ipc-method-result-builder.hpp | 2 +- common/base-exception.hpp | 2 +- common/lxc/exception.hpp | 4 +-- common/utils/exception.hpp | 4 +-- libs/dbus/exception.hpp | 10 +++--- libs/ipc/exception.hpp | 16 +++++----- libs/ipc/internals/finish-request.hpp | 2 +- libs/ipc/internals/method-request.hpp | 6 ++-- libs/ipc/internals/processor.cpp | 26 ++++++++-------- libs/ipc/internals/processor.hpp | 46 ++++++++++++++-------------- libs/ipc/internals/remove-peer-request.hpp | 2 +- libs/ipc/internals/result-builder.hpp | 10 ++---- libs/ipc/internals/send-result-request.hpp | 4 +-- libs/ipc/internals/signal-request.hpp | 6 ++-- libs/ipc/method-result.cpp | 6 ++-- libs/ipc/method-result.hpp | 6 ++-- libs/ipc/service.hpp | 8 ++--- libs/lxcpp/exception.hpp | 22 ++++++------- server/exception.hpp | 14 ++++----- server/zones-manager.cpp | 4 +-- tests/cppcheck/cppcheck.sh | 4 ++- tests/cppcheck/cppcheck.suppress | 23 ++++++++++++-- tests/unit_tests/ipc/ut-ipc.cpp | 2 +- tests/unit_tests/server/ut-zones-manager.cpp | 11 +++---- tests/unit_tests/utils/ut-worker.cpp | 2 +- zone-daemon/exception.hpp | 2 +- 29 files changed, 135 insertions(+), 124 deletions(-) diff --git a/cli/cli-exception.hpp b/cli/cli-exception.hpp index 982f52d..f0d5e0f 100644 --- a/cli/cli-exception.hpp +++ b/cli/cli-exception.hpp @@ -38,12 +38,12 @@ namespace cli { */ struct CliException: public VasumException { - CliException(const std::string& error) : VasumException(error) {} + explicit CliException(const std::string& error) : VasumException(error) {} }; struct IOException: public CliException { - IOException(const std::string& error) : CliException(error) {} + explicit IOException(const std::string& error) : CliException(error) {} }; } // namespace cli diff --git a/client/exception.hpp b/client/exception.hpp index d4be66b..98ebf81 100644 --- a/client/exception.hpp +++ b/client/exception.hpp @@ -37,27 +37,27 @@ namespace vasum { */ struct ClientException: public VasumException { - ClientException(const std::string& error) : VasumException(error) {} + explicit ClientException(const std::string& error) : VasumException(error) {} }; struct IOException: public ClientException { - IOException(const std::string& error) : ClientException(error) {} + explicit IOException(const std::string& error) : ClientException(error) {} }; struct OperationFailedException: public ClientException { - OperationFailedException(const std::string& error) : ClientException(error) {} + explicit OperationFailedException(const std::string& error) : ClientException(error) {} }; struct InvalidArgumentException: public ClientException { - InvalidArgumentException(const std::string& error) : ClientException(error) {} + explicit InvalidArgumentException(const std::string& error) : ClientException(error) {} }; struct InvalidResponseException: public ClientException { - InvalidResponseException(const std::string& error) : ClientException(error) {} + explicit InvalidResponseException(const std::string& error) : ClientException(error) {} }; } diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index e3aca1d..41cc919 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -899,4 +899,3 @@ VsmStatus Client::vsm_clean_up_zones_root() noexcept std::make_shared()); }); } - diff --git a/common/api/ipc-method-result-builder.hpp b/common/api/ipc-method-result-builder.hpp index e9554d0..cad5d8a 100644 --- a/common/api/ipc-method-result-builder.hpp +++ b/common/api/ipc-method-result-builder.hpp @@ -40,7 +40,7 @@ const std::string IPC_CONNECTION_PREFIX = "ipc://"; class IPCMethodResultBuilder: public MethodResultBuilder { public: - IPCMethodResultBuilder(const ipc::MethodResult::Pointer& methodResult); + explicit IPCMethodResultBuilder(const ipc::MethodResult::Pointer& methodResult); ~IPCMethodResultBuilder() {} private: diff --git a/common/base-exception.hpp b/common/base-exception.hpp index 645fa41..05e1fd6 100644 --- a/common/base-exception.hpp +++ b/common/base-exception.hpp @@ -38,7 +38,7 @@ namespace vasum { */ struct VasumException: public std::runtime_error { - VasumException(const std::string& error) : std::runtime_error(error) {} + explicit VasumException(const std::string& error) : std::runtime_error(error) {} }; } // namespace vasum diff --git a/common/lxc/exception.hpp b/common/lxc/exception.hpp index 379fe43..40c7d5f 100644 --- a/common/lxc/exception.hpp +++ b/common/lxc/exception.hpp @@ -37,12 +37,12 @@ namespace vasum { */ struct LxcException: public VasumException { - LxcException(const std::string& error) : VasumException(error) {} + explicit LxcException(const std::string& error) : VasumException(error) {} }; struct KeyNotFoundException: public LxcException { - KeyNotFoundException(const std::string& error) : LxcException(error) {} + explicit KeyNotFoundException(const std::string& error) : LxcException(error) {} }; } // namespace vasum diff --git a/common/utils/exception.hpp b/common/utils/exception.hpp index fda0554..232b090 100644 --- a/common/utils/exception.hpp +++ b/common/utils/exception.hpp @@ -36,12 +36,12 @@ namespace utils { */ struct UtilsException: public std::runtime_error { - UtilsException(const std::string& error) : std::runtime_error(error) {} + explicit UtilsException(const std::string& error) : std::runtime_error(error) {} }; struct ProvisionExistsException: public UtilsException { - ProvisionExistsException(const std::string& error) : UtilsException(error) {} + explicit ProvisionExistsException(const std::string& error) : UtilsException(error) {} }; /** diff --git a/libs/dbus/exception.hpp b/libs/dbus/exception.hpp index a09bdbc..b38877c 100644 --- a/libs/dbus/exception.hpp +++ b/libs/dbus/exception.hpp @@ -34,7 +34,7 @@ namespace dbus { */ struct DbusException: public std::runtime_error { - DbusException(const std::string& error = "") : std::runtime_error(error) {} + explicit DbusException(const std::string& error = "") : std::runtime_error(error) {} }; /** @@ -42,7 +42,7 @@ struct DbusException: public std::runtime_error { */ struct DbusIOException: public DbusException { - DbusIOException(const std::string& error = "") : DbusException(error) {} + explicit DbusIOException(const std::string& error = "") : DbusException(error) {} }; /** @@ -50,7 +50,7 @@ struct DbusIOException: public DbusException { */ struct DbusOperationException: public DbusException { - DbusOperationException(const std::string& error = "") : DbusException(error) {} + explicit DbusOperationException(const std::string& error = "") : DbusException(error) {} }; /** @@ -58,7 +58,7 @@ struct DbusOperationException: public DbusException { */ struct DbusCustomException: public DbusException { - DbusCustomException(const std::string& error = "") : DbusException(error) {} + explicit DbusCustomException(const std::string& error = "") : DbusException(error) {} }; /** @@ -66,7 +66,7 @@ struct DbusCustomException: public DbusException { */ struct DbusInvalidArgumentException: public DbusException { - DbusInvalidArgumentException(const std::string& error = "") : DbusException(error) {} + explicit DbusInvalidArgumentException(const std::string& error = "") : DbusException(error) {} }; } // namespace dbus diff --git a/libs/ipc/exception.hpp b/libs/ipc/exception.hpp index 140619c..3fe7a5b 100644 --- a/libs/ipc/exception.hpp +++ b/libs/ipc/exception.hpp @@ -36,7 +36,7 @@ namespace ipc { * @defgroup IPCException IPCException */ struct IPCException: public std::runtime_error { - IPCException(const std::string& message) + explicit IPCException(const std::string& message) : std::runtime_error(message) {} }; @@ -45,7 +45,7 @@ struct IPCException: public std::runtime_error { * @ingroup IPCException */ struct IPCParsingException: public IPCException { - IPCParsingException(const std::string& message = "Exception during reading/parsing data from the socket") + explicit IPCParsingException(const std::string& message = "Exception during reading/parsing data from the socket") : IPCException(message) {} }; @@ -54,7 +54,7 @@ struct IPCParsingException: public IPCException { * @ingroup IPCException */ struct IPCSerializationException: public IPCException { - IPCSerializationException(const std::string& message = "Exception during writing/serializing data to the socket") + explicit IPCSerializationException(const std::string& message = "Exception during writing/serializing data to the socket") : IPCException(message) {} }; @@ -63,7 +63,7 @@ struct IPCSerializationException: public IPCException { * @ingroup IPCException */ struct IPCPeerDisconnectedException: public IPCException { - IPCPeerDisconnectedException(const std::string& message = "No such peer. Might got disconnected.") + explicit IPCPeerDisconnectedException(const std::string& message = "No such peer. Might got disconnected.") : IPCException(message) {} }; @@ -72,7 +72,7 @@ struct IPCPeerDisconnectedException: public IPCException { * @ingroup IPCException */ struct IPCNaughtyPeerException: public IPCException { - IPCNaughtyPeerException(const std::string& message = "Peer performed a forbidden action.") + explicit IPCNaughtyPeerException(const std::string& message = "Peer performed a forbidden action.") : IPCException(message) {} }; @@ -81,7 +81,7 @@ struct IPCNaughtyPeerException: public IPCException { * @ingroup IPCException */ struct IPCRemovedPeerException: public IPCException { - IPCRemovedPeerException(const std::string& message = "Removing peer") + explicit IPCRemovedPeerException(const std::string& message = "Removing peer") : IPCException(message) {} }; @@ -90,7 +90,7 @@ struct IPCRemovedPeerException: public IPCException { * @ingroup IPCException */ struct IPCClosingException: public IPCException { - IPCClosingException(const std::string& message = "Closing IPC") + explicit IPCClosingException(const std::string& message = "Closing IPC") : IPCException(message) {} }; @@ -99,7 +99,7 @@ struct IPCClosingException: public IPCException { * @ingroup IPCException */ struct IPCTimeoutException: public IPCException { - IPCTimeoutException(const std::string& message) + explicit IPCTimeoutException(const std::string& message) : IPCException(message) {} }; diff --git a/libs/ipc/internals/finish-request.hpp b/libs/ipc/internals/finish-request.hpp index 5a948bd..934c135 100644 --- a/libs/ipc/internals/finish-request.hpp +++ b/libs/ipc/internals/finish-request.hpp @@ -43,4 +43,4 @@ public: } // namespace ipc -#endif // COMMON_IPC_INTERNALS_FINISH_REQUEST_HPP \ No newline at end of file +#endif // COMMON_IPC_INTERNALS_FINISH_REQUEST_HPP diff --git a/libs/ipc/internals/method-request.hpp b/libs/ipc/internals/method-request.hpp index 663cbde..53d9d44 100644 --- a/libs/ipc/internals/method-request.hpp +++ b/libs/ipc/internals/method-request.hpp @@ -41,7 +41,7 @@ public: template static std::shared_ptr create(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process); @@ -54,7 +54,7 @@ public: ResultBuilderHandler process; private: - MethodRequest(const MethodID methodID, const PeerID peerID) + MethodRequest(const MethodID methodID, const PeerID& peerID) : methodID(methodID), peerID(peerID), messageID(getNextMessageID()) @@ -64,7 +64,7 @@ private: template std::shared_ptr MethodRequest::create(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process) { diff --git a/libs/ipc/internals/processor.cpp b/libs/ipc/internals/processor.cpp index fdbcbe8..164d735 100644 --- a/libs/ipc/internals/processor.cpp +++ b/libs/ipc/internals/processor.cpp @@ -92,7 +92,7 @@ Processor::Peers::iterator Processor::getPeerInfoIterator(const FileDescriptor f }); } -Processor::Peers::iterator Processor::getPeerInfoIterator(const PeerID peerID) +Processor::Peers::iterator Processor::getPeerInfoIterator(const PeerID & peerID) { return std::find_if(mPeerInfo.begin(), mPeerInfo.end(), [peerID](const PeerInfo & peerInfo) { return peerID == peerInfo.peerID; @@ -162,16 +162,16 @@ FileDescriptor Processor::getEventFD() } void Processor::sendResult(const MethodID methodID, - const PeerID peerID, - const MessageID messageID, + const PeerID& peerID, + const MessageID& messageID, const std::shared_ptr& data) { auto requestPtr = std::make_shared(methodID, peerID, messageID, data); mRequestQueue.pushFront(Event::SEND_RESULT, requestPtr); } -void Processor::sendError(const PeerID peerID, - const MessageID messageID, +void Processor::sendError(const PeerID& peerID, + const MessageID& messageID, const int errorCode, const std::string& message) { @@ -180,8 +180,8 @@ void Processor::sendError(const PeerID peerID, } void Processor::sendVoid(const MethodID methodID, - const PeerID peerID, - const MessageID messageID) + const PeerID& peerID, + const MessageID& messageID) { auto data = std::make_shared(); auto requestPtr = std::make_shared(methodID, peerID, messageID, data); @@ -208,7 +208,7 @@ PeerID Processor::addPeer(const std::shared_ptr& socketPtr) return requestPtr->peerID; } -void Processor::removePeerSyncInternal(const PeerID peerID, Lock& lock) +void Processor::removePeerSyncInternal(const PeerID& peerID, Lock& lock) { LOGS(mLogPrefix + "Processor removePeer peerID: " << peerID); @@ -329,7 +329,7 @@ bool Processor::handleInput(const FileDescriptor fd) } } -void Processor::onNewSignals(const PeerID peerID, std::shared_ptr& data) +void Processor::onNewSignals(const PeerID& peerID, std::shared_ptr& data) { LOGS(mLogPrefix + "Processor onNewSignals peerID: " << peerID); @@ -338,7 +338,7 @@ void Processor::onNewSignals(const PeerID peerID, std::shared_ptr& data) +void Processor::onErrorSignal(const PeerID&, std::shared_ptr& data) { LOGS(mLogPrefix + "Processor onErrorSignal messageID: " << data->messageID); @@ -351,7 +351,7 @@ void Processor::onErrorSignal(const PeerID, std::shared_ptr signalCallbacks) { LOGS(mLogPrefix + "Processor onRemoteSignal; methodID: " << methodID << " messageID: " << messageID); @@ -422,7 +422,7 @@ bool Processor::onRemoteSignal(Peers::iterator& peerIt, bool Processor::onRemoteMethod(Peers::iterator& peerIt, const MethodID methodID, - const MessageID messageID, + const MessageID& messageID, std::shared_ptr methodCallbacks) { LOGS(mLogPrefix + "Processor onRemoteMethod; methodID: " << methodID << " messageID: " << messageID); diff --git a/libs/ipc/internals/processor.hpp b/libs/ipc/internals/processor.hpp index e383a57..91edfc1 100644 --- a/libs/ipc/internals/processor.hpp +++ b/libs/ipc/internals/processor.hpp @@ -217,8 +217,8 @@ public: * @param data data to send */ void sendResult(const MethodID methodID, - const PeerID peerID, - const MessageID messageID, + const PeerID& peerID, + const MessageID& messageID, const std::shared_ptr& data); /** @@ -229,8 +229,8 @@ public: * @param errorCode code of the error * @param message description of the error */ - void sendError(const PeerID peerID, - const MessageID messageID, + void sendError(const PeerID& peerID, + const MessageID& messageID, const int errorCode, const std::string& message); @@ -242,8 +242,8 @@ public: * @param messageID id of the message to which it replies */ void sendVoid(const MethodID methodID, - const PeerID peerID, - const MessageID messageID); + const PeerID& peerID, + const MessageID& messageID); /** * Removes the callback associated with specific method id. @@ -267,7 +267,7 @@ public: */ template std::shared_ptr callSync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, unsigned int timeoutMS = 5000); @@ -283,7 +283,7 @@ public: */ template MessageID callAsync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process); @@ -352,7 +352,7 @@ private: struct RegisterSignalsProtocolMessage { RegisterSignalsProtocolMessage() = default; - RegisterSignalsProtocolMessage(const std::vector& ids) + explicit RegisterSignalsProtocolMessage(const std::vector& ids) : ids(ids) {} std::vector ids; @@ -365,7 +365,7 @@ private: struct ErrorProtocolMessage { ErrorProtocolMessage() = default; - ErrorProtocolMessage(const MessageID messageID, const int code, const std::string& message) + ErrorProtocolMessage(const MessageID& messageID, const int code, const std::string& message) : messageID(messageID), code(code), message(message) {} MessageID messageID; @@ -461,7 +461,7 @@ private: template MessageID callAsyncInternal(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process); @@ -475,7 +475,7 @@ private: template void signalInternal(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data); // Request handlers @@ -487,28 +487,28 @@ private: bool onFinishRequest(FinishRequest& request); bool onReturnValue(Peers::iterator& peerIt, - const MessageID messageID); + const MessageID& messageID); bool onRemoteMethod(Peers::iterator& peerIt, const MethodID methodID, - const MessageID messageID, + const MessageID& messageID, std::shared_ptr methodCallbacks); bool onRemoteSignal(Peers::iterator& peerIt, const MethodID methodID, - const MessageID messageID, + const MessageID& messageID, std::shared_ptr signalCallbacks); void removePeerInternal(Peers::iterator peerIt, const std::exception_ptr& exceptionPtr); - void removePeerSyncInternal(const PeerID peerID, Lock& lock); + void removePeerSyncInternal(const PeerID& peerID, Lock& lock); - void onNewSignals(const PeerID peerID, + void onNewSignals(const PeerID& peerID, std::shared_ptr& data); - void onErrorSignal(const PeerID peerID, + void onErrorSignal(const PeerID& peerID, std::shared_ptr& data); Peers::iterator getPeerInfoIterator(const FileDescriptor fd); - Peers::iterator getPeerInfoIterator(const PeerID peerID); + Peers::iterator getPeerInfoIterator(const PeerID& peerID); }; @@ -616,7 +616,7 @@ void Processor::setSignalHandler(const MethodID methodID, template MessageID Processor::callAsync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process) { @@ -626,7 +626,7 @@ MessageID Processor::callAsync(const MethodID methodID, template MessageID Processor::callAsyncInternal(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process) { @@ -638,7 +638,7 @@ MessageID Processor::callAsyncInternal(const MethodID methodID, template std::shared_ptr Processor::callSync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, unsigned int timeoutMS) { @@ -692,7 +692,7 @@ std::shared_ptr Processor::callSync(const MethodID methodID, template void Processor::signalInternal(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data) { auto requestPtr = SignalRequest::create(methodID, peerID, data); diff --git a/libs/ipc/internals/remove-peer-request.hpp b/libs/ipc/internals/remove-peer-request.hpp index c9f7ec7..e124227 100644 --- a/libs/ipc/internals/remove-peer-request.hpp +++ b/libs/ipc/internals/remove-peer-request.hpp @@ -37,7 +37,7 @@ public: RemovePeerRequest(const RemovePeerRequest&) = delete; RemovePeerRequest& operator=(const RemovePeerRequest&) = delete; - RemovePeerRequest(const PeerID peerID, + RemovePeerRequest(const PeerID& peerID, const std::shared_ptr& conditionPtr) : peerID(peerID), conditionPtr(conditionPtr) diff --git a/libs/ipc/internals/result-builder.hpp b/libs/ipc/internals/result-builder.hpp index 97134e3..b9c9471 100644 --- a/libs/ipc/internals/result-builder.hpp +++ b/libs/ipc/internals/result-builder.hpp @@ -39,12 +39,12 @@ public: mExceptionPtr(nullptr) {} - ResultBuilder(const std::exception_ptr& exceptionPtr) + explicit ResultBuilder(const std::exception_ptr& exceptionPtr) : mData(nullptr), mExceptionPtr(exceptionPtr) {} - ResultBuilder(const std::shared_ptr& data) + explicit ResultBuilder(const std::shared_ptr& data) : mData(data), mExceptionPtr(nullptr) @@ -68,9 +68,3 @@ typedef std::function ResultBuilderHandler; } // namespace ipc #endif // COMMON_IPC_RESULT_BUILDER_HPP - - - - - - diff --git a/libs/ipc/internals/send-result-request.hpp b/libs/ipc/internals/send-result-request.hpp index a6ed2b4..de512c0 100644 --- a/libs/ipc/internals/send-result-request.hpp +++ b/libs/ipc/internals/send-result-request.hpp @@ -36,8 +36,8 @@ public: SendResultRequest& operator=(const SendResultRequest&) = delete; SendResultRequest(const MethodID methodID, - const PeerID peerID, - const MessageID messageID, + const PeerID& peerID, + const MessageID& messageID, const std::shared_ptr& data) : methodID(methodID), peerID(peerID), diff --git a/libs/ipc/internals/signal-request.hpp b/libs/ipc/internals/signal-request.hpp index 904d3f3..aa597c0 100644 --- a/libs/ipc/internals/signal-request.hpp +++ b/libs/ipc/internals/signal-request.hpp @@ -38,7 +38,7 @@ public: template static std::shared_ptr create(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data); MethodID methodID; @@ -48,7 +48,7 @@ public: SerializeCallback serialize; private: - SignalRequest(const MethodID methodID, const PeerID peerID) + SignalRequest(const MethodID methodID, const PeerID& peerID) : methodID(methodID), peerID(peerID), messageID(getNextMessageID()) @@ -58,7 +58,7 @@ private: template std::shared_ptr SignalRequest::create(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data) { std::shared_ptr request(new SignalRequest(methodID, peerID)); diff --git a/libs/ipc/method-result.cpp b/libs/ipc/method-result.cpp index 97eb450..f110689 100644 --- a/libs/ipc/method-result.cpp +++ b/libs/ipc/method-result.cpp @@ -31,8 +31,8 @@ namespace ipc { MethodResult::MethodResult(Processor& processor, const MethodID methodID, - const MessageID messageID, - const PeerID peerID) + const MessageID& messageID, + const PeerID& peerID) : mProcessor(processor), mMethodID(methodID), mPeerID(peerID), @@ -54,7 +54,7 @@ void MethodResult::setError(const int code, const std::string& message) mProcessor.sendError(mPeerID, mMessageID, code, message); } -PeerID MethodResult::getPeerID() +PeerID MethodResult::getPeerID() const { return mPeerID; } diff --git a/libs/ipc/method-result.hpp b/libs/ipc/method-result.hpp index c1729f7..c6fce37 100644 --- a/libs/ipc/method-result.hpp +++ b/libs/ipc/method-result.hpp @@ -43,8 +43,8 @@ public: MethodResult(Processor& processor, const MethodID methodID, - const MessageID messageID, - const PeerID peerID); + const MessageID& messageID, + const PeerID& peerID); template @@ -55,7 +55,7 @@ public: void setVoid(); void setError(const int code, const std::string& message); - PeerID getPeerID(); + PeerID getPeerID() const; private: Processor& mProcessor; diff --git a/libs/ipc/service.hpp b/libs/ipc/service.hpp index a5f7c86..6d953dd 100644 --- a/libs/ipc/service.hpp +++ b/libs/ipc/service.hpp @@ -191,7 +191,7 @@ public: */ template std::shared_ptr callSync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, unsigned int timeoutMS = 5000); @@ -208,7 +208,7 @@ public: */ template void callAsync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& resultCallback); @@ -251,7 +251,7 @@ void Service::setSignalHandler(const MethodID methodID, template std::shared_ptr Service::callSync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, unsigned int timeoutMS) { @@ -263,7 +263,7 @@ std::shared_ptr Service::callSync(const MethodID methodID, template void Service::callAsync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& resultCallback) { diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index af81779..7764282 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -32,57 +32,57 @@ namespace lxcpp { * Base class for exceptions in lxcpp */ struct Exception: public std::runtime_error { - Exception(const std::string& message) + explicit Exception(const std::string& message) : std::runtime_error(message) {} }; struct NotImplementedException: public Exception { - NotImplementedException(const std::string& message = "Functionality not yet implemented") + explicit NotImplementedException(const std::string& message = "Functionality not yet implemented") : Exception(message) {} }; struct ProcessSetupException: public Exception { - ProcessSetupException(const std::string& message = "Error while setting up a process") + explicit ProcessSetupException(const std::string& message = "Error while setting up a process") : Exception(message) {} }; struct FileSystemSetupException: public Exception { - FileSystemSetupException(const std::string& message = "Error during a file system operation") + explicit FileSystemSetupException(const std::string& message = "Error during a file system operation") : Exception(message) {} }; struct EnvironmentSetupException: public Exception { - EnvironmentSetupException(const std::string& message = "Error during handling environment variables") + explicit EnvironmentSetupException(const std::string& message = "Error during handling environment variables") : Exception(message) {} }; struct CredentialSetupException: public Exception { - CredentialSetupException(const std::string& message = "Error during handling environment variables") + explicit CredentialSetupException(const std::string& message = "Error during handling environment variables") : Exception(message) {} }; struct CapabilitySetupException: public Exception { - CapabilitySetupException(const std::string& message = "Error during a capability operation") + explicit CapabilitySetupException(const std::string& message = "Error during a capability operation") : Exception(message) {} }; struct BadArgument: public Exception { - BadArgument(const std::string& message = "Bad argument passed") + explicit BadArgument(const std::string& message = "Bad argument passed") : Exception(message) {} }; struct NoSuchValue: public Exception { - NoSuchValue(const std::string& message = "Value not found") + explicit NoSuchValue(const std::string& message = "Value not found") : Exception(message) {} }; struct NetworkException : public Exception { - NetworkException (const std::string& message = "Error during setting up a network") + explicit NetworkException (const std::string& message = "Error during setting up a network") : Exception(message) {} }; struct ConfigureException: public Exception { - ConfigureException(const std::string& message = "Error while configuring a container") + explicit ConfigureException(const std::string& message = "Error while configuring a container") : Exception(message) {} }; diff --git a/server/exception.hpp b/server/exception.hpp index e1b3be4..e72df76 100644 --- a/server/exception.hpp +++ b/server/exception.hpp @@ -37,7 +37,7 @@ namespace vasum { */ struct ServerException: public VasumException { - ServerException(const std::string& error) : VasumException(error) {} + explicit ServerException(const std::string& error) : VasumException(error) {} }; /** @@ -46,7 +46,7 @@ struct ServerException: public VasumException { */ struct ZoneOperationException: public ServerException { - ZoneOperationException(const std::string& error) : ServerException(error) {} + explicit ZoneOperationException(const std::string& error) : ServerException(error) {} }; /** @@ -54,7 +54,7 @@ struct ZoneOperationException: public ServerException { */ struct InvalidZoneIdException : public ServerException { - InvalidZoneIdException(const std::string& error) : ServerException(error) {} + explicit InvalidZoneIdException(const std::string& error) : ServerException(error) {} }; /** @@ -62,7 +62,7 @@ struct InvalidZoneIdException : public ServerException { */ struct ZoneConnectionException: public ServerException { - ZoneConnectionException(const std::string& error) : ServerException(error) {} + explicit ZoneConnectionException(const std::string& error) : ServerException(error) {} }; /** @@ -70,7 +70,7 @@ struct ZoneConnectionException: public ServerException { */ struct HostConnectionException: public ServerException { - HostConnectionException(const std::string& error) : ServerException(error) {} + explicit HostConnectionException(const std::string& error) : ServerException(error) {} }; /** @@ -79,12 +79,12 @@ struct HostConnectionException: public ServerException { */ struct InputMonitorException: public ServerException { - InputMonitorException(const std::string& error) : ServerException(error) {} + explicit InputMonitorException(const std::string& error) : ServerException(error) {} }; struct TimeoutException: public InputMonitorException { - TimeoutException(const std::string& error) : InputMonitorException (error) {} + explicit TimeoutException(const std::string& error) : InputMonitorException (error) {} }; } diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 55e63f5..baf3ed1 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -1266,7 +1266,7 @@ void ZonesManager::createZone(const std::string& id, } catch (std::runtime_error& e) { LOGE("Generate config failed: " << e.what()); utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr)); - throw e; + throw; } LOGT("Creating new zone"); @@ -1275,7 +1275,7 @@ void ZonesManager::createZone(const std::string& id, } catch (std::runtime_error& e) { LOGE("Creating new zone failed: " << e.what()); utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr)); - throw e; + throw; } mDynamicConfig.zoneIds.push_back(id); diff --git a/tests/cppcheck/cppcheck.sh b/tests/cppcheck/cppcheck.sh index b8bb637..bbe96b5 100755 --- a/tests/cppcheck/cppcheck.sh +++ b/tests/cppcheck/cppcheck.sh @@ -11,5 +11,7 @@ OPT+=" -I common" OPT+=" -I libs" OPT+=" -I client" OPT+=" -I server" +OPT+=" -I tests/unit_tests" +OPT+=" -I tests/unit_tests/socket_test_service" OPT+=" -U__NR_capset" -cppcheck ${OPT} --template=gcc ./ 1>/dev/null +cppcheck ${OPT} --template=gcc $@ ./ 1>/dev/null diff --git a/tests/cppcheck/cppcheck.suppress b/tests/cppcheck/cppcheck.suppress index d3b098f..8d7380b 100644 --- a/tests/cppcheck/cppcheck.suppress +++ b/tests/cppcheck/cppcheck.suppress @@ -1,7 +1,26 @@ // public API functions (or write tests to use them all) unusedFunction:wrapper/wrapper-compatibility.cpp unusedFunction:wrapper/wrapper.cpp +unusedFunction:libs/config/kvstore.cpp +unusedFunction:libs/ipc/internals/processor.cpp +unusedFunction:server/zones-manager.cpp +unusedFunction:libs/lxcpp/container-impl.cpp +unusedFunction:libs/lxcpp/filesystem.cpp +unusedFunction:libs/lxcpp/network.cpp +unusedFunction:libs/lxcpp/network-config.cpp +unusedFunction:client/vasum-client.cpp +unusedFunction:common/netlink/netlink-message.cpp +unusedFunction:common/utils/fd-utils.cpp +unusedFunction:server/zone.cpp -// lambda not recognized to catch exception (v1.68) -exceptThrowInNoexecptFunction:client/vasum-client-impl.cpp +// lambda not recognized to catch exception (v1.69) +throwInNoexceptFunction:client/vasum-client-impl.cpp +// complains that all constructors with 1 argument should be explicit +noExplicitConstructor + +// required for C abstraction +unusedStructMember:common/utils/initctl.cpp + +// functions called by external utilities +unusedFunction:tests/unit_tests/ut.cpp diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index 853faa2..5ba540e 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -237,7 +237,7 @@ void testEcho(Client& c, const MethodID methodID) BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } -void testEcho(Service& s, const MethodID methodID, const PeerID peerID) +void testEcho(Service& s, const MethodID methodID, const PeerID& peerID) { std::shared_ptr sentData(new SendData(56)); std::shared_ptr recvData = s.callSync(methodID, peerID, sentData, TIMEOUT); diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 819da53..6d6a71d 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -163,7 +163,7 @@ public: void signalSubscribe(const DbusConnection::SignalCallback& callback) { - mClient->signalSubscribe(callback, isHost() ? api::dbus::BUS_NAME : api::dbus::BUS_NAME); + mClient->signalSubscribe(callback, api::dbus::BUS_NAME); } void callSwitchToDefault() @@ -225,12 +225,9 @@ public: interface.c_str(), method.c_str(), parameters); - GVariantPtr result = mClient->callMethod(isHost() ? api::dbus::BUS_NAME : - api::dbus::BUS_NAME, - isHost() ? api::dbus::OBJECT_PATH : - api::dbus::OBJECT_PATH, - isHost() ? api::dbus::INTERFACE : - api::dbus::INTERFACE, + GVariantPtr result = mClient->callMethod(api::dbus::BUS_NAME, + api::dbus::OBJECT_PATH, + api::dbus::INTERFACE, api::dbus::METHOD_PROXY_CALL, packedParameters, "(v)"); diff --git a/tests/unit_tests/utils/ut-worker.cpp b/tests/unit_tests/utils/ut-worker.cpp index 52c14fd..b05aef0 100644 --- a/tests/unit_tests/utils/ut-worker.cpp +++ b/tests/unit_tests/utils/ut-worker.cpp @@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE(NoCopy) Task(Task&& r) : count(r.count) {} Task& operator=(const Task&) = delete; Task& operator=(Task&&) = delete; - void operator() () {} + void operator() () const {} }; diff --git a/zone-daemon/exception.hpp b/zone-daemon/exception.hpp index 5fcf54d..9889e62 100644 --- a/zone-daemon/exception.hpp +++ b/zone-daemon/exception.hpp @@ -37,7 +37,7 @@ namespace zone_daemon { */ struct ZoneDaemonException: public VasumException { - ZoneDaemonException(const std::string& error) : VasumException(error) {} + explicit ZoneDaemonException(const std::string& error) : VasumException(error) {} }; -- 2.7.4 From ded590f480be25eb3b8c593187606f9859c942ee Mon Sep 17 00:00:00 2001 From: Pawel Kubik Date: Wed, 9 Sep 2015 17:27:08 +0200 Subject: [PATCH 09/16] Static common library [Feature] Static common library [Cause] Need for cleaner dependency management [Solution] Rules for building static common library, linking it with other binaries instead of manually adding sources [Verification] Build, install, run tests and main executables Change-Id: I6eccf5a706b88ca4576e5bfc31b73ebe87177ff5 --- CMakeLists.txt | 2 +- cli/CMakeLists.txt | 10 ++++------ client/CMakeLists.txt | 9 ++++----- common/CMakeLists.txt | 29 +++++++++++++++++++++++++++++ libs/dbus/CMakeLists.txt | 15 +++++---------- libs/ipc/CMakeLists.txt | 14 +++++--------- libs/logger/CMakeLists.txt | 15 ++++++--------- libs/lxcpp/CMakeLists.txt | 23 ++++++----------------- server/CMakeLists.txt | 8 ++++---- tests/unit_tests/CMakeLists.txt | 21 ++++++++++++--------- wrapper/CMakeLists.txt | 12 ++++-------- zone-daemon/CMakeLists.txt | 7 +++---- 12 files changed, 83 insertions(+), 82 deletions(-) create mode 100644 common/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 9823735..5b98eee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,6 +188,7 @@ SET(VSM_CONFIG_INSTALL_DIR ${SYSCONF_INSTALL_DIR}/vasum) SET(VSM_SERVER_IPC_SOCKET_PATH ${RUN_DIR}/vasum.socket) 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) @@ -204,4 +205,3 @@ ENDIF(NOT WITHOUT_DBUS) ADD_SUBDIRECTORY(${TESTS_FOLDER}) ADD_SUBDIRECTORY(${CLI_FOLDER}) ADD_SUBDIRECTORY(${WRAPPER_FOLDER}) - diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 0f4fbfe..478cc25 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -19,14 +19,14 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the command line interface...") -FILE(GLOB cli_SRCS *.cpp *.hpp - ${COMMON_FOLDER}/utils/c-array.cpp - ${COMMON_FOLDER}/utils/c-array.hpp) +FILE(GLOB cli_SRCS *.cpp *.hpp) ## Setup target ################################################################ SET(CLI_CODENAME "vsm") ADD_EXECUTABLE(${CLI_CODENAME} ${cli_SRCS}) +ADD_DEPENDENCIES(${CLI_CODENAME} Common ${PROJECT_NAME}-client Ipc) + ## Readline detection ########################################################## FIND_PATH(READLINE_INCLUDE_DIR readline/readline.h @@ -46,11 +46,9 @@ INCLUDE_DIRECTORIES(${READLINE_INCLUDE_DIRS}) TARGET_LINK_LIBRARIES(${CLI_CODENAME} ${READLINE_LIBRARIES}) ## Link libraries ############################################################## -PKG_CHECK_MODULES(LIB_DEPS REQUIRED vasum) - INCLUDE_DIRECTORIES(${CLIENT_FOLDER}) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) -TARGET_LINK_LIBRARIES(${CLI_CODENAME} ${PROJECT_NAME}-client ${LIB_DEPS_LIBRARIES} Ipc) +TARGET_LINK_LIBRARIES(${CLI_CODENAME} Common ${PROJECT_NAME}-client ${LIB_DEPS_LIBRARIES} Ipc) CONFIGURE_FILE(support/vsm-completion.sh.in ${CMAKE_BINARY_DIR}/vsm-completion.sh diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index f0d1828..e4e9ca5 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -22,9 +22,6 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the Client...") FILE(GLOB project_SRCS *.cpp *.hpp *.h) -FILE(GLOB common_SRCS ${COMMON_FOLDER}/utils/*.hpp ${COMMON_FOLDER}/utils/*.cpp - ${COMMON_FOLDER}/*.hpp ${COMMON_FOLDER}/*.cpp) - SET(_LIB_VERSION_ "${VERSION}") SET(_LIB_SOVERSION_ "0") SET(PC_FILE "${PROJECT_NAME}.pc") @@ -36,12 +33,14 @@ SET(PC_FILE "${PROJECT_NAME}.pc") ADD_DEFINITIONS(-fvisibility=hidden) ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${project_SRCS} ${common_SRCS}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${project_SRCS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} COMPILE_DEFINITIONS HOST_IPC_SOCKET="${VSM_SERVER_IPC_SOCKET_PATH}") +ADD_DEPENDENCIES(${PROJECT_NAME} Common Config Ipc) + ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS system filesystem) PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0) @@ -51,7 +50,7 @@ INCLUDE_DIRECTORIES(${LIBS_FOLDER}) INCLUDE_DIRECTORIES(${IPC_FOLDER}) INCLUDE_DIRECTORIES(${SERVER_FOLDER}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${LIB_DEPS_LIBRARIES} ${Boost_LIBRARIES} Config Ipc) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${LIB_DEPS_LIBRARIES} ${Boost_LIBRARIES} Config Ipc) IF(NOT WITHOUT_DBUS) TARGET_LINK_LIBRARIES(${PROJECT_NAME} SimpleDbus) ENDIF(NOT WITHOUT_DBUS) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt new file mode 100644 index 0000000..8534a46 --- /dev/null +++ b/common/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +# +# 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 CMakeLists.txt +# @author Pawel Kubik (p.kubik@samsung.com) +# + +MESSAGE(STATUS "") +MESSAGE(STATUS "Generating makefile for the libCommon...") +FILE(GLOB_RECURSE SRCS *.cpp *.hpp) + +## Setup target ################################################################ +ADD_LIBRARY(Common STATIC ${SRCS}) + +PKG_CHECK_MODULES(COMMON_DEPS REQUIRED glib-2.0) + +INCLUDE_DIRECTORIES(SYSTEM ${COMMON_FOLDER} ${LIBS_FOLDER} ${COMMON_DEPS_INCLUDE_DIRS}) diff --git a/libs/dbus/CMakeLists.txt b/libs/dbus/CMakeLists.txt index 840b3b4..6045c04 100644 --- a/libs/dbus/CMakeLists.txt +++ b/libs/dbus/CMakeLists.txt @@ -22,14 +22,7 @@ PROJECT(SimpleDbus) MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the libSimpleDbus...") FILE(GLOB HEADERS *.hpp) -FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/callback-guard.hpp - ${COMMON_FOLDER}/utils/scoped-gerror.hpp - ${COMMON_FOLDER}/utils/glib-utils.hpp - ${COMMON_FOLDER}/utils/callback-wrapper.hpp) -FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/callback-guard.cpp - ${COMMON_FOLDER}/utils/scoped-gerror.cpp - ${COMMON_FOLDER}/utils/glib-utils.cpp - ${COMMON_FOLDER}/utils/callback-wrapper.cpp) +FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/callback-guard.hpp) FILE(GLOB SRCS *.cpp *.hpp) SET(_LIB_VERSION_ "${VERSION}") @@ -37,18 +30,20 @@ SET(_LIB_SOVERSION_ "0") SET(PC_FILE "lib${PROJECT_NAME}.pc") ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_UTILS}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} ) +ADD_DEPENDENCIES(${PROJECT_NAME} Common) + ## Link libraries ############################################################## PKG_CHECK_MODULES(DBUS_DEPS REQUIRED glib-2.0 gio-2.0) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${DBUS_DEPS_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${DBUS_DEPS_LIBRARIES} Logger) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${DBUS_DEPS_LIBRARIES} Logger) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY) diff --git a/libs/ipc/CMakeLists.txt b/libs/ipc/CMakeLists.txt index 854e0de..9e1e6f9 100644 --- a/libs/ipc/CMakeLists.txt +++ b/libs/ipc/CMakeLists.txt @@ -25,29 +25,25 @@ MESSAGE(STATUS "Generating makefile for the libIpc...") FILE(GLOB HEADERS *.hpp) FILE(GLOB HEADERS_INTERNALS internals/*.hpp) FILE(GLOB HEADERS_EPOLL epoll/*.hpp) -FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/fd-utils.hpp - ${COMMON_FOLDER}/utils/eventfd.hpp - ${COMMON_FOLDER}/utils/exception.hpp +FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/eventfd.hpp ${COMMON_FOLDER}/utils/callback-guard.hpp) FILE(GLOB SRCS *.cpp) FILE(GLOB SRCS_INTERNALS internals/*.cpp) FILE(GLOB SRCS_EPOLL epoll/*.cpp) -FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/fd-utils.cpp - ${COMMON_FOLDER}/utils/eventfd.cpp - ${COMMON_FOLDER}/utils/exception.cpp - ${COMMON_FOLDER}/utils/callback-guard.cpp) SET(_LIB_VERSION_ "${VERSION}") SET(_LIB_SOVERSION_ "0") SET(PC_FILE "lib${PROJECT_NAME}.pc") ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_INTERNALS} ${SRCS_UTILS} ${SRCS_EPOLL}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_INTERNALS} ${SRCS_EPOLL}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} ) +ADD_DEPENDENCIES(${PROJECT_NAME} Common) + ## Link libraries ############################################################## IF(NOT WITHOUT_SYSTEMD) PKG_CHECK_MODULES(IPC_DEPS REQUIRED libsystemd-daemon uuid) @@ -56,7 +52,7 @@ ENDIF(NOT WITHOUT_SYSTEMD) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${DBUS_DEPS_INCLUDE_DIRS} ${IPC_DEPS_INCLUDE_DIRS} ${CONFIG_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${IPC_DEPS_LIBRARIES} Logger Config) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${IPC_DEPS_LIBRARIES} Logger Config) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY) diff --git a/libs/logger/CMakeLists.txt b/libs/logger/CMakeLists.txt index 6a65b34..b44a876 100644 --- a/libs/logger/CMakeLists.txt +++ b/libs/logger/CMakeLists.txt @@ -21,22 +21,22 @@ PROJECT(Logger) MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the libLogger...") -FILE(GLOB HEADERS *.hpp) -FILE(GLOB SRCS *.cpp *.hpp) -FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/ccolor.hpp) -FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/ccolor.cpp) +FILE(GLOB HEADERS *.hpp) +FILE(GLOB SRCS *.cpp *.hpp) SET(_LIB_VERSION_ "${VERSION}") SET(_LIB_SOVERSION_ "0") SET(PC_FILE "lib${PROJECT_NAME}.pc") ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_UTILS}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} ) +ADD_DEPENDENCIES(${PROJECT_NAME} Common) + ## Link libraries ############################################################## IF(NOT WITHOUT_SYSTEMD) PKG_CHECK_MODULES(LOGGER_DEPS REQUIRED libsystemd-journal) @@ -44,7 +44,7 @@ ENDIF(NOT WITHOUT_SYSTEMD) INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${LOGGER_DEPS_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${LOGGER_DEPS_LIBRARIES}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${LOGGER_DEPS_LIBRARIES}) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY) @@ -59,6 +59,3 @@ INSTALL(TARGETS ${PROJECT_NAME} INSTALL(FILES ${HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/vasum-tools/logger) - -INSTALL(FILES ${HEADERS_UTILS} - DESTINATION ${INCLUDE_INSTALL_DIR}/vasum-tools/logger/utils) diff --git a/libs/lxcpp/CMakeLists.txt b/libs/lxcpp/CMakeLists.txt index c76de74..203ddd3 100644 --- a/libs/lxcpp/CMakeLists.txt +++ b/libs/lxcpp/CMakeLists.txt @@ -21,22 +21,11 @@ PROJECT(lxcpp) MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the liblxcpp...") -FILE(GLOB HEADERS *.hpp) -FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/fd-utils.hpp - ${COMMON_FOLDER}/utils/exception.hpp - ${COMMON_FOLDER}/utils/channel.hpp - ${COMMON_FOLDER}/utils/environment.hpp - ${COMMON_FOLDER}/utils/execute.hpp) -FILE(GLOB HEADERS_NETLINK ${COMMON_FOLDER}/netlink/*.hpp) +FILE(GLOB HEADERS *.hpp) +FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/channel.hpp) FILE(GLOB HEADERS_COMMANDS commands/*.hpp) FILE(GLOB SRCS *.cpp *.hpp) -FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/fd-utils.cpp - ${COMMON_FOLDER}/utils/exception.cpp - ${COMMON_FOLDER}/utils/channel.cpp - ${COMMON_FOLDER}/utils/environment.cpp - ${COMMON_FOLDER}/utils/execute.cpp) -FILE(GLOB SRCS_NETLINK ${COMMON_FOLDER}/netlink/*.cpp) FILE(GLOB SRCS_COMMANDS commands/*.cpp) SET(_LIB_VERSION_ "${VERSION}") @@ -44,17 +33,19 @@ SET(_LIB_SOVERSION_ "0") SET(PC_FILE "lib${PROJECT_NAME}.pc") ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_UTILS} ${SRCS_NETLINK} ${SRCS_COMMANDS}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_COMMANDS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} ) +ADD_DEPENDENCIES(${PROJECT_NAME} Common Logger) + ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS system filesystem) INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${Boost_LIBRARIES} Logger) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${Boost_LIBRARIES} Logger) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY) @@ -71,7 +62,5 @@ INSTALL(FILES ${HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp) INSTALL(FILES ${HEADERS_UTILS} DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/utils) -INSTALL(FILES ${HEADERS_NETLINK} - DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/netlink) INSTALL(FILES ${HEADERS_COMMANDS} DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/commands) diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 58c50f6..86b4f79 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -19,14 +19,14 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the Server...") -FILE(GLOB project_SRCS *.cpp *.hpp) -FILE(GLOB_RECURSE common_SRCS ${COMMON_FOLDER}/*.cpp ${COMMON_FOLDER}/*.hpp) +FILE(GLOB project_SRCS *.cpp *.hpp) ## Setup target ################################################################ SET(SERVER_CODENAME "${PROJECT_NAME}-server") -ADD_EXECUTABLE(${SERVER_CODENAME} ${project_SRCS} ${common_SRCS}) +ADD_EXECUTABLE(${SERVER_CODENAME} ${project_SRCS}) +ADD_DEPENDENCIES(${SERVER_CODENAME} Common Logger Config Ipc) ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS program_options system filesystem regex) @@ -43,7 +43,7 @@ SET_TARGET_PROPERTIES(${SERVER_CODENAME} PROPERTIES LINK_FLAGS "-pthread" ) -TARGET_LINK_LIBRARIES(${SERVER_CODENAME} ${SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} Logger Config Ipc) +TARGET_LINK_LIBRARIES(${SERVER_CODENAME} Common ${SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} Logger Config Ipc) IF(NOT WITHOUT_DBUS) TARGET_LINK_LIBRARIES(${SERVER_CODENAME} SimpleDbus) ENDIF(NOT WITHOUT_DBUS) diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index b532336..1c05576 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -20,7 +20,6 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the Unit Tests...") FILE(GLOB_RECURSE project_SRCS *.cpp *.hpp) -FILE(GLOB_RECURSE common_SRCS ${COMMON_FOLDER}/*.cpp ${COMMON_FOLDER}/*.hpp) FILE(GLOB server_SRCS ${SERVER_FOLDER}/*.cpp ${SERVER_FOLDER}/*.hpp) FILE(GLOB client_SRCS ${CLIENT_FOLDER}/*.cpp ${CLIENT_FOLDER}/*.h) FILE(GLOB socket_test_SRCS ${SOCKET_TEST_FOLDER}/*.cpp ${SOCKET_TEST_FOLDER}/*.hpp) @@ -35,20 +34,25 @@ LIST(REMOVE_ITEM project_SRCS ${socket_test_SRCS} ${lxcpp_test_SRCS}) ## Setup target ################################################################ SET(UT_SERVER_CODENAME "${PROJECT_NAME}-server-unit-tests") -ADD_EXECUTABLE(${UT_SERVER_CODENAME} ${project_SRCS} ${common_SRCS} ${server_SRCS} ${client_SRCS}) +ADD_EXECUTABLE(${UT_SERVER_CODENAME} ${project_SRCS} ${server_SRCS} ${client_SRCS}) +ADD_DEPENDENCIES(${UT_SERVER_CODENAME} ${PROJECT_NAME}-server) ## A fake target to test vasum-client C API -ADD_EXECUTABLE("vasum-client-c-api-compile-test" client/client-c-api-compile-test.c) +SET(CLIENT_C_API_COMPILE_TEST "vasum-client-c-api-compile-test") +ADD_EXECUTABLE(${CLIENT_C_API_COMPILE_TEST} client/client-c-api-compile-test.c) +ADD_DEPENDENCIES(${CLIENT_C_API_COMPILE_TEST} ${PROJECT_NAME}-client) ## A fake target to test lxcpp API -ADD_EXECUTABLE("lxcpp-api-compile-test" lxcpp/lxcpp-api-compile-test.cpp) -TARGET_LINK_LIBRARIES("lxcpp-api-compile-test" lxcpp) +SET(LXCPP_API_COMPILE_TEST "lxcpp-api-compile-test") +ADD_EXECUTABLE(${LXCPP_API_COMPILE_TEST} lxcpp/lxcpp-api-compile-test.cpp) +ADD_DEPENDENCIES(${LXCPP_API_COMPILE_TEST} lxcpp) +TARGET_LINK_LIBRARIES(${LXCPP_API_COMPILE_TEST} lxcpp) IF(NOT WITHOUT_SYSTEMD) SET(SOCKET_TEST_CODENAME "${PROJECT_NAME}-socket-test") ## A stub mini-service to test socket functionality -ADD_EXECUTABLE(${SOCKET_TEST_CODENAME} ${socket_test_SRCS} ${common_SRCS} ${client_SRCS}) +ADD_EXECUTABLE(${SOCKET_TEST_CODENAME} ${socket_test_SRCS} ${client_SRCS}) ENDIF(NOT WITHOUT_SYSTEMD) ## Link libraries ############################################################## @@ -65,7 +69,7 @@ SET_TARGET_PROPERTIES(${UT_SERVER_CODENAME} PROPERTIES LINK_FLAGS "-pthread" ) -TARGET_LINK_LIBRARIES(${UT_SERVER_CODENAME} ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} +TARGET_LINK_LIBRARIES(${UT_SERVER_CODENAME} Common ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} Logger Config Ipc lxcpp) IF(NOT WITHOUT_DBUS) TARGET_LINK_LIBRARIES(${UT_SERVER_CODENAME} SimpleDbus) @@ -78,7 +82,7 @@ SET_TARGET_PROPERTIES(${SOCKET_TEST_CODENAME} PROPERTIES LINK_FLAGS "-pthread" ) -TARGET_LINK_LIBRARIES(${SOCKET_TEST_CODENAME} ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} +TARGET_LINK_LIBRARIES(${SOCKET_TEST_CODENAME} Common ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} Logger Config Ipc) IF(NOT WITHOUT_DBUS) TARGET_LINK_LIBRARIES(${SOCKET_TEST_CODENAME} SimpleDbus) @@ -100,4 +104,3 @@ INSTALL(TARGETS ${UT_SERVER_CODENAME} DESTINATION bin) IF(NOT WITHOUT_SYSTEMD) INSTALL(TARGETS ${SOCKET_TEST_CODENAME} DESTINATION bin) ENDIF(NOT WITHOUT_SYSTEMD) - diff --git a/wrapper/CMakeLists.txt b/wrapper/CMakeLists.txt index 3346df8..7e70765 100644 --- a/wrapper/CMakeLists.txt +++ b/wrapper/CMakeLists.txt @@ -27,12 +27,6 @@ FILE(GLOB wrapper_SRCS *.cpp *.hpp *.h ${CLIENT_FOLDER}/host-ipc-connection.hpp ${CLIENT_FOLDER}/host-ipc-connection.cpp ${CLIENT_FOLDER}/utils.hpp ${CLIENT_FOLDER}/utils.cpp) -FILE(GLOB common_SRCS ${COMMON_FOLDER}/epoll/*.hpp ${COMMON_FOLDER}/epoll/*.cpp - ${COMMON_FOLDER}/ipc/*.hpp ${COMMON_FOLDER}/ipc/*.cpp - ${COMMON_FOLDER}/ipc/internals/*.hpp ${COMMON_FOLDER}/ipc/internals/*.cpp - ${COMMON_FOLDER}/utils/*.hpp ${COMMON_FOLDER}/utils/*.cpp - ${COMMON_FOLDER}/*.hpp ${COMMON_FOLDER}/*.cpp) - SET(_LIB_VERSION_ "${VERSION}") SET(_LIB_SOVERSION_ "0") SET(PC_FILE "${PROJECT_NAME}.pc") @@ -44,12 +38,14 @@ SET(PC_FILE "${PROJECT_NAME}.pc") ADD_DEFINITIONS(-fvisibility=hidden) ADD_DEFINITIONS(-D__STDC_FORMAT_MACROS) -ADD_LIBRARY(${PROJECT_NAME} SHARED ${wrapper_SRCS} ${common_SRCS}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${wrapper_SRCS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} COMPILE_DEFINITIONS HOST_IPC_SOCKET="${VSM_SERVER_IPC_SOCKET_PATH}") +ADD_DEPENDENCIES(${PROJECT_NAME} Common Config Ipc) + ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS system filesystem) PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0) @@ -59,7 +55,7 @@ INCLUDE_DIRECTORIES(${LIBS_FOLDER}) INCLUDE_DIRECTORIES(${SERVER_FOLDER}) INCLUDE_DIRECTORIES(${CLIENT_FOLDER}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${LIB_DEPS_LIBRARIES} ${Boost_LIBRARIES} Config Ipc) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${LIB_DEPS_LIBRARIES} ${Boost_LIBRARIES} Config Ipc) IF(NOT WITHOUT_DBUS) TARGET_LINK_LIBRARIES(${PROJECT_NAME} SimpleDbus) ENDIF(NOT WITHOUT_DBUS) diff --git a/zone-daemon/CMakeLists.txt b/zone-daemon/CMakeLists.txt index 7171eee..0437a4f 100644 --- a/zone-daemon/CMakeLists.txt +++ b/zone-daemon/CMakeLists.txt @@ -20,13 +20,12 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the Zone Daemon...") FILE(GLOB project_SRCS *.cpp *.hpp) -FILE(GLOB common_SRCS ${COMMON_FOLDER}/utils/*.cpp ${COMMON_FOLDER}/utils/*.hpp - ${COMMON_FOLDER}/*.cpp) ## Setup target ################################################################ SET(ZONE_DAEMON_CODENAME "${PROJECT_NAME}-zone-daemon") -ADD_EXECUTABLE(${ZONE_DAEMON_CODENAME} ${project_SRCS} ${common_SRCS}) +ADD_EXECUTABLE(${ZONE_DAEMON_CODENAME} ${project_SRCS}) +ADD_DEPENDENCIES(${ZONE_DAEMON_CODENAME} Common Logger SimpleDbus Ipc) ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS program_options system filesystem) @@ -42,7 +41,7 @@ SET_TARGET_PROPERTIES(${ZONE_DAEMON_CODENAME} PROPERTIES LINK_FLAGS "-pthread" ) -TARGET_LINK_LIBRARIES(${ZONE_DAEMON_CODENAME} ${ZONE_DAEMON_DEPS_LIBRARIES} +TARGET_LINK_LIBRARIES(${ZONE_DAEMON_CODENAME} Common ${ZONE_DAEMON_DEPS_LIBRARIES} ${Boost_LIBRARIES} Logger SimpleDbus Ipc) -- 2.7.4 From 54a315716b6773507cc0bffa236f10f11c5d2400 Mon Sep 17 00:00:00 2001 From: Pawel Kubik Date: Mon, 14 Sep 2015 12:20:36 +0200 Subject: [PATCH 10/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 11/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 12/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 13/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 14/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 15/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 16/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